diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index fc51944cf..ec64007f1 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -858,7 +858,7 @@ impl MetricPattern for MetricPattern32 { fn get(&self // Reusable pattern structs /// Pattern struct for repeated tree structure. -pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { +pub struct AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { pub adjusted_sopr: MetricPattern6, pub adjusted_sopr_30d_ema: MetricPattern6, pub adjusted_sopr_7d_ema: MetricPattern6, @@ -866,6 +866,8 @@ pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSe pub adjusted_value_destroyed: MetricPattern1, pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, + pub ceiling_price: DollarsSatsPattern, + pub floor_price: DollarsSatsPattern, pub investor_cap_raw: MetricPattern11, pub investor_price: DollarsSatsPattern, pub investor_price_cents: MetricPattern1, @@ -914,7 +916,7 @@ pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSe pub value_destroyed: MetricPattern1, } -impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { +impl AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -925,6 +927,8 @@ impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSopr adjusted_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), + ceiling_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "ceiling_price")), + floor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "floor_price")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), investor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "investor_price")), investor_price_cents: MetricPattern1::new(client.clone(), _m(&acc, "investor_price_cents")), @@ -976,7 +980,7 @@ impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSopr } /// Pattern struct for repeated tree structure. -pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { +pub struct AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { pub adjusted_sopr: MetricPattern6, pub adjusted_sopr_30d_ema: MetricPattern6, pub adjusted_sopr_7d_ema: MetricPattern6, @@ -984,6 +988,8 @@ pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSe pub adjusted_value_destroyed: MetricPattern1, pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, + pub ceiling_price: DollarsSatsPattern, + pub floor_price: DollarsSatsPattern, pub investor_cap_raw: MetricPattern11, pub investor_price: DollarsSatsPattern, pub investor_price_cents: MetricPattern1, @@ -1030,7 +1036,7 @@ pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSe pub value_destroyed: MetricPattern1, } -impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { +impl AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -1041,6 +1047,8 @@ impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSopr adjusted_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), + ceiling_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "ceiling_price")), + floor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "floor_price")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), investor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "investor_price")), investor_price_cents: MetricPattern1::new(client.clone(), _m(&acc, "investor_price_cents")), @@ -1090,9 +1098,11 @@ impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSopr } /// Pattern struct for repeated tree structure. -pub struct CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { +pub struct CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, + pub ceiling_price: DollarsSatsPattern, + pub floor_price: DollarsSatsPattern, pub investor_cap_raw: MetricPattern11, pub investor_price: DollarsSatsPattern, pub investor_price_cents: MetricPattern1, @@ -1141,12 +1151,14 @@ pub struct CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTo pub value_destroyed: MetricPattern1, } -impl CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { +impl CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), + ceiling_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "ceiling_price")), + floor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "floor_price")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), investor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "investor_price")), investor_price_cents: MetricPattern1::new(client.clone(), _m(&acc, "investor_price_cents")), @@ -1198,9 +1210,11 @@ impl CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalVal } /// Pattern struct for repeated tree structure. -pub struct CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { +pub struct CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, + pub ceiling_price: DollarsSatsPattern, + pub floor_price: DollarsSatsPattern, pub investor_cap_raw: MetricPattern11, pub investor_price: DollarsSatsPattern, pub investor_price_cents: MetricPattern1, @@ -1247,12 +1261,14 @@ pub struct CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTo pub value_destroyed: MetricPattern1, } -impl CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { +impl CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), + ceiling_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "ceiling_price")), + floor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "floor_price")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), investor_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "investor_price")), investor_price_cents: MetricPattern1::new(client.clone(), _m(&acc, "investor_price_cents")), @@ -2032,7 +2048,7 @@ pub struct ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern { pub addr_count_30d_change: MetricPattern4, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, @@ -2047,7 +2063,7 @@ impl ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern { addr_count_30d_change: MetricPattern4::new(client.clone(), _m(&acc, "addr_count_30d_change")), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedNegNetNuplSupplyUnrealizedPattern::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), @@ -2176,7 +2192,7 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, pub outputs: UtxoPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, pub relative: InvestedNegNetSupplyUnrealizedPattern, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, @@ -2189,7 +2205,7 @@ impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern { activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), acc.clone()), cost_basis: InvestedMaxMinPercentilesSpotPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), acc.clone()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), acc.clone()), relative: InvestedNegNetSupplyUnrealizedPattern::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), @@ -2202,7 +2218,7 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, + pub realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern3, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, @@ -2215,7 +2231,7 @@ impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5 { activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), acc.clone()), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), acc.clone()), + realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), acc.clone()), relative: InvestedNegNetNuplSupplyUnrealizedPattern3::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), @@ -2228,7 +2244,7 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, @@ -2241,7 +2257,7 @@ impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 { activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), acc.clone()), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedNegNetNuplSupplyUnrealizedPattern::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), @@ -2254,7 +2270,7 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern3, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, @@ -2267,7 +2283,7 @@ impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 { activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), acc.clone()), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedNegNetNuplSupplyUnrealizedPattern3::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), @@ -2280,7 +2296,7 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedSupplyPattern, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, @@ -2293,7 +2309,7 @@ impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3 { activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), acc.clone()), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedSupplyPattern::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), @@ -2306,7 +2322,7 @@ pub struct ActivityCostOutputsRealizedSupplyUnrealizedPattern { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub supply: _30dHalvedTotalPattern, pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, } @@ -2318,7 +2334,7 @@ impl ActivityCostOutputsRealizedSupplyUnrealizedPattern { activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), acc.clone()), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), } @@ -5240,7 +5256,7 @@ pub struct MetricsTree_Distribution_UtxoCohorts_All { pub supply: _30dHalvedTotalPattern, pub outputs: UtxoPattern, pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, - pub realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, pub relative: MetricsTree_Distribution_UtxoCohorts_All_Relative, @@ -5252,7 +5268,7 @@ impl MetricsTree_Distribution_UtxoCohorts_All { supply: _30dHalvedTotalPattern::new(client.clone(), "".to_string()), outputs: UtxoPattern::new(client.clone(), "utxo_count".to_string()), activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), "".to_string()), - realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), "".to_string()), + realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), "".to_string()), unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), "".to_string()), cost_basis: InvestedMaxMinPercentilesSpotPattern::new(client.clone(), "".to_string()), relative: MetricsTree_Distribution_UtxoCohorts_All_Relative::new(client.clone(), format!("{base_path}_relative")), @@ -5565,7 +5581,7 @@ pub struct MetricsTree_Distribution_UtxoCohorts_Term_Short { pub supply: _30dHalvedTotalPattern, pub outputs: UtxoPattern, pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, - pub realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern4, @@ -5577,7 +5593,7 @@ impl MetricsTree_Distribution_UtxoCohorts_Term_Short { supply: _30dHalvedTotalPattern::new(client.clone(), "sth".to_string()), outputs: UtxoPattern::new(client.clone(), "sth_utxo_count".to_string()), activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), "sth".to_string()), - realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), "sth".to_string()), + realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), "sth".to_string()), unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), "sth".to_string()), cost_basis: InvestedMaxMinPercentilesSpotPattern::new(client.clone(), "sth".to_string()), relative: InvestedNegNetNuplSupplyUnrealizedPattern4::new(client.clone(), "sth".to_string()), @@ -5590,7 +5606,7 @@ pub struct MetricsTree_Distribution_UtxoCohorts_Term_Long { pub supply: _30dHalvedTotalPattern, pub outputs: UtxoPattern, pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, - pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, + pub realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern4, @@ -5602,7 +5618,7 @@ impl MetricsTree_Distribution_UtxoCohorts_Term_Long { supply: _30dHalvedTotalPattern::new(client.clone(), "lth".to_string()), outputs: UtxoPattern::new(client.clone(), "lth_utxo_count".to_string()), activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), "lth".to_string()), - realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), "lth".to_string()), + realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), "lth".to_string()), unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), "lth".to_string()), cost_basis: InvestedMaxMinPercentilesSpotPattern::new(client.clone(), "lth".to_string()), relative: InvestedNegNetNuplSupplyUnrealizedPattern4::new(client.clone(), "lth".to_string()), @@ -6051,7 +6067,7 @@ pub struct BrkClient { impl BrkClient { /// Client version. - pub const VERSION: &'static str = "v0.1.5"; + pub const VERSION: &'static str = "v0.1.6"; /// Create a new client with the given base URL. pub fn new(base_url: impl Into) -> Self { diff --git a/crates/brk_computer/src/distribution/metrics/realized.rs b/crates/brk_computer/src/distribution/metrics/realized.rs index 8b6ab3717..04c15d77b 100644 --- a/crates/brk_computer/src/distribution/metrics/realized.rs +++ b/crates/brk_computer/src/distribution/metrics/realized.rs @@ -17,7 +17,8 @@ use crate::{ internal::{ CentsUnsignedToDollars, ComputedFromDateLast, ComputedFromDateRatio, ComputedFromHeightLast, ComputedFromHeightSum, ComputedFromHeightSumCum, DollarsMinus, - DollarsPlus, LazyBinaryFromHeightSum, LazyBinaryFromHeightSumCum, + DollarsPlus, DollarsSquaredDivide, LazyBinaryFromHeightSum, LazyBinaryFromHeightSumCum, + LazyBinaryPriceFromHeight, LazyComputedValueFromHeightSumCum, LazyFromDateLast, LazyFromHeightLast, LazyFromHeightSum, LazyFromHeightSumCum, LazyPriceFromCents, PercentageDollarsF32, PriceFromHeight, StoredF32Identity, ValueFromDateLast, @@ -43,6 +44,10 @@ pub struct RealizedMetrics { pub investor_price: LazyPriceFromCents, pub investor_price_extra: ComputedFromDateRatio, + // === Floor/Ceiling Price Bands (lazy: realized²/investor, investor²/realized) === + pub floor_price: LazyBinaryPriceFromHeight, + pub ceiling_price: LazyBinaryPriceFromHeight, + // === Raw values for aggregation (needed to compute investor_price for aggregated cohorts) === /// Raw Σ(price × sats) for realized cap aggregation pub cap_raw: BytesVec, @@ -286,6 +291,26 @@ impl RealizedMetrics { extended, )?; + // Floor price = realized² / investor (lower band) + let floor_price = LazyBinaryPriceFromHeight::forced_import::( + cfg.db, + &cfg.name("floor_price"), + cfg.version, + realized_price.dollars.height.boxed_clone(), + investor_price.dollars.height.boxed_clone(), + cfg.indexes, + )?; + + // Ceiling price = investor² / realized (upper band) + let ceiling_price = LazyBinaryPriceFromHeight::forced_import::( + cfg.db, + &cfg.name("ceiling_price"), + cfg.version, + investor_price.dollars.height.boxed_clone(), + realized_price.dollars.height.boxed_clone(), + cfg.indexes, + )?; + // Raw values for aggregation let cap_raw = BytesVec::forced_import(cfg.db, &cfg.name("cap_raw"), cfg.version)?; let investor_cap_raw = @@ -429,6 +454,11 @@ impl RealizedMetrics { investor_price_cents, investor_price, investor_price_extra, + + // === Floor/Ceiling Price Bands === + floor_price, + ceiling_price, + cap_raw, investor_cap_raw, @@ -1148,6 +1178,10 @@ impl RealizedMetrics { )?; } + // Floor/ceiling price bands (derive stored dateindex from lazy height) + self.floor_price.dollars.derive_from(indexes, starting_indexes, exit)?; + self.ceiling_price.dollars.derive_from(indexes, starting_indexes, exit)?; + Ok(()) } } diff --git a/crates/brk_computer/src/distribution/state/cohort/base.rs b/crates/brk_computer/src/distribution/state/cohort/base.rs index 1e78908b3..dd6c2b511 100644 --- a/crates/brk_computer/src/distribution/state/cohort/base.rs +++ b/crates/brk_computer/src/distribution/state/cohort/base.rs @@ -3,9 +3,7 @@ use std::path::Path; use brk_error::Result; use brk_types::{Age, CentsSats, CentsUnsigned, CostBasisSnapshot, Height, Sats, SupplyState}; -use super::super::cost_basis::{ - CachedUnrealizedState, CostBasisData, Percentiles, RealizedState, UnrealizedState, -}; +use super::super::cost_basis::{CostBasisData, Percentiles, RealizedState, UnrealizedState}; #[derive(Clone)] pub struct CohortState { @@ -15,9 +13,6 @@ pub struct CohortState { pub satblocks_destroyed: Sats, pub satdays_destroyed: Sats, cost_basis_data: Option, - cached_unrealized: Option, - /// If set, prices are rounded to nearest dollar with N significant digits. - price_rounding_digits: Option, } impl CohortState { @@ -29,28 +24,18 @@ impl CohortState { satblocks_destroyed: Sats::ZERO, satdays_destroyed: Sats::ZERO, cost_basis_data: compute_dollars.then_some(CostBasisData::create(path, name)), - cached_unrealized: None, - price_rounding_digits: None, } } /// Enable price rounding for cost basis data. pub fn with_price_rounding(mut self, digits: i32) -> Self { - self.price_rounding_digits = Some(digits); + if let Some(data) = self.cost_basis_data.take() { + self.cost_basis_data = Some(data.with_price_rounding(digits)); + } self } - /// Round price if rounding is enabled. - #[inline] - fn round_price(&self, price: CentsUnsigned) -> CentsUnsigned { - match self.price_rounding_digits { - Some(digits) => price.round_to_dollar(digits), - None => price, - } - } - pub fn import_at_or_before(&mut self, height: Height) -> Result { - self.cached_unrealized = None; match self.cost_basis_data.as_mut() { Some(p) => p.import_at_or_before(height), None => Ok(height), @@ -73,7 +58,6 @@ impl CohortState { p.clean()?; p.init(); } - self.cached_unrealized = None; Ok(()) } @@ -111,21 +95,16 @@ impl CohortState { self.supply += &s.supply_state; if s.supply_state.value > Sats::ZERO && self.realized.is_some() { - let rounded_price = self.round_price(s.realized_price); self.realized .as_mut() .unwrap() .increment_snapshot(s.price_sats, s.investor_cap); self.cost_basis_data.as_mut().unwrap().increment( - rounded_price, + s.realized_price, s.supply_state.value, s.price_sats, s.investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_receive(rounded_price, s.supply_state.value); - } } } @@ -140,21 +119,16 @@ impl CohortState { self.supply -= &s.supply_state; if s.supply_state.value > Sats::ZERO && self.realized.is_some() { - let rounded_price = self.round_price(s.realized_price); self.realized .as_mut() .unwrap() .decrement_snapshot(s.price_sats, s.investor_cap); self.cost_basis_data.as_mut().unwrap().decrement( - rounded_price, + s.realized_price, s.supply_state.value, s.price_sats, s.investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_send(rounded_price, s.supply_state.value); - } } } @@ -179,10 +153,6 @@ impl CohortState { price_sats, investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_receive(price, sats); - } } } @@ -195,37 +165,27 @@ impl CohortState { ) { self.supply += supply; - if supply.value > Sats::ZERO && self.realized.is_some() { - // Pre-compute rounded prices before mutable borrows - let current_rounded = self.round_price(current.realized_price); - let prev_rounded = self.round_price(prev.realized_price); - - self.realized.as_mut().unwrap().receive(price, supply.value); + if supply.value > Sats::ZERO + && let Some(realized) = self.realized.as_mut() + { + realized.receive(price, supply.value); if current.supply_state.value.is_not_zero() { self.cost_basis_data.as_mut().unwrap().increment( - current_rounded, + current.realized_price, current.supply_state.value, current.price_sats, current.investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_receive(current_rounded, current.supply_state.value); - } } if prev.supply_state.value.is_not_zero() { self.cost_basis_data.as_mut().unwrap().decrement( - prev_rounded, + prev.realized_price, prev.supply_state.value, prev.price_sats, prev.investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_send(prev_rounded, prev.supply_state.value); - } } } } @@ -269,10 +229,6 @@ impl CohortState { prev_ps, prev_investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_send(pp, sats); - } } } } @@ -299,7 +255,7 @@ impl CohortState { self.satblocks_destroyed += age.satblocks_destroyed(supply.value); self.satdays_destroyed += age.satdays_destroyed(supply.value); - if self.realized.is_some() { + if let Some(realized) = self.realized.as_mut() { let sats = supply.value; // Compute once for realized.send using typed values @@ -308,39 +264,24 @@ impl CohortState { let ath_ps = CentsSats::from_price_sats(ath, sats); let prev_investor_cap = prev_ps.to_investor_cap(prev_price); - // Pre-compute rounded prices before mutable borrows - let current_rounded = self.round_price(current.realized_price); - let prev_rounded = self.round_price(prev.realized_price); - - self.realized - .as_mut() - .unwrap() - .send(sats, current_ps, prev_ps, ath_ps, prev_investor_cap); + realized.send(sats, current_ps, prev_ps, ath_ps, prev_investor_cap); if current.supply_state.value.is_not_zero() { self.cost_basis_data.as_mut().unwrap().increment( - current_rounded, + current.realized_price, current.supply_state.value, current.price_sats, current.investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_receive(current_rounded, current.supply_state.value); - } } if prev.supply_state.value.is_not_zero() { self.cost_basis_data.as_mut().unwrap().decrement( - prev_rounded, + prev.realized_price, prev.supply_state.value, prev.price_sats, prev.investor_cap, ); - - if let Some(cache) = self.cached_unrealized.as_mut() { - cache.on_send(prev_rounded, prev.supply_state.value); - } } } } @@ -355,25 +296,10 @@ impl CohortState { height_price: CentsUnsigned, date_price: Option, ) -> (UnrealizedState, Option) { - let cost_basis_data = match self.cost_basis_data.as_ref() { - Some(p) if !p.is_empty() => p, - _ => return (UnrealizedState::ZERO, date_price.map(|_| UnrealizedState::ZERO)), - }; - - let date_state = date_price.map(|date_price| { - CachedUnrealizedState::compute_full_standalone(date_price.into(), cost_basis_data) - }); - - let height_state = if let Some(cache) = self.cached_unrealized.as_mut() { - cache.get_at_price(height_price, cost_basis_data) - } else { - let cache = CachedUnrealizedState::compute_fresh(height_price, cost_basis_data); - let state = cache.current_state(); - self.cached_unrealized = Some(cache); - state - }; - - (height_state, date_state) + match self.cost_basis_data.as_mut() { + Some(p) => p.compute_unrealized_states(height_price, date_price), + None => (UnrealizedState::ZERO, date_price.map(|_| UnrealizedState::ZERO)), + } } pub fn write(&mut self, height: Height, cleanup: bool) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/state/cost_basis/data.rs b/crates/brk_computer/src/distribution/state/cost_basis/data.rs index 016ee3394..a082c6b10 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/data.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/data.rs @@ -1,7 +1,6 @@ use std::{ collections::BTreeMap, fs, - ops::Bound, path::{Path, PathBuf}, }; @@ -15,7 +14,10 @@ use vecdb::Bytes; use crate::utils::OptionExt; -use super::Percentiles; +use super::{CachedUnrealizedState, Percentiles, UnrealizedState}; + +/// Type alias for the price-to-sats map used in cost basis data. +pub(super) type CostBasisMap = BTreeMap; #[derive(Clone, Debug, Default)] struct PendingRaw { @@ -31,6 +33,8 @@ pub struct CostBasisData { state: Option, pending: FxHashMap, pending_raw: PendingRaw, + cache: Option, + rounding_digits: Option, } const STATE_TO_KEEP: usize = 10; @@ -42,6 +46,21 @@ impl CostBasisData { state: None, pending: FxHashMap::default(), pending_raw: PendingRaw::default(), + cache: None, + rounding_digits: None, + } + } + + pub fn with_price_rounding(mut self, digits: i32) -> Self { + self.rounding_digits = Some(digits); + self + } + + #[inline] + fn round_price(&self, price: CentsUnsigned) -> CentsUnsigned { + match self.rounding_digits { + Some(digits) => price.round_to_dollar(digits), + None => price, } } @@ -53,6 +72,7 @@ impl CostBasisData { self.state = Some(State::deserialize(&fs::read(path)?)?); self.pending.clear(); self.pending_raw = PendingRaw::default(); + self.cache = None; Ok(height) } @@ -75,14 +95,6 @@ impl CostBasisData { self.state.u().base.map.iter().map(|(&k, v)| (k, v)) } - pub fn range( - &self, - bounds: (Bound, Bound), - ) -> impl Iterator { - self.assert_pending_empty(); - self.state.u().base.map.range(bounds).map(|(&k, v)| (k, v)) - } - pub fn is_empty(&self) -> bool { self.pending.is_empty() && self.state.u().base.map.is_empty() } @@ -119,7 +131,8 @@ impl CostBasisData { self.state.u().investor_cap_raw } - /// Increment with pre-computed typed values + /// Increment with pre-computed typed values. + /// Handles rounding and cache update. pub fn increment( &mut self, price: CentsUnsigned, @@ -127,14 +140,19 @@ impl CostBasisData { price_sats: CentsSats, investor_cap: CentsSquaredSats, ) { + let price = self.round_price(price); self.pending.entry(price.into()).or_default().0 += sats; self.pending_raw.cap_inc += price_sats; if investor_cap != CentsSquaredSats::ZERO { self.pending_raw.investor_cap_inc += investor_cap; } + if let Some(cache) = self.cache.as_mut() { + cache.on_receive(price, sats); + } } - /// Decrement with pre-computed typed values + /// Decrement with pre-computed typed values. + /// Handles rounding and cache update. pub fn decrement( &mut self, price: CentsUnsigned, @@ -142,11 +160,15 @@ impl CostBasisData { price_sats: CentsSats, investor_cap: CentsSquaredSats, ) { + let price = self.round_price(price); self.pending.entry(price.into()).or_default().1 += sats; self.pending_raw.cap_dec += price_sats; if investor_cap != CentsSquaredSats::ZERO { self.pending_raw.investor_cap_dec += investor_cap; } + if let Some(cache) = self.cache.as_mut() { + cache.on_send(price, sats); + } } pub fn apply_pending(&mut self) { @@ -214,6 +236,7 @@ impl CostBasisData { self.state.replace(State::default()); self.pending.clear(); self.pending_raw = PendingRaw::default(); + self.cache = None; } pub fn compute_percentiles(&self) -> Option { @@ -221,9 +244,36 @@ impl CostBasisData { Percentiles::compute(self.iter().map(|(k, &v)| (k, v))) } + pub fn compute_unrealized_states( + &mut self, + height_price: CentsUnsigned, + date_price: Option, + ) -> (UnrealizedState, Option) { + if self.is_empty() { + return (UnrealizedState::ZERO, date_price.map(|_| UnrealizedState::ZERO)); + } + + let map = &self.state.u().base.map; + + let date_state = + date_price.map(|p| CachedUnrealizedState::compute_full_standalone(p.into(), map)); + + let height_state = if let Some(cache) = self.cache.as_mut() { + cache.get_at_price(height_price, map) + } else { + let cache = CachedUnrealizedState::compute_fresh(height_price, map); + let state = cache.current_state(); + self.cache = Some(cache); + state + }; + + (height_state, date_state) + } + pub fn clean(&mut self) -> Result<()> { let _ = fs::remove_dir_all(&self.pathbuf); fs::create_dir_all(self.path_by_height())?; + self.cache = None; Ok(()) } diff --git a/crates/brk_computer/src/distribution/state/cost_basis/mod.rs b/crates/brk_computer/src/distribution/state/cost_basis/mod.rs index 07905ee95..a1fdaa93d 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/mod.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/mod.rs @@ -6,4 +6,7 @@ mod unrealized; pub use data::*; pub use percentiles::*; pub use realized::*; -pub use unrealized::*; +pub use unrealized::UnrealizedState; + +// Internal use only +pub(super) use unrealized::CachedUnrealizedState; diff --git a/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs b/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs index d1e8831ba..76b557d00 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs @@ -2,7 +2,7 @@ use std::ops::Bound; use brk_types::{CentsUnsigned, CentsUnsignedCompact, Sats}; -use super::data::CostBasisData; +use super::CostBasisMap; #[derive(Debug, Default, Clone)] pub struct UnrealizedState { @@ -113,9 +113,9 @@ pub struct CachedUnrealizedState { } impl CachedUnrealizedState { - pub fn compute_fresh(price: CentsUnsigned, cost_basis_data: &CostBasisData) -> Self { + pub fn compute_fresh(price: CentsUnsigned, map: &CostBasisMap) -> Self { let price: CentsUnsignedCompact = price.into(); - let state = Self::compute_raw(price, cost_basis_data); + let state = Self::compute_raw(price, map); Self { state, at_price: price, @@ -130,11 +130,11 @@ impl CachedUnrealizedState { pub fn get_at_price( &mut self, new_price: CentsUnsigned, - cost_basis_data: &CostBasisData, + map: &CostBasisMap, ) -> UnrealizedState { let new_price: CentsUnsignedCompact = new_price.into(); if new_price != self.at_price { - self.update_for_price_change(new_price, cost_basis_data); + self.update_for_price_change(new_price, map); } self.state.to_output() } @@ -187,11 +187,7 @@ impl CachedUnrealizedState { } } - fn update_for_price_change( - &mut self, - new_price: CentsUnsignedCompact, - cost_basis_data: &CostBasisData, - ) { + fn update_for_price_change(&mut self, new_price: CentsUnsignedCompact, map: &CostBasisMap) { let old_price = self.at_price; if new_price > old_price { @@ -202,8 +198,7 @@ impl CachedUnrealizedState { // First, process UTXOs crossing from loss to profit // Range (old_price, new_price] means: old_price < price <= new_price - for (price, &sats) in - cost_basis_data.range((Bound::Excluded(old_price), Bound::Included(new_price))) + for (&price, &sats) in map.range((Bound::Excluded(old_price), Bound::Included(new_price))) { let sats_u128 = sats.as_u128(); let price_u128 = price.as_u128(); @@ -244,8 +239,7 @@ impl CachedUnrealizedState { // First, process UTXOs crossing from profit to loss // Range (new_price, old_price] means: new_price < price <= old_price - for (price, &sats) in - cost_basis_data.range((Bound::Excluded(new_price), Bound::Included(old_price))) + for (&price, &sats) in map.range((Bound::Excluded(new_price), Bound::Included(old_price))) { let sats_u128 = sats.as_u128(); let price_u128 = price.as_u128(); @@ -283,14 +277,11 @@ impl CachedUnrealizedState { self.at_price = new_price; } - /// Compute raw cached state from cost_basis_data. - fn compute_raw( - current_price: CentsUnsignedCompact, - cost_basis_data: &CostBasisData, - ) -> CachedStateRaw { + /// Compute raw cached state from the map. + fn compute_raw(current_price: CentsUnsignedCompact, map: &CostBasisMap) -> CachedStateRaw { let mut state = CachedStateRaw::default(); - for (price, &sats) in cost_basis_data.iter() { + for (&price, &sats) in map.iter() { let sats_u128 = sats.as_u128(); let price_u128 = price.as_u128(); let invested_capital = price_u128 * sats_u128; @@ -320,8 +311,8 @@ impl CachedUnrealizedState { /// Used for date_state which doesn't use the cache. pub fn compute_full_standalone( current_price: CentsUnsignedCompact, - cost_basis_data: &CostBasisData, + map: &CostBasisMap, ) -> UnrealizedState { - Self::compute_raw(current_price, cost_basis_data).to_output() + Self::compute_raw(current_price, map).to_output() } } diff --git a/crates/brk_computer/src/internal/multi/from_height/lazy_binary_price.rs b/crates/brk_computer/src/internal/multi/from_height/lazy_binary_price.rs new file mode 100644 index 000000000..c782e26d5 --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_height/lazy_binary_price.rs @@ -0,0 +1,63 @@ +//! Lazy binary price wrapper with both USD and sats representations. +//! +//! Height-level value is lazy binary: transform(source1[h], source2[h]). +//! Sats are derived lazily from the dollars output. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Dollars, Height, SatsFract, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, Database, IterableBoxedVec, IterableCloneableVec}; + +use super::LazyBinaryComputedFromHeightLast; +use crate::{ + indexes, + internal::{ComputedVecValue, DollarsToSatsFract, LazyFromHeightLast, NumericValue}, +}; + +/// Lazy binary price metric with both USD and sats representations. +/// +/// Dollars: lazy binary transform at height, stored at dateindex. +/// Sats: lazy unary transform of dollars (fully lazy). +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyBinaryPriceFromHeight +where + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dollars: LazyBinaryComputedFromHeightLast, + pub sats: LazyFromHeightLast, +} + +impl LazyBinaryPriceFromHeight +where + S1T: NumericValue + JsonSchema, + S2T: NumericValue + JsonSchema, +{ + pub fn forced_import>( + db: &Database, + name: &str, + version: Version, + source1: IterableBoxedVec, + source2: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Result { + let dollars = LazyBinaryComputedFromHeightLast::forced_import::( + db, name, version, source1, source2, indexes, + )?; + + let sats = LazyFromHeightLast::from_lazy_binary_computed::( + &format!("{name}_sats"), + version, + dollars.height.boxed_clone(), + &dollars, + ); + + Ok(Self { dollars, sats }) + } +} diff --git a/crates/brk_computer/src/internal/multi/from_height/mod.rs b/crates/brk_computer/src/internal/multi/from_height/mod.rs index c3bd18d5f..a568cbe50 100644 --- a/crates/brk_computer/src/internal/multi/from_height/mod.rs +++ b/crates/brk_computer/src/internal/multi/from_height/mod.rs @@ -11,6 +11,7 @@ mod lazy_transform_distribution; mod lazy_binary_computed_distribution; mod lazy_binary_computed_full; mod lazy_binary_computed_last; +mod lazy_binary_price; mod lazy_binary_computed_sum; mod lazy_binary_computed_sum_cum; mod lazy_computed_full; @@ -47,6 +48,7 @@ pub use lazy_transform_distribution::*; pub use lazy_binary_computed_distribution::*; pub use lazy_binary_computed_full::*; pub use lazy_binary_computed_last::*; +pub use lazy_binary_price::*; pub use lazy_binary_computed_sum::*; pub use lazy_binary_computed_sum_cum::*; pub use lazy_computed_full::*; diff --git a/crates/brk_computer/src/internal/single/transform/dollars_squared_divide.rs b/crates/brk_computer/src/internal/single/transform/dollars_squared_divide.rs new file mode 100644 index 000000000..8cb80373c --- /dev/null +++ b/crates/brk_computer/src/internal/single/transform/dollars_squared_divide.rs @@ -0,0 +1,18 @@ +use brk_types::Dollars; +use vecdb::BinaryTransform; + +/// (Dollars, Dollars) -> Dollars: a² / b +pub struct DollarsSquaredDivide; + +impl BinaryTransform for DollarsSquaredDivide { + #[inline(always)] + fn apply(a: Dollars, b: Dollars) -> Dollars { + let af = f64::from(a); + let bf = f64::from(b); + if bf == 0.0 { + Dollars::NAN + } else { + Dollars::from(af * af / bf) + } + } +} diff --git a/crates/brk_computer/src/internal/single/transform/mod.rs b/crates/brk_computer/src/internal/single/transform/mod.rs index f22352029..4c5b8acef 100644 --- a/crates/brk_computer/src/internal/single/transform/mod.rs +++ b/crates/brk_computer/src/internal/single/transform/mod.rs @@ -3,6 +3,7 @@ mod cents_unsigned_to_sats_fract; mod close_price_times_sats; mod difference_f32; mod dollar_halve; +mod dollars_squared_divide; mod dollar_identity; mod dollar_minus; mod dollar_plus; @@ -45,6 +46,7 @@ pub use cents_unsigned_to_sats_fract::*; pub use close_price_times_sats::*; pub use difference_f32::*; pub use dollar_halve::*; +pub use dollars_squared_divide::*; pub use dollar_identity::*; pub use dollar_minus::*; pub use dollar_plus::*; diff --git a/crates/brk_website/src/handlers.rs b/crates/brk_website/src/handlers.rs index cdadf9daf..e3dd6262f 100644 --- a/crates/brk_website/src/handlers.rs +++ b/crates/brk_website/src/handlers.rs @@ -1,34 +1,60 @@ use std::path::Path; -use axum::{body::Body, extract::State, http::Response}; +use axum::{ + body::Body, + extract::State, + http::{HeaderMap, Response, StatusCode}, +}; use crate::{HeaderMapExtended, Result, Website}; pub async fn file_handler( State(website): State, + headers: HeaderMap, path: axum::extract::Path, ) -> Result> { - serve(&website, &path.0) + serve(&website, &path.0, &headers) } -pub async fn index_handler(State(website): State) -> Result> { - serve(&website, "") +pub async fn index_handler( + State(website): State, + headers: HeaderMap, +) -> Result> { + serve(&website, "", &headers) } -fn serve(website: &Website, path: &str) -> Result> { +fn serve(website: &Website, path: &str, request_headers: &HeaderMap) -> Result> { let path = sanitize(path); - let content = website.get_file(&path)?; - let mut response = Response::new(Body::from(content)); - let headers = response.headers_mut(); - - // Empty path or no extension = index.html (SPA fallback) let is_html = path.is_empty() || Path::new(&path).extension().is_none() || path.ends_with(".html"); + // Etag 304 check (release mode, HTML only) + if is_html { + if let Some(etag) = website.index_etag() { + if request_headers.has_etag(etag) { + let mut response = Response::builder() + .status(StatusCode::NOT_MODIFIED) + .body(Body::empty()) + .unwrap(); + let headers = response.headers_mut(); + headers.insert_etag(etag); + headers.insert_cache_control_must_revalidate(); + return Ok(response); + } + } + } + + let content = website.get_file(&path)?; + let mut response = Response::new(Body::from(content)); + let headers = response.headers_mut(); + if is_html { headers.insert_content_type_text_html(); + if let Some(etag) = website.index_etag() { + headers.insert_etag(etag); + } } else { headers.insert_content_type(Path::new(&path)); } diff --git a/crates/brk_website/src/headers.rs b/crates/brk_website/src/headers.rs index 91ca99653..219c65325 100644 --- a/crates/brk_website/src/headers.rs +++ b/crates/brk_website/src/headers.rs @@ -3,6 +3,8 @@ use std::path::Path; use axum::http::{HeaderMap, header}; pub trait HeaderMapExtended { + fn has_etag(&self, etag: &str) -> bool; + fn insert_etag(&mut self, etag: &str); fn insert_cache_control_must_revalidate(&mut self); fn insert_cache_control_immutable(&mut self); fn insert_content_type(&mut self, path: &Path); @@ -10,6 +12,15 @@ pub trait HeaderMapExtended { } impl HeaderMapExtended for HeaderMap { + fn has_etag(&self, etag: &str) -> bool { + self.get(header::IF_NONE_MATCH) + .is_some_and(|v| v == etag) + } + + fn insert_etag(&mut self, etag: &str) { + self.insert(header::ETAG, etag.parse().unwrap()); + } + fn insert_cache_control_must_revalidate(&mut self) { self.insert( header::CACHE_CONTROL, diff --git a/crates/brk_website/src/website.rs b/crates/brk_website/src/website.rs index 2a3f14f6a..21c0893b2 100644 --- a/crates/brk_website/src/website.rs +++ b/crates/brk_website/src/website.rs @@ -1,5 +1,6 @@ use std::{ fs, + hash::{DefaultHasher, Hash, Hasher}, path::{Path, PathBuf}, str::FromStr, sync::OnceLock, @@ -15,8 +16,13 @@ use crate::{Error, Result}; /// Embedded website assets pub static EMBEDDED_WEBSITE: Dir = include_dir!("$CARGO_MANIFEST_DIR/website"); +struct CachedIndex { + html: Vec, + etag: String, +} + /// Cached index.html with importmap injected -static INDEX_HTML: OnceLock = OnceLock::new(); +static INDEX_HTML: OnceLock = OnceLock::new(); /// Website configuration: /// - `true` or omitted: serve embedded website @@ -35,6 +41,14 @@ impl Website { !matches!(self, Self::Disabled) } + /// Returns the cached index.html etag (None in debug mode or before first request) + pub fn index_etag(&self) -> Option<&str> { + if cfg!(debug_assertions) { + return None; + } + INDEX_HTML.get().map(|cached| cached.etag.as_str()) + } + /// Returns the filesystem path if available, None means use embedded pub fn filesystem_path(&self) -> Option { match self { @@ -96,35 +110,46 @@ impl Website { } // Release mode: cache with importmap - let html = INDEX_HTML.get_or_init(|| match self.filesystem_path() { - None => { - let file = EMBEDDED_WEBSITE - .get_file("index.html") - .expect("index.html must exist in embedded website"); + let cached = INDEX_HTML.get_or_init(|| { + let html = match self.filesystem_path() { + None => { + let file = EMBEDDED_WEBSITE + .get_file("index.html") + .expect("index.html must exist in embedded website"); - let html = - std::str::from_utf8(file.contents()).expect("index.html must be valid UTF-8"); + let html = + std::str::from_utf8(file.contents()).expect("index.html must be valid UTF-8"); - let importmap = ImportMap::scan_embedded(&EMBEDDED_WEBSITE, ""); - importmap - .transform_html(html) - .unwrap_or_else(|| html.to_string()) - } - Some(base) => { - let html = - fs::read_to_string(base.join("index.html")).expect("index.html must exist"); + let importmap = ImportMap::scan_embedded(&EMBEDDED_WEBSITE, ""); + importmap + .transform_html(html) + .unwrap_or_else(|| html.to_string()) + } + Some(base) => { + let html = + fs::read_to_string(base.join("index.html")).expect("index.html must exist"); - match ImportMap::scan(&base, "") { - Ok(importmap) => importmap.transform_html(&html).unwrap_or(html), - Err(e) => { - error!("Failed to scan for importmap: {e}"); - html + match ImportMap::scan(&base, "") { + Ok(importmap) => importmap.transform_html(&html).unwrap_or(html), + Err(e) => { + error!("Failed to scan for importmap: {e}"); + html + } } } + }; + + let mut hasher = DefaultHasher::new(); + html.hash(&mut hasher); + let etag = format!("\"{}\"", hasher.finish()); + + CachedIndex { + html: html.into_bytes(), + etag, } }); - Ok(html.as_bytes().to_vec()) + Ok(cached.html.clone()) } fn get_embedded(&self, path: &str) -> Result> { diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 48a0af67e..2056f41b0 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1438,7 +1438,7 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } // Reusable structural pattern factories /** - * @typedef {Object} AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern + * @typedef {Object} AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern * @property {MetricPattern6} adjustedSopr * @property {MetricPattern6} adjustedSopr30dEma * @property {MetricPattern6} adjustedSopr7dEma @@ -1446,6 +1446,8 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } * @property {MetricPattern1} adjustedValueDestroyed * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow + * @property {DollarsSatsPattern} ceilingPrice + * @property {DollarsSatsPattern} floorPrice * @property {MetricPattern11} investorCapRaw * @property {DollarsSatsPattern} investorPrice * @property {MetricPattern1} investorPriceCents @@ -1495,12 +1497,12 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } */ /** - * Create a AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern pattern node + * Create a AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} + * @returns {AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} */ -function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) { +function createAdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) { return { adjustedSopr: createMetricPattern6(client, _m(acc, 'adjusted_sopr')), adjustedSopr30dEma: createMetricPattern6(client, _m(acc, 'adjusted_sopr_30d_ema')), @@ -1509,6 +1511,8 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe adjustedValueDestroyed: createMetricPattern1(client, _m(acc, 'adjusted_value_destroyed')), capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), + ceilingPrice: createDollarsSatsPattern(client, _m(acc, 'ceiling_price')), + floorPrice: createDollarsSatsPattern(client, _m(acc, 'floor_price')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), investorPrice: createDollarsSatsPattern(client, _m(acc, 'investor_price')), investorPriceCents: createMetricPattern1(client, _m(acc, 'investor_price_cents')), @@ -1559,7 +1563,7 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe } /** - * @typedef {Object} AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 + * @typedef {Object} AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 * @property {MetricPattern6} adjustedSopr * @property {MetricPattern6} adjustedSopr30dEma * @property {MetricPattern6} adjustedSopr7dEma @@ -1567,6 +1571,8 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe * @property {MetricPattern1} adjustedValueDestroyed * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow + * @property {DollarsSatsPattern} ceilingPrice + * @property {DollarsSatsPattern} floorPrice * @property {MetricPattern11} investorCapRaw * @property {DollarsSatsPattern} investorPrice * @property {MetricPattern1} investorPriceCents @@ -1614,12 +1620,12 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe */ /** - * Create a AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 pattern node + * Create a AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} + * @returns {AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} */ -function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) { +function createAdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) { return { adjustedSopr: createMetricPattern6(client, _m(acc, 'adjusted_sopr')), adjustedSopr30dEma: createMetricPattern6(client, _m(acc, 'adjusted_sopr_30d_ema')), @@ -1628,6 +1634,8 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe adjustedValueDestroyed: createMetricPattern1(client, _m(acc, 'adjusted_value_destroyed')), capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), + ceilingPrice: createDollarsSatsPattern(client, _m(acc, 'ceiling_price')), + floorPrice: createDollarsSatsPattern(client, _m(acc, 'floor_price')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), investorPrice: createDollarsSatsPattern(client, _m(acc, 'investor_price')), investorPriceCents: createMetricPattern1(client, _m(acc, 'investor_price_cents')), @@ -1676,9 +1684,11 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe } /** - * @typedef {Object} CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 + * @typedef {Object} CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow + * @property {DollarsSatsPattern} ceilingPrice + * @property {DollarsSatsPattern} floorPrice * @property {MetricPattern11} investorCapRaw * @property {DollarsSatsPattern} investorPrice * @property {MetricPattern1} investorPriceCents @@ -1728,15 +1738,17 @@ function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSe */ /** - * Create a CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 pattern node + * Create a CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} + * @returns {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} */ -function createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) { +function createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) { return { capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), + ceilingPrice: createDollarsSatsPattern(client, _m(acc, 'ceiling_price')), + floorPrice: createDollarsSatsPattern(client, _m(acc, 'floor_price')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), investorPrice: createDollarsSatsPattern(client, _m(acc, 'investor_price')), investorPriceCents: createMetricPattern1(client, _m(acc, 'investor_price_cents')), @@ -1787,9 +1799,11 @@ function createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSo } /** - * @typedef {Object} CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern + * @typedef {Object} CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow + * @property {DollarsSatsPattern} ceilingPrice + * @property {DollarsSatsPattern} floorPrice * @property {MetricPattern11} investorCapRaw * @property {DollarsSatsPattern} investorPrice * @property {MetricPattern1} investorPriceCents @@ -1837,15 +1851,17 @@ function createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSo */ /** - * Create a CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern pattern node + * Create a CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} + * @returns {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} */ -function createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) { +function createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) { return { capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), + ceilingPrice: createDollarsSatsPattern(client, _m(acc, 'ceiling_price')), + floorPrice: createDollarsSatsPattern(client, _m(acc, 'floor_price')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), investorPrice: createDollarsSatsPattern(client, _m(acc, 'investor_price')), investorPriceCents: createMetricPattern1(client, _m(acc, 'investor_price_cents')), @@ -2683,7 +2699,7 @@ function createAverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern2(clie * @property {MetricPattern4} addrCount30dChange * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedNegNetNuplSupplyUnrealizedPattern} relative * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized @@ -2702,7 +2718,7 @@ function createActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern(cl addrCount30dChange: createMetricPattern4(client, _m(acc, 'addr_count_30d_change')), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedNegNetNuplSupplyUnrealizedPattern(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), @@ -2846,7 +2862,7 @@ function create_10y2y3y4y5y6y8yPattern(client, acc) { * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {InvestedMaxMinPercentilesSpotPattern} costBasis * @property {UtxoPattern} outputs - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized * @property {InvestedNegNetSupplyUnrealizedPattern} relative * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized @@ -2863,7 +2879,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern(client activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createInvestedMaxMinPercentilesSpotPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc), relative: createInvestedNegNetSupplyUnrealizedPattern(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc), @@ -2875,7 +2891,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern(client * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized + * @property {AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized * @property {InvestedNegNetNuplSupplyUnrealizedPattern3} relative * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized @@ -2892,7 +2908,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc), + realized: createAdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc), relative: createInvestedNegNetNuplSupplyUnrealizedPattern3(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc), @@ -2904,7 +2920,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedNegNetNuplSupplyUnrealizedPattern} relative * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized @@ -2921,7 +2937,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedNegNetNuplSupplyUnrealizedPattern(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), @@ -2933,7 +2949,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedNegNetNuplSupplyUnrealizedPattern3} relative * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized @@ -2950,7 +2966,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedNegNetNuplSupplyUnrealizedPattern3(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc), @@ -2962,7 +2978,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedSupplyPattern} relative * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized @@ -2979,7 +2995,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedSupplyPattern(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), @@ -2991,7 +3007,7 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {_30dHalvedTotalPattern} supply * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized */ @@ -3007,7 +3023,7 @@ function createActivityCostOutputsRealizedSupplyUnrealizedPattern(client, acc) { activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), supply: create_30dHalvedTotalPattern(client, acc), unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), }; @@ -4611,7 +4627,7 @@ function createRatioPattern2(client, acc) { * @property {_30dHalvedTotalPattern} supply * @property {UtxoPattern} outputs * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity - * @property {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized * @property {InvestedMaxMinPercentilesSpotPattern} costBasis * @property {MetricsTree_Distribution_UtxoCohorts_All_Relative} relative @@ -4760,7 +4776,7 @@ function createRatioPattern2(client, acc) { * @property {_30dHalvedTotalPattern} supply * @property {UtxoPattern} outputs * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity - * @property {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized * @property {InvestedMaxMinPercentilesSpotPattern} costBasis * @property {InvestedNegNetNuplSupplyUnrealizedPattern4} relative @@ -4771,7 +4787,7 @@ function createRatioPattern2(client, acc) { * @property {_30dHalvedTotalPattern} supply * @property {UtxoPattern} outputs * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity - * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized + * @property {CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized * @property {InvestedMaxMinPercentilesSpotPattern} costBasis * @property {InvestedNegNetNuplSupplyUnrealizedPattern4} relative @@ -4976,7 +4992,7 @@ function createRatioPattern2(client, acc) { * @extends BrkClientBase */ class BrkClient extends BrkClientBase { - VERSION = "v0.1.5"; + VERSION = "v0.1.6"; INDEXES = /** @type {const} */ ([ "dateindex", @@ -6736,7 +6752,7 @@ class BrkClient extends BrkClientBase { supply: create_30dHalvedTotalPattern(this, ''), outputs: createUtxoPattern(this, 'utxo_count'), activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(this, ''), - realized: createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(this, ''), + realized: createAdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(this, ''), unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(this, ''), costBasis: createInvestedMaxMinPercentilesSpotPattern(this, ''), relative: { @@ -6863,7 +6879,7 @@ class BrkClient extends BrkClientBase { supply: create_30dHalvedTotalPattern(this, 'sth'), outputs: createUtxoPattern(this, 'sth_utxo_count'), activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(this, 'sth'), - realized: createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(this, 'sth'), + realized: createAdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(this, 'sth'), unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(this, 'sth'), costBasis: createInvestedMaxMinPercentilesSpotPattern(this, 'sth'), relative: createInvestedNegNetNuplSupplyUnrealizedPattern4(this, 'sth'), @@ -6872,7 +6888,7 @@ class BrkClient extends BrkClientBase { supply: create_30dHalvedTotalPattern(this, 'lth'), outputs: createUtxoPattern(this, 'lth_utxo_count'), activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(this, 'lth'), - realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(this, 'lth'), + realized: createCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(this, 'lth'), unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(this, 'lth'), costBasis: createInvestedMaxMinPercentilesSpotPattern(this, 'lth'), relative: createInvestedNegNetNuplSupplyUnrealizedPattern4(this, 'lth'), diff --git a/modules/brk-client/package.json b/modules/brk-client/package.json index 6ceddf1ce..5bdef631d 100644 --- a/modules/brk-client/package.json +++ b/modules/brk-client/package.json @@ -34,5 +34,5 @@ "url": "git+https://github.com/bitcoinresearchkit/brk.git" }, "type": "module", - "version": "0.1.5" + "version": "0.1.6" } diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 8ba57aa01..a5664f6d4 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -1862,7 +1862,7 @@ class MetricPattern32(Generic[T]): # Reusable structural pattern classes -class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern: +class AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -1874,6 +1874,8 @@ class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSop self.adjusted_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed')) self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) + self.ceiling_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'ceiling_price')) + self.floor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'floor_price')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) self.investor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'investor_price')) self.investor_price_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'investor_price_cents')) @@ -1921,7 +1923,7 @@ class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSop self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) -class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2: +class AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -1933,6 +1935,8 @@ class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSop self.adjusted_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed')) self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) + self.ceiling_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'ceiling_price')) + self.floor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'floor_price')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) self.investor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'investor_price')) self.investor_price_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'investor_price_cents')) @@ -1978,13 +1982,15 @@ class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSop self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) -class CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2: +class CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) + self.ceiling_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'ceiling_price')) + self.floor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'floor_price')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) self.investor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'investor_price')) self.investor_price_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'investor_price_cents')) @@ -2032,13 +2038,15 @@ class CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalVa self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) -class CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern: +class CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) + self.ceiling_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'ceiling_price')) + self.floor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'floor_price')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) self.investor_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'investor_price')) self.investor_price_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'investor_price_cents')) @@ -2456,7 +2464,7 @@ class ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern: self.addr_count_30d_change: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'addr_count_30d_change')) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedNegNetNuplSupplyUnrealizedPattern = InvestedNegNetNuplSupplyUnrealizedPattern(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) @@ -2527,7 +2535,7 @@ class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern: self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) self.cost_basis: InvestedMaxMinPercentilesSpotPattern = InvestedMaxMinPercentilesSpotPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) self.relative: InvestedNegNetSupplyUnrealizedPattern = InvestedNegNetSupplyUnrealizedPattern(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) @@ -2540,7 +2548,7 @@ class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5: self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) + self.realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) self.relative: InvestedNegNetNuplSupplyUnrealizedPattern3 = InvestedNegNetNuplSupplyUnrealizedPattern3(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) @@ -2553,7 +2561,7 @@ class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4: self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedNegNetNuplSupplyUnrealizedPattern = InvestedNegNetNuplSupplyUnrealizedPattern(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) @@ -2566,7 +2574,7 @@ class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6: self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedNegNetNuplSupplyUnrealizedPattern3 = InvestedNegNetNuplSupplyUnrealizedPattern3(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) @@ -2579,7 +2587,7 @@ class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3: self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedSupplyPattern = InvestedSupplyPattern(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) @@ -2592,7 +2600,7 @@ class ActivityCostOutputsRealizedSupplyUnrealizedPattern: self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) @@ -3979,7 +3987,7 @@ class MetricsTree_Distribution_UtxoCohorts_All: self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, '') self.outputs: UtxoPattern = UtxoPattern(client, 'utxo_count') self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, '') - self.realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, '') + self.realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, '') self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, '') self.cost_basis: InvestedMaxMinPercentilesSpotPattern = InvestedMaxMinPercentilesSpotPattern(client, '') self.relative: MetricsTree_Distribution_UtxoCohorts_All_Relative = MetricsTree_Distribution_UtxoCohorts_All_Relative(client) @@ -4111,7 +4119,7 @@ class MetricsTree_Distribution_UtxoCohorts_Term_Short: self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, 'sth') self.outputs: UtxoPattern = UtxoPattern(client, 'sth_utxo_count') self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, 'sth') - self.realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, 'sth') + self.realized: AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, 'sth') self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, 'sth') self.cost_basis: InvestedMaxMinPercentilesSpotPattern = InvestedMaxMinPercentilesSpotPattern(client, 'sth') self.relative: InvestedNegNetNuplSupplyUnrealizedPattern4 = InvestedNegNetNuplSupplyUnrealizedPattern4(client, 'sth') @@ -4123,7 +4131,7 @@ class MetricsTree_Distribution_UtxoCohorts_Term_Long: self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, 'lth') self.outputs: UtxoPattern = UtxoPattern(client, 'lth_utxo_count') self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, 'lth') - self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, 'lth') + self.realized: CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, 'lth') self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, 'lth') self.cost_basis: InvestedMaxMinPercentilesSpotPattern = InvestedMaxMinPercentilesSpotPattern(client, 'lth') self.relative: InvestedNegNetNuplSupplyUnrealizedPattern4 = InvestedNegNetNuplSupplyUnrealizedPattern4(client, 'lth') @@ -4401,7 +4409,7 @@ class MetricsTree: class BrkClient(BrkClientBase): """Main BRK client with metrics tree and API methods.""" - VERSION = "v0.1.5" + VERSION = "v0.1.6" INDEXES = [ "dateindex", diff --git a/packages/brk_client/pyproject.toml b/packages/brk_client/pyproject.toml index 6a47d0ba4..3d8e9626b 100644 --- a/packages/brk_client/pyproject.toml +++ b/packages/brk_client/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "brk-client" -version = "0.1.5" +version = "0.1.6" description = "Python client for the Bitcoin Research Kit" readme = "README.md" requires-python = ">=3.9" diff --git a/website/scripts/options/distribution/prices.js b/website/scripts/options/distribution/prices.js index 39bdcf568..1b79efe1c 100644 --- a/website/scripts/options/distribution/prices.js +++ b/website/scripts/options/distribution/prices.js @@ -19,7 +19,7 @@ import { baseline, price } from "../series.js"; import { Unit } from "../../utils/units.js"; /** - * @param {{ realized: { realizedPrice: ActivePricePattern, investorPrice: ActivePricePattern } }} tree + * @param {{ realized: { realizedPrice: ActivePricePattern, investorPrice: ActivePricePattern, floorPrice: ActivePricePattern, ceilingPrice: ActivePricePattern } }} tree * @param {(metric: string) => string} title * @returns {PartialChartOption} */ @@ -30,6 +30,8 @@ function createCompareChart(tree, title) { top: [ price({ metric: tree.realized.realizedPrice, name: "Realized", color: colors.realized }), price({ metric: tree.realized.investorPrice, name: "Investor", color: colors.investor }), + price({ metric: tree.realized.ceilingPrice, name: "I²/R", color: colors.stat.max, style: 2, defaultActive: false }), + price({ metric: tree.realized.floorPrice, name: "R²/I", color: colors.stat.min, style: 2, defaultActive: false }), ], }; } diff --git a/website/scripts/types.js b/website/scripts/types.js index d69962297..744ee4941 100644 --- a/website/scripts/types.js +++ b/website/scripts/types.js @@ -89,10 +89,10 @@ * @typedef {Brk.GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} UnrealizedFullPattern * * Realized patterns - * @typedef {Brk.CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} RealizedPattern - * @typedef {Brk.CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} RealizedPattern2 - * @typedef {Brk.AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} RealizedPattern3 - * @typedef {Brk.AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} RealizedPattern4 + * @typedef {Brk.CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} RealizedPattern + * @typedef {Brk.CapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} RealizedPattern2 + * @typedef {Brk.AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} RealizedPattern3 + * @typedef {Brk.AdjustedCapCapitulationCeilingFloorInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} RealizedPattern4 */ /**