diff --git a/Cargo.lock b/Cargo.lock index 55c9b4d42..ca8e12361 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2436,8 +2436,6 @@ dependencies = [ [[package]] name = "rawdb" version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32158f67cfcd5359af3294b26cc4acbd8e412106ab1d6e470038b5284df362e7" dependencies = [ "libc", "log", @@ -3256,8 +3254,6 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" [[package]] name = "vecdb" version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c9f596e212ac69076b58735d340dd944f83531b5a83061020d4a922b73016d" dependencies = [ "ctrlc", "log", @@ -3277,8 +3273,6 @@ dependencies = [ [[package]] name = "vecdb_derive" version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c4ecf88e970a6275bad540fc68e022ed86987d817ef6711a7c57889aa2dfdf" dependencies = [ "quote", "syn", diff --git a/Cargo.toml b/Cargo.toml index 18299430f..e69431e9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,8 +83,8 @@ tokio = { version = "1.49.0", features = ["rt-multi-thread"] } tracing = { version = "0.1", default-features = false, features = ["std"] } tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] } tower-layer = "0.3" -vecdb = { version = "0.6.4", features = ["derive", "serde_json", "pco", "schemars"] } -# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } +# vecdb = { version = "0.6.4", features = ["derive", "serde_json", "pco", "schemars"] } +vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } [workspace.metadata.release] shared-version = true diff --git a/crates/brk_bindgen/src/analysis/patterns.rs b/crates/brk_bindgen/src/analysis/patterns.rs index 5afadff55..8d99cbfb0 100644 --- a/crates/brk_bindgen/src/analysis/patterns.rs +++ b/crates/brk_bindgen/src/analysis/patterns.rs @@ -87,6 +87,13 @@ pub fn detect_structural_patterns( }) .collect(); + // Deduplicate patterns by name - different signatures can map to the same name + // when their normalized forms match but they can't be unified as generics + { + let mut seen_names: BTreeSet = BTreeSet::new(); + patterns.retain(|p| seen_names.insert(p.name.clone())); + } + patterns.extend(generic_patterns); // Build pattern lookup for mode analysis (patterns appearing 2+ times) diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 217eaf9e1..85ec56903 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -858,13 +858,12 @@ impl MetricPattern for MetricPattern32 { fn get(&self // Reusable pattern structs /// Pattern struct for repeated tree structure. -pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern { +pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { pub adjusted_sopr: MetricPattern6, pub adjusted_sopr_30d_ema: MetricPattern6, pub adjusted_sopr_7d_ema: MetricPattern6, pub adjusted_value_created: MetricPattern1, pub adjusted_value_destroyed: MetricPattern1, - pub ath_regret: CumulativeSumPattern, pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, pub investor_cap_raw: MetricPattern11, @@ -876,10 +875,13 @@ pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSop pub mvrv: MetricPattern4, pub neg_realized_loss: CumulativeSumPattern2, pub net_realized_pnl: CumulativeSumPattern, + pub net_realized_pnl_7d_ema: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, pub net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern, + pub peak_regret: CumulativeSumPattern, + pub peak_regret_rel_to_realized_cap: MetricPattern1, pub profit_flow: MetricPattern1, pub profit_value_created: MetricPattern1, pub profit_value_destroyed: MetricPattern1, @@ -888,16 +890,22 @@ pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSop pub realized_cap_cents: MetricPattern1, pub realized_cap_rel_to_own_market_cap: MetricPattern1, pub realized_loss: CumulativeSumPattern, + pub realized_loss_7d_ema: MetricPattern4, pub realized_loss_rel_to_realized_cap: CumulativeSumPattern, pub realized_price: DollarsSatsPattern, pub realized_price_extra: RatioPattern, pub realized_profit: CumulativeSumPattern, + pub realized_profit_7d_ema: MetricPattern4, pub realized_profit_rel_to_realized_cap: CumulativeSumPattern, pub realized_profit_to_loss_ratio: MetricPattern6, pub realized_value: MetricPattern1, pub sell_side_risk_ratio: MetricPattern6, pub sell_side_risk_ratio_30d_ema: MetricPattern6, pub sell_side_risk_ratio_7d_ema: MetricPattern6, + pub sent_in_loss: BitcoinDollarsSatsPattern3, + pub sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5, + pub sent_in_profit: BitcoinDollarsSatsPattern3, + pub sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5, pub sopr: MetricPattern6, pub sopr_30d_ema: MetricPattern6, pub sopr_7d_ema: MetricPattern6, @@ -906,7 +914,7 @@ pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSop pub value_destroyed: MetricPattern1, } -impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern { +impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -915,7 +923,6 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal adjusted_sopr_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "adjusted_sopr_7d_ema")), adjusted_value_created: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_created")), adjusted_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), - ath_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_ath_regret")), cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), @@ -927,10 +934,13 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: CumulativeSumPattern2::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), + net_realized_pnl_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_7d_ema")), net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + peak_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_peak_regret")), + peak_regret_rel_to_realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "peak_regret_rel_to_realized_cap")), profit_flow: MetricPattern1::new(client.clone(), _m(&acc, "profit_flow")), profit_value_created: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_created")), profit_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_destroyed")), @@ -939,16 +949,22 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal realized_cap_cents: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_cents")), realized_cap_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), realized_loss: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss")), + realized_loss_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_loss_7d_ema")), realized_loss_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit")), + realized_profit_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_profit_7d_ema")), realized_profit_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), realized_profit_to_loss_ratio: MetricPattern6::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), sell_side_risk_ratio: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), sell_side_risk_ratio_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), sell_side_risk_ratio_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sent_in_loss: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_loss")), + sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_loss_14d_ema")), + sent_in_profit: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_profit")), + sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_profit_14d_ema")), sopr: MetricPattern6::new(client.clone(), _m(&acc, "sopr")), sopr_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_30d_ema")), sopr_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_7d_ema")), @@ -960,13 +976,12 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal } /// Pattern struct for repeated tree structure. -pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 { +pub struct AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { pub adjusted_sopr: MetricPattern6, pub adjusted_sopr_30d_ema: MetricPattern6, pub adjusted_sopr_7d_ema: MetricPattern6, pub adjusted_value_created: MetricPattern1, pub adjusted_value_destroyed: MetricPattern1, - pub ath_regret: CumulativeSumPattern, pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, pub investor_cap_raw: MetricPattern11, @@ -978,10 +993,13 @@ pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSop pub mvrv: MetricPattern4, pub neg_realized_loss: CumulativeSumPattern2, pub net_realized_pnl: CumulativeSumPattern, + pub net_realized_pnl_7d_ema: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, pub net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern, + pub peak_regret: CumulativeSumPattern, + pub peak_regret_rel_to_realized_cap: MetricPattern1, pub profit_flow: MetricPattern1, pub profit_value_created: MetricPattern1, pub profit_value_destroyed: MetricPattern1, @@ -989,15 +1007,21 @@ pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSop pub realized_cap_30d_delta: MetricPattern4, pub realized_cap_cents: MetricPattern1, pub realized_loss: CumulativeSumPattern, + pub realized_loss_7d_ema: MetricPattern4, pub realized_loss_rel_to_realized_cap: CumulativeSumPattern, pub realized_price: DollarsSatsPattern, pub realized_price_extra: RatioPattern2, pub realized_profit: CumulativeSumPattern, + pub realized_profit_7d_ema: MetricPattern4, pub realized_profit_rel_to_realized_cap: CumulativeSumPattern, pub realized_value: MetricPattern1, pub sell_side_risk_ratio: MetricPattern6, pub sell_side_risk_ratio_30d_ema: MetricPattern6, pub sell_side_risk_ratio_7d_ema: MetricPattern6, + pub sent_in_loss: BitcoinDollarsSatsPattern3, + pub sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5, + pub sent_in_profit: BitcoinDollarsSatsPattern3, + pub sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5, pub sopr: MetricPattern6, pub sopr_30d_ema: MetricPattern6, pub sopr_7d_ema: MetricPattern6, @@ -1006,7 +1030,7 @@ pub struct AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSop pub value_destroyed: MetricPattern1, } -impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 { +impl AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -1015,7 +1039,6 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal adjusted_sopr_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "adjusted_sopr_7d_ema")), adjusted_value_created: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_created")), adjusted_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), - ath_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_ath_regret")), cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), @@ -1027,10 +1050,13 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: CumulativeSumPattern2::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), + net_realized_pnl_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_7d_ema")), net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + peak_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_peak_regret")), + peak_regret_rel_to_realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "peak_regret_rel_to_realized_cap")), profit_flow: MetricPattern1::new(client.clone(), _m(&acc, "profit_flow")), profit_value_created: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_created")), profit_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_destroyed")), @@ -1038,15 +1064,21 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_cap_cents: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_cents")), realized_loss: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss")), + realized_loss_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_loss_7d_ema")), realized_loss_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RatioPattern2::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit")), + realized_profit_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_profit_7d_ema")), realized_profit_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), sell_side_risk_ratio: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), sell_side_risk_ratio_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), sell_side_risk_ratio_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sent_in_loss: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_loss")), + sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_loss_14d_ema")), + sent_in_profit: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_profit")), + sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_profit_14d_ema")), sopr: MetricPattern6::new(client.clone(), _m(&acc, "sopr")), sopr_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_30d_ema")), sopr_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_7d_ema")), @@ -1058,8 +1090,7 @@ impl AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotal } /// Pattern struct for repeated tree structure. -pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 { - pub ath_regret: CumulativeSumPattern, +pub struct CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, pub investor_cap_raw: MetricPattern11, @@ -1071,10 +1102,13 @@ pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalVa pub mvrv: MetricPattern4, pub neg_realized_loss: CumulativeSumPattern2, pub net_realized_pnl: CumulativeSumPattern, + pub net_realized_pnl_7d_ema: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, pub net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern, + pub peak_regret: CumulativeSumPattern, + pub peak_regret_rel_to_realized_cap: MetricPattern1, pub profit_flow: MetricPattern1, pub profit_value_created: MetricPattern1, pub profit_value_destroyed: MetricPattern1, @@ -1083,16 +1117,22 @@ pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalVa pub realized_cap_cents: MetricPattern1, pub realized_cap_rel_to_own_market_cap: MetricPattern1, pub realized_loss: CumulativeSumPattern, + pub realized_loss_7d_ema: MetricPattern4, pub realized_loss_rel_to_realized_cap: CumulativeSumPattern, pub realized_price: DollarsSatsPattern, pub realized_price_extra: RatioPattern, pub realized_profit: CumulativeSumPattern, + pub realized_profit_7d_ema: MetricPattern4, pub realized_profit_rel_to_realized_cap: CumulativeSumPattern, pub realized_profit_to_loss_ratio: MetricPattern6, pub realized_value: MetricPattern1, pub sell_side_risk_ratio: MetricPattern6, pub sell_side_risk_ratio_30d_ema: MetricPattern6, pub sell_side_risk_ratio_7d_ema: MetricPattern6, + pub sent_in_loss: BitcoinDollarsSatsPattern3, + pub sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5, + pub sent_in_profit: BitcoinDollarsSatsPattern3, + pub sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5, pub sopr: MetricPattern6, pub sopr_30d_ema: MetricPattern6, pub sopr_7d_ema: MetricPattern6, @@ -1101,11 +1141,10 @@ pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalVa pub value_destroyed: MetricPattern1, } -impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 { +impl CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - ath_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_ath_regret")), cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), @@ -1117,10 +1156,13 @@ impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePat mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: CumulativeSumPattern2::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), + net_realized_pnl_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_7d_ema")), net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + peak_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_peak_regret")), + peak_regret_rel_to_realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "peak_regret_rel_to_realized_cap")), profit_flow: MetricPattern1::new(client.clone(), _m(&acc, "profit_flow")), profit_value_created: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_created")), profit_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_destroyed")), @@ -1129,16 +1171,22 @@ impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePat realized_cap_cents: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_cents")), realized_cap_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), realized_loss: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss")), + realized_loss_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_loss_7d_ema")), realized_loss_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit")), + realized_profit_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_profit_7d_ema")), realized_profit_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), realized_profit_to_loss_ratio: MetricPattern6::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), sell_side_risk_ratio: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), sell_side_risk_ratio_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), sell_side_risk_ratio_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sent_in_loss: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_loss")), + sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_loss_14d_ema")), + sent_in_profit: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_profit")), + sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_profit_14d_ema")), sopr: MetricPattern6::new(client.clone(), _m(&acc, "sopr")), sopr_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_30d_ema")), sopr_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_7d_ema")), @@ -1150,8 +1198,7 @@ impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePat } /// Pattern struct for repeated tree structure. -pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern { - pub ath_regret: CumulativeSumPattern, +pub struct CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { pub cap_raw: MetricPattern11, pub capitulation_flow: MetricPattern1, pub investor_cap_raw: MetricPattern11, @@ -1163,10 +1210,13 @@ pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalVa pub mvrv: MetricPattern4, pub neg_realized_loss: CumulativeSumPattern2, pub net_realized_pnl: CumulativeSumPattern, + pub net_realized_pnl_7d_ema: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, pub net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern, + pub peak_regret: CumulativeSumPattern, + pub peak_regret_rel_to_realized_cap: MetricPattern1, pub profit_flow: MetricPattern1, pub profit_value_created: MetricPattern1, pub profit_value_destroyed: MetricPattern1, @@ -1174,15 +1224,21 @@ pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalVa pub realized_cap_30d_delta: MetricPattern4, pub realized_cap_cents: MetricPattern1, pub realized_loss: CumulativeSumPattern, + pub realized_loss_7d_ema: MetricPattern4, pub realized_loss_rel_to_realized_cap: CumulativeSumPattern, pub realized_price: DollarsSatsPattern, pub realized_price_extra: RatioPattern2, pub realized_profit: CumulativeSumPattern, + pub realized_profit_7d_ema: MetricPattern4, pub realized_profit_rel_to_realized_cap: CumulativeSumPattern, pub realized_value: MetricPattern1, pub sell_side_risk_ratio: MetricPattern6, pub sell_side_risk_ratio_30d_ema: MetricPattern6, pub sell_side_risk_ratio_7d_ema: MetricPattern6, + pub sent_in_loss: BitcoinDollarsSatsPattern3, + pub sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5, + pub sent_in_profit: BitcoinDollarsSatsPattern3, + pub sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5, pub sopr: MetricPattern6, pub sopr_30d_ema: MetricPattern6, pub sopr_7d_ema: MetricPattern6, @@ -1191,11 +1247,10 @@ pub struct AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalVa pub value_destroyed: MetricPattern1, } -impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern { +impl CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - ath_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_ath_regret")), cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "cap_raw")), capitulation_flow: MetricPattern1::new(client.clone(), _m(&acc, "capitulation_flow")), investor_cap_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_raw")), @@ -1207,10 +1262,13 @@ impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePat mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: CumulativeSumPattern2::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), + net_realized_pnl_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_7d_ema")), net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + peak_regret: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_peak_regret")), + peak_regret_rel_to_realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "peak_regret_rel_to_realized_cap")), profit_flow: MetricPattern1::new(client.clone(), _m(&acc, "profit_flow")), profit_value_created: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_created")), profit_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_destroyed")), @@ -1218,15 +1276,21 @@ impl AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePat realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_cap_cents: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_cents")), realized_loss: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss")), + realized_loss_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_loss_7d_ema")), realized_loss_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: DollarsSatsPattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RatioPattern2::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit")), + realized_profit_7d_ema: MetricPattern4::new(client.clone(), _m(&acc, "realized_profit_7d_ema")), realized_profit_rel_to_realized_cap: CumulativeSumPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), sell_side_risk_ratio: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), sell_side_risk_ratio_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), sell_side_risk_ratio_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sent_in_loss: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_loss")), + sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_loss_14d_ema")), + sent_in_profit: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent_in_profit")), + sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_in_profit_14d_ema")), sopr: MetricPattern6::new(client.clone(), _m(&acc, "sopr")), sopr_30d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_30d_ema")), sopr_7d_ema: MetricPattern6::new(client.clone(), _m(&acc, "sopr_7d_ema")), @@ -1306,7 +1370,7 @@ impl _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern { } /// Pattern struct for repeated tree structure. -pub struct InvestedNegNetNuplSupplyUnrealizedPattern2 { +pub struct InvestedNegNetNuplSupplyUnrealizedPattern4 { pub invested_capital_in_loss_pct: MetricPattern1, pub invested_capital_in_profit_pct: MetricPattern1, pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1, @@ -1324,12 +1388,13 @@ pub struct InvestedNegNetNuplSupplyUnrealizedPattern2 { pub unrealized_loss_rel_to_market_cap: MetricPattern1, pub unrealized_loss_rel_to_own_market_cap: MetricPattern1, pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub unrealized_peak_regret_rel_to_market_cap: MetricPattern4, pub unrealized_profit_rel_to_market_cap: MetricPattern1, pub unrealized_profit_rel_to_own_market_cap: MetricPattern1, pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1, } -impl InvestedNegNetNuplSupplyUnrealizedPattern2 { +impl InvestedNegNetNuplSupplyUnrealizedPattern4 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -1350,6 +1415,7 @@ impl InvestedNegNetNuplSupplyUnrealizedPattern2 { unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), + unrealized_peak_regret_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "unrealized_peak_regret_rel_to_market_cap")), unrealized_profit_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), unrealized_profit_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), @@ -1510,8 +1576,53 @@ impl RatioPattern { } /// Pattern struct for repeated tree structure. -pub struct AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern { - pub ath_regret: MetricPattern1, +pub struct GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern { + pub greed_index: MetricPattern1, + pub invested_capital_in_loss: MetricPattern1, + pub invested_capital_in_loss_raw: MetricPattern11, + pub invested_capital_in_profit: MetricPattern1, + pub invested_capital_in_profit_raw: MetricPattern11, + pub investor_cap_in_loss_raw: MetricPattern11, + pub investor_cap_in_profit_raw: MetricPattern11, + pub neg_unrealized_loss: MetricPattern1, + pub net_sentiment: MetricPattern1, + pub net_unrealized_pnl: MetricPattern1, + pub pain_index: MetricPattern1, + pub peak_regret: MetricPattern4, + pub supply_in_loss: BitcoinDollarsSatsPattern4, + pub supply_in_profit: BitcoinDollarsSatsPattern4, + pub total_unrealized_pnl: MetricPattern1, + pub unrealized_loss: MetricPattern1, + pub unrealized_profit: MetricPattern1, +} + +impl GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + greed_index: MetricPattern1::new(client.clone(), _m(&acc, "greed_index")), + invested_capital_in_loss: MetricPattern1::new(client.clone(), _m(&acc, "invested_capital_in_loss")), + invested_capital_in_loss_raw: MetricPattern11::new(client.clone(), _m(&acc, "invested_capital_in_loss_raw")), + invested_capital_in_profit: MetricPattern1::new(client.clone(), _m(&acc, "invested_capital_in_profit")), + invested_capital_in_profit_raw: MetricPattern11::new(client.clone(), _m(&acc, "invested_capital_in_profit_raw")), + investor_cap_in_loss_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_in_loss_raw")), + investor_cap_in_profit_raw: MetricPattern11::new(client.clone(), _m(&acc, "investor_cap_in_profit_raw")), + neg_unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")), + net_sentiment: MetricPattern1::new(client.clone(), _m(&acc, "net_sentiment")), + net_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl")), + pain_index: MetricPattern1::new(client.clone(), _m(&acc, "pain_index")), + peak_regret: MetricPattern4::new(client.clone(), _m(&acc, "unrealized_peak_regret")), + supply_in_loss: BitcoinDollarsSatsPattern4::new(client.clone(), _m(&acc, "supply_in_loss")), + supply_in_profit: BitcoinDollarsSatsPattern4::new(client.clone(), _m(&acc, "supply_in_profit")), + total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_unrealized_pnl")), + unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss")), + unrealized_profit: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern { pub greed_index: MetricPattern1, pub invested_capital_in_loss: MetricPattern1, pub invested_capital_in_loss_raw: MetricPattern11, @@ -1530,11 +1641,10 @@ pub struct AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern { pub unrealized_profit: MetricPattern1, } -impl AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern { +impl GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - ath_regret: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_ath_regret")), greed_index: MetricPattern1::new(client.clone(), _m(&acc, "greed_index")), invested_capital_in_loss: MetricPattern1::new(client.clone(), _m(&acc, "invested_capital_in_loss")), invested_capital_in_loss_raw: MetricPattern11::new(client.clone(), _m(&acc, "invested_capital_in_loss_raw")), @@ -1597,6 +1707,44 @@ impl _1m1w1y24hBlocksCoinbaseDaysDominanceFeeSubsidyPattern { } } +/// Pattern struct for repeated tree structure. +pub struct InvestedNegNetNuplSupplyUnrealizedPattern3 { + pub invested_capital_in_loss_pct: MetricPattern1, + pub invested_capital_in_profit_pct: MetricPattern1, + pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1, + pub net_unrealized_pnl_rel_to_market_cap: MetricPattern1, + pub nupl: MetricPattern1, + pub supply_in_loss_rel_to_circulating_supply: MetricPattern1, + pub supply_in_loss_rel_to_own_supply: MetricPattern1, + pub supply_in_profit_rel_to_circulating_supply: MetricPattern1, + pub supply_in_profit_rel_to_own_supply: MetricPattern1, + pub supply_rel_to_circulating_supply: MetricPattern4, + pub unrealized_loss_rel_to_market_cap: MetricPattern1, + pub unrealized_peak_regret_rel_to_market_cap: MetricPattern4, + pub unrealized_profit_rel_to_market_cap: MetricPattern1, +} + +impl InvestedNegNetNuplSupplyUnrealizedPattern3 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + invested_capital_in_loss_pct: MetricPattern1::new(client.clone(), _m(&acc, "invested_capital_in_loss_pct")), + invested_capital_in_profit_pct: MetricPattern1::new(client.clone(), _m(&acc, "invested_capital_in_profit_pct")), + neg_unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), + net_unrealized_pnl_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")), + nupl: MetricPattern1::new(client.clone(), _m(&acc, "nupl")), + supply_in_loss_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), + supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), + supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), + unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), + unrealized_peak_regret_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "unrealized_peak_regret_rel_to_market_cap")), + unrealized_profit_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _10y1m1w1y2y3m3y4y5y6m6y8yPattern3 { pub _10y: BitcoinDollarsSatsPattern5, @@ -1973,10 +2121,10 @@ pub struct ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern { pub addr_count: MetricPattern1, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern, - pub supply: HalvedTotalPattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, } impl ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern { @@ -1987,10 +2135,10 @@ impl ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern { addr_count: MetricPattern1::new(client.clone(), _m(&acc, "addr_count")), cost_basis: MaxMinPattern::new(client.clone(), acc.clone()), outputs: UtxoPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedNegNetNuplSupplyUnrealizedPattern::new(client.clone(), acc.clone()), - supply: HalvedTotalPattern::new(client.clone(), _m(&acc, "supply")), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), + unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), } } } @@ -2026,10 +2174,10 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, pub outputs: UtxoPattern, - pub realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, pub relative: InvestedNegNetSupplyUnrealizedPattern, - pub supply: HalvedTotalPattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, } impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern { @@ -2039,10 +2187,10 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2::new(client.clone(), acc.clone()), + realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), acc.clone()), relative: InvestedNegNetSupplyUnrealizedPattern::new(client.clone(), acc.clone()), - supply: HalvedTotalPattern::new(client.clone(), _m(&acc, "supply")), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), + unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), } } } @@ -2052,10 +2200,10 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2, - pub relative: InvestedNegNetNuplSupplyUnrealizedPattern, - pub supply: HalvedTotalPattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, + pub relative: InvestedNegNetNuplSupplyUnrealizedPattern3, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, } impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5 { @@ -2065,10 +2213,10 @@ 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: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2::new(client.clone(), acc.clone()), - relative: InvestedNegNetNuplSupplyUnrealizedPattern::new(client.clone(), acc.clone()), - supply: HalvedTotalPattern::new(client.clone(), _m(&acc, "supply")), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::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()), } } } @@ -2078,10 +2226,10 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedNegNetNuplSupplyUnrealizedPattern, - pub supply: HalvedTotalPattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, } impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 { @@ -2091,10 +2239,36 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedNegNetNuplSupplyUnrealizedPattern::new(client.clone(), acc.clone()), - supply: HalvedTotalPattern::new(client.clone(), _m(&acc, "supply")), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), + unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 { + pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, + pub cost_basis: MaxMinPattern, + pub outputs: UtxoPattern, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub relative: InvestedNegNetNuplSupplyUnrealizedPattern3, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, +} + +impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + 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()), + relative: InvestedNegNetNuplSupplyUnrealizedPattern3::new(client.clone(), acc.clone()), + supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), + unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), } } } @@ -2104,10 +2278,10 @@ pub struct ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3 { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, pub relative: InvestedSupplyPattern, - pub supply: HalvedTotalPattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, } impl ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3 { @@ -2117,10 +2291,10 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern::new(client.clone(), acc.clone()), + realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), relative: InvestedSupplyPattern::new(client.clone(), acc.clone()), - supply: HalvedTotalPattern::new(client.clone(), _m(&acc, "supply")), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), + unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), } } } @@ -2130,9 +2304,9 @@ pub struct ActivityCostOutputsRealizedSupplyUnrealizedPattern { pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, pub cost_basis: MaxMinPattern, pub outputs: UtxoPattern, - pub realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern, - pub supply: HalvedTotalPattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub supply: _30dHalvedTotalPattern, + pub unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, } impl ActivityCostOutputsRealizedSupplyUnrealizedPattern { @@ -2142,9 +2316,9 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern::new(client.clone(), acc.clone()), - supply: HalvedTotalPattern::new(client.clone(), _m(&acc, "supply")), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), + realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), acc.clone()), + supply: _30dHalvedTotalPattern::new(client.clone(), acc.clone()), + unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), acc.clone()), } } } @@ -2173,6 +2347,30 @@ impl BalanceBothReactivatedReceivingSendingPattern { } } +/// Pattern struct for repeated tree structure. +pub struct CoinblocksCoindaysSatblocksSatdaysSentPattern { + pub coinblocks_destroyed: CumulativeSumPattern, + pub coindays_destroyed: CumulativeSumPattern, + pub satblocks_destroyed: MetricPattern11, + pub satdays_destroyed: MetricPattern11, + pub sent: BitcoinDollarsSatsPattern3, + pub sent_14d_ema: BitcoinDollarsSatsPattern5, +} + +impl CoinblocksCoindaysSatblocksSatdaysSentPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + coinblocks_destroyed: CumulativeSumPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")), + coindays_destroyed: CumulativeSumPattern::new(client.clone(), _m(&acc, "coindays_destroyed")), + satblocks_destroyed: MetricPattern11::new(client.clone(), _m(&acc, "satblocks_destroyed")), + satdays_destroyed: MetricPattern11::new(client.clone(), _m(&acc, "satdays_destroyed")), + sent: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent")), + sent_14d_ema: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "sent_14d_ema")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct InvestedMaxMinPercentilesSpotPattern { pub invested_capital: Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern, @@ -2197,28 +2395,6 @@ impl InvestedMaxMinPercentilesSpotPattern { } } -/// Pattern struct for repeated tree structure. -pub struct CoinblocksCoindaysSatblocksSatdaysSentPattern { - pub coinblocks_destroyed: CumulativeSumPattern, - pub coindays_destroyed: CumulativeSumPattern, - pub satblocks_destroyed: MetricPattern11, - pub satdays_destroyed: MetricPattern11, - pub sent: BitcoinDollarsSatsPattern3, -} - -impl CoinblocksCoindaysSatblocksSatdaysSentPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - coinblocks_destroyed: CumulativeSumPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")), - coindays_destroyed: CumulativeSumPattern::new(client.clone(), _m(&acc, "coindays_destroyed")), - satblocks_destroyed: MetricPattern11::new(client.clone(), _m(&acc, "satblocks_destroyed")), - satdays_destroyed: MetricPattern11::new(client.clone(), _m(&acc, "satdays_destroyed")), - sent: BitcoinDollarsSatsPattern3::new(client.clone(), _m(&acc, "sent")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct InvestedSupplyPattern { pub invested_capital_in_loss_pct: MetricPattern1, @@ -2259,6 +2435,24 @@ impl CloseHighLowOpenPattern2 { } } +/// Pattern struct for repeated tree structure. +pub struct _30dHalvedTotalPattern { + pub _30d_change: BitcoinDollarsSatsPattern5, + pub halved: BitcoinDollarsSatsPattern4, + pub total: BitcoinDollarsSatsPattern4, +} + +impl _30dHalvedTotalPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + _30d_change: BitcoinDollarsSatsPattern5::new(client.clone(), _m(&acc, "_30d_change")), + halved: BitcoinDollarsSatsPattern4::new(client.clone(), _m(&acc, "supply_halved")), + total: BitcoinDollarsSatsPattern4::new(client.clone(), _m(&acc, "supply")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct BaseCumulativeSumPattern { pub base: MetricPattern11, @@ -2399,22 +2593,6 @@ impl DollarsSatsPattern2 { } } -/// Pattern struct for repeated tree structure. -pub struct HalvedTotalPattern { - pub halved: BitcoinDollarsSatsPattern4, - pub total: BitcoinDollarsSatsPattern4, -} - -impl HalvedTotalPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - halved: BitcoinDollarsSatsPattern4::new(client.clone(), _m(&acc, "halved")), - total: BitcoinDollarsSatsPattern4::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct MaxMinPattern { pub max: DollarsSatsPattern, @@ -4923,7 +5101,7 @@ impl MetricsTree_Price_Usd { /// Metrics tree node. pub struct MetricsTree_Distribution { - pub chain_state: MetricPattern11, + pub supply_state: MetricPattern11, pub any_address_indexes: MetricsTree_Distribution_AnyAddressIndexes, pub addresses_data: MetricsTree_Distribution_AddressesData, pub utxo_cohorts: MetricsTree_Distribution_UtxoCohorts, @@ -4941,7 +5119,7 @@ pub struct MetricsTree_Distribution { impl MetricsTree_Distribution { pub fn new(client: Arc, base_path: String) -> Self { Self { - chain_state: MetricPattern11::new(client.clone(), "chain".to_string()), + supply_state: MetricPattern11::new(client.clone(), "supply_state".to_string()), any_address_indexes: MetricsTree_Distribution_AnyAddressIndexes::new(client.clone(), format!("{base_path}_any_address_indexes")), addresses_data: MetricsTree_Distribution_AddressesData::new(client.clone(), format!("{base_path}_addresses_data")), utxo_cohorts: MetricsTree_Distribution_UtxoCohorts::new(client.clone(), format!("{base_path}_utxo_cohorts")), @@ -5035,11 +5213,11 @@ impl MetricsTree_Distribution_UtxoCohorts { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_All { - pub supply: HalvedTotalPattern, + pub supply: _30dHalvedTotalPattern, pub outputs: UtxoPattern, pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, - pub realized: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, pub relative: MetricsTree_Distribution_UtxoCohorts_All_Relative, } @@ -5047,11 +5225,11 @@ pub struct MetricsTree_Distribution_UtxoCohorts_All { impl MetricsTree_Distribution_UtxoCohorts_All { pub fn new(client: Arc, base_path: String) -> Self { Self { - supply: HalvedTotalPattern::new(client.clone(), "supply".to_string()), + supply: _30dHalvedTotalPattern::new(client.clone(), "".to_string()), outputs: UtxoPattern::new(client.clone(), "utxo_count".to_string()), activity: CoinblocksCoindaysSatblocksSatdaysSentPattern::new(client.clone(), "".to_string()), - realized: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern::new(client.clone(), "".to_string()), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), "".to_string()), + realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::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")), } @@ -5062,12 +5240,18 @@ impl MetricsTree_Distribution_UtxoCohorts_All { pub struct MetricsTree_Distribution_UtxoCohorts_All_Relative { pub supply_in_profit_rel_to_own_supply: MetricPattern1, pub supply_in_loss_rel_to_own_supply: MetricPattern1, + pub unrealized_profit_rel_to_market_cap: MetricPattern1, + pub unrealized_loss_rel_to_market_cap: MetricPattern1, + pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1, + pub net_unrealized_pnl_rel_to_market_cap: MetricPattern1, + pub nupl: MetricPattern1, pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1, pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1, pub invested_capital_in_profit_pct: MetricPattern1, pub invested_capital_in_loss_pct: MetricPattern1, + pub unrealized_peak_regret_rel_to_market_cap: MetricPattern4, } impl MetricsTree_Distribution_UtxoCohorts_All_Relative { @@ -5075,12 +5259,18 @@ impl MetricsTree_Distribution_UtxoCohorts_All_Relative { Self { supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), "supply_in_profit_rel_to_own_supply".to_string()), supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), "supply_in_loss_rel_to_own_supply".to_string()), + unrealized_profit_rel_to_market_cap: MetricPattern1::new(client.clone(), "unrealized_profit_rel_to_market_cap".to_string()), + unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), "unrealized_loss_rel_to_market_cap".to_string()), + neg_unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), "neg_unrealized_loss_rel_to_market_cap".to_string()), + net_unrealized_pnl_rel_to_market_cap: MetricPattern1::new(client.clone(), "net_unrealized_pnl_rel_to_market_cap".to_string()), + nupl: MetricPattern1::new(client.clone(), "nupl".to_string()), unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), "unrealized_profit_rel_to_own_total_unrealized_pnl".to_string()), unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), "unrealized_loss_rel_to_own_total_unrealized_pnl".to_string()), neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), "neg_unrealized_loss_rel_to_own_total_unrealized_pnl".to_string()), net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), "net_unrealized_pnl_rel_to_own_total_unrealized_pnl".to_string()), invested_capital_in_profit_pct: MetricPattern1::new(client.clone(), "invested_capital_in_profit_pct".to_string()), invested_capital_in_loss_pct: MetricPattern1::new(client.clone(), "invested_capital_in_loss_pct".to_string()), + unrealized_peak_regret_rel_to_market_cap: MetricPattern4::new(client.clone(), "unrealized_peak_regret_rel_to_market_cap".to_string()), } } } @@ -5208,47 +5398,47 @@ impl MetricsTree_Distribution_UtxoCohorts_Year { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_MinAge { - pub _1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, - pub _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4, + pub _1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, + pub _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6, } impl MetricsTree_Distribution_UtxoCohorts_MinAge { pub fn new(client: Arc, base_path: String) -> Self { Self { - _1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_1d_old".to_string()), - _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_1w_old".to_string()), - _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_1m_old".to_string()), - _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_2m_old".to_string()), - _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_3m_old".to_string()), - _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_4m_old".to_string()), - _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_5m_old".to_string()), - _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_6m_old".to_string()), - _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_1y_old".to_string()), - _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_2y_old".to_string()), - _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_3y_old".to_string()), - _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_4y_old".to_string()), - _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_5y_old".to_string()), - _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_6y_old".to_string()), - _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_7y_old".to_string()), - _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_8y_old".to_string()), - _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_10y_old".to_string()), - _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_over_12y_old".to_string()), + _1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_1d_old".to_string()), + _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_1w_old".to_string()), + _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_1m_old".to_string()), + _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_2m_old".to_string()), + _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_3m_old".to_string()), + _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_4m_old".to_string()), + _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_5m_old".to_string()), + _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_6m_old".to_string()), + _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_1y_old".to_string()), + _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_2y_old".to_string()), + _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_3y_old".to_string()), + _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_4y_old".to_string()), + _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_5y_old".to_string()), + _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_6y_old".to_string()), + _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_7y_old".to_string()), + _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_8y_old".to_string()), + _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_10y_old".to_string()), + _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6::new(client.clone(), "utxos_over_12y_old".to_string()), } } } @@ -5348,50 +5538,50 @@ impl MetricsTree_Distribution_UtxoCohorts_Term { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_Term_Short { - pub supply: HalvedTotalPattern, + pub supply: _30dHalvedTotalPattern, pub outputs: UtxoPattern, pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, - pub realized: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern, + pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, - pub relative: InvestedNegNetNuplSupplyUnrealizedPattern2, + pub relative: InvestedNegNetNuplSupplyUnrealizedPattern4, } impl MetricsTree_Distribution_UtxoCohorts_Term_Short { pub fn new(client: Arc, base_path: String) -> Self { Self { - supply: HalvedTotalPattern::new(client.clone(), "sth_supply".to_string()), + 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: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern::new(client.clone(), "sth".to_string()), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), "sth".to_string()), + realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern::new(client.clone(), "sth".to_string()), + unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), "sth".to_string()), cost_basis: InvestedMaxMinPercentilesSpotPattern::new(client.clone(), "sth".to_string()), - relative: InvestedNegNetNuplSupplyUnrealizedPattern2::new(client.clone(), "sth".to_string()), + relative: InvestedNegNetNuplSupplyUnrealizedPattern4::new(client.clone(), "sth".to_string()), } } } /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_Term_Long { - pub supply: HalvedTotalPattern, + pub supply: _30dHalvedTotalPattern, pub outputs: UtxoPattern, pub activity: CoinblocksCoindaysSatblocksSatdaysSentPattern, - pub realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2, - pub unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern, + pub realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2, + pub unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern, pub cost_basis: InvestedMaxMinPercentilesSpotPattern, - pub relative: InvestedNegNetNuplSupplyUnrealizedPattern2, + pub relative: InvestedNegNetNuplSupplyUnrealizedPattern4, } impl MetricsTree_Distribution_UtxoCohorts_Term_Long { pub fn new(client: Arc, base_path: String) -> Self { Self { - supply: HalvedTotalPattern::new(client.clone(), "lth_supply".to_string()), + 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2::new(client.clone(), "lth".to_string()), - unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern::new(client.clone(), "lth".to_string()), + realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2::new(client.clone(), "lth".to_string()), + unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern::new(client.clone(), "lth".to_string()), cost_basis: InvestedMaxMinPercentilesSpotPattern::new(client.clone(), "lth".to_string()), - relative: InvestedNegNetNuplSupplyUnrealizedPattern2::new(client.clone(), "lth".to_string()), + relative: InvestedNegNetNuplSupplyUnrealizedPattern4::new(client.clone(), "lth".to_string()), } } } diff --git a/crates/brk_computer/src/distribution/block/cohort/sent.rs b/crates/brk_computer/src/distribution/block/cohort/sent.rs index 6d4a8583b..ed9d89769 100644 --- a/crates/brk_computer/src/distribution/block/cohort/sent.rs +++ b/crates/brk_computer/src/distribution/block/cohort/sent.rs @@ -24,7 +24,7 @@ use super::super::cache::AddressLookup; /// parallel execution with UTXO cohort processing (which mutates chain_state). /// /// `price_range_max` is used to compute the peak price during each UTXO's holding period -/// for accurate ATH regret calculation. +/// for accurate peak regret calculation. #[allow(clippy::too_many_arguments)] pub fn process_sent( sent_data: HeightToAddressTypeToVec<(TypeIndex, Sats)>, @@ -50,7 +50,7 @@ pub fn process_sent( let blocks_old = current_height.to_usize() - receive_height.to_usize(); let age = Age::new(current_timestamp, prev_timestamp, blocks_old); - // Compute peak price during holding period for ATH regret + // Compute peak price during holding period for peak regret // This is the max HIGH price between receive and send heights let peak_price: Option = price_range_max.map(|t| t.max_between(receive_height, current_height)); diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index dbf43a41b..cad58cd60 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -1,19 +1,21 @@ use std::{cmp::Reverse, collections::BinaryHeap, path::Path}; use brk_cohort::{ - ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge, ByMinAge, - BySpendableType, ByTerm, ByYear, Filter, Filtered, StateLevel, UTXOGroups, + AGE_BOUNDARIES, ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, + ByMaxAge, ByMinAge, BySpendableType, ByTerm, ByYear, Filter, Filtered, StateLevel, UTXOGroups, }; use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{CentsUnsigned, DateIndex, Dollars, Height, Sats, StoredF32, Version}; +use brk_types::{ + CentsUnsigned, DateIndex, Dollars, Height, ONE_HOUR_IN_SEC, Sats, StoredF32, Timestamp, Version, +}; use derive_more::{Deref, DerefMut}; use rayon::prelude::*; -use vecdb::{AnyStoredVec, Database, Exit, GenericStoredVec, IterableVec}; +use vecdb::{AnyStoredVec, Database, Exit, GenericStoredVec, IterableVec, VecIndex}; use crate::{ ComputeIndexes, - distribution::DynCohortVecs, + distribution::{DynCohortVecs, compute::PriceRangeMax, state::BlockState}, indexes, internal::{PERCENTILES, PERCENTILES_LEN, compute_spot_percentile_rank}, price, @@ -357,13 +359,13 @@ impl UTXOCohorts { }) .collect(); - // Compute percentiles for each aggregate filter - for aggregate in self.0.iter_aggregate_mut() { + // Compute percentiles for each aggregate filter in parallel + self.0.par_iter_aggregate_mut().try_for_each(|aggregate| { let filter = aggregate.filter().clone(); // Get cost_basis, skip if not configured let Some(cost_basis) = aggregate.metrics.cost_basis.as_mut() else { - continue; + return Ok(()); }; // Collect relevant cohort data for this aggregate and sum totals @@ -397,7 +399,7 @@ impl UTXOCohorts { .dateindex .truncate_push(dateindex, StoredF32::NAN)?; } - continue; + return Ok(()); } // K-way merge using min-heap: O(n log k) where k = number of cohorts @@ -507,9 +509,9 @@ impl UTXOCohorts { let rank = compute_spot_percentile_rank(&usd_result, spot); spot_pct.dateindex.truncate_push(dateindex, rank)?; } - } - Ok(()) + Ok(()) + }) } /// Validate computed versions for all cohorts (separate and aggregate). @@ -525,4 +527,112 @@ impl UTXOCohorts { Ok(()) } + + /// Compute and push peak regret for all age_range cohorts. + /// + /// Uses split points to efficiently compute regret per cohort. + /// All 21 cohorts are computed in parallel, then pushed sequentially. + /// Called once per day when dateindex changes. + pub fn compute_and_push_peak_regret( + &mut self, + chain_state: &[BlockState], + current_height: Height, + current_timestamp: Timestamp, + spot: CentsUnsigned, + price_range_max: &PriceRangeMax, + dateindex: DateIndex, + ) -> Result<()> { + const FIRST_PRICE_HEIGHT: usize = 68_195; + + let start_height = FIRST_PRICE_HEIGHT; + let end_height = current_height.to_usize() + 1; + + // Early return: push zeros if no price data yet + if end_height <= start_height { + for cohort in self.0.age_range.iter_mut() { + if let Some(unrealized) = cohort.metrics.unrealized.as_mut() + && let Some(peak_regret) = unrealized.peak_regret.as_mut() + { + peak_regret + .dateindex + .truncate_push(dateindex, Dollars::ZERO)?; + } + } + return Ok(()); + } + + let spot_u128 = spot.as_u128(); + let current_ts = *current_timestamp; + + // Compute split points: splits[k] = first index where age < AGE_BOUNDARIES[k] + let splits: [usize; 20] = std::array::from_fn(|k| { + let boundary_seconds = (AGE_BOUNDARIES[k] as u32) * ONE_HOUR_IN_SEC; + let threshold_ts = current_ts.saturating_sub(boundary_seconds); + chain_state[..end_height].partition_point(|b| *b.timestamp <= threshold_ts) + }); + + // Build ranges for all 21 cohorts + let ranges: [(usize, usize); 21] = std::array::from_fn(|i| { + if i == 0 { + (splits[0], end_height) + } else if i < 20 { + (splits[i], splits[i - 1]) + } else { + (start_height, splits[19]) + } + }); + + // Compute regret for all cohorts in parallel + let regrets: [Dollars; 21] = ranges + .into_par_iter() + .map(|(range_start, range_end)| { + let effective_start = range_start.max(start_height); + if effective_start >= range_end { + return Dollars::ZERO; + } + + let mut regret: u128 = 0; + for h in effective_start..range_end { + let block = &chain_state[h]; + let supply = block.supply.value; + + if supply.is_zero() { + continue; + } + + let cost_basis = match block.price { + Some(p) => p, + None => continue, + }; + + let receive_height = Height::from(h); + let peak = price_range_max.max_between(receive_height, current_height); + let peak_u128 = peak.as_u128(); + let cost_u128 = cost_basis.as_u128(); + let supply_u128 = supply.as_u128(); + + regret += if spot_u128 >= cost_u128 { + (peak_u128 - spot_u128) * supply_u128 + } else { + (peak_u128 - cost_u128) * supply_u128 + }; + } + + CentsUnsigned::new((regret / Sats::ONE_BTC_U128) as u64).to_dollars() + }) + .collect::>() + .try_into() + .unwrap(); + + // Push results to cohorts + for (cohort, regret) in self.0.age_range.iter_mut().zip(regrets) { + if let Some(unrealized) = cohort.metrics.unrealized.as_mut() + && let Some(peak_regret) = unrealized.peak_regret.as_mut() + { + peak_regret.dateindex.truncate_push(dateindex, regret)?; + } + } + + Ok(()) + } } diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/send.rs b/crates/brk_computer/src/distribution/cohorts/utxo/send.rs index d107171cd..cfa5989f1 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/send.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/send.rs @@ -19,7 +19,7 @@ impl UTXOCohorts { /// We need to update the cohort states based on when that UTXO was created. /// /// `price_range_max` is used to compute the peak price during each UTXO's holding period - /// for accurate ATH regret calculation. + /// for accurate peak regret calculation. pub fn send( &mut self, height_to_sent: FxHashMap, @@ -45,7 +45,7 @@ impl UTXOCohorts { let blocks_old = chain_len - 1 - receive_height.to_usize(); let age = Age::new(last_timestamp, block_state.timestamp, blocks_old); - // Compute peak price during holding period for ATH regret + // Compute peak price during holding period for peak regret // This is the max HIGH price between receive and send heights let peak_price: Option = price_range_max.map(|t| t.max_between(receive_height, send_height)); diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs b/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs index 278a45c73..df78c471e 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs @@ -11,10 +11,10 @@ impl UTXOCohorts { /// UTXOs age with each block. When they cross hour boundaries, /// they move between age-based cohorts (e.g., from "0-1h" to "1h-1d"). /// - /// Complexity: O(k * (log n + m)) where: + /// Complexity: O(k * log n) where: /// - k = 20 boundaries to check /// - n = total blocks in chain_state - /// - m = blocks crossing each boundary (typically 0-2 per boundary per block) + /// - Linear scan for end_idx is faster than binary search since typically 0-2 blocks cross each boundary pub fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp) { if chain_state.is_empty() { return; @@ -49,9 +49,12 @@ impl UTXOCohorts { continue; } - // Binary search to find blocks in the timestamp range (lower, upper] + // Binary search to find start, then linear scan for end (typically 0-2 blocks) let start_idx = chain_state.partition_point(|b| *b.timestamp <= lower_timestamp); - let end_idx = chain_state.partition_point(|b| *b.timestamp <= upper_timestamp); + let end_idx = chain_state[start_idx..] + .iter() + .position(|b| *b.timestamp > upper_timestamp) + .map_or(chain_state.len(), |pos| start_idx + pos); // Move supply from younger cohort to older cohort for block_state in &chain_state[start_idx..end_idx] { diff --git a/crates/brk_computer/src/distribution/compute/block_loop.rs b/crates/brk_computer/src/distribution/compute/block_loop.rs index 4a348447d..ec508ed13 100644 --- a/crates/brk_computer/src/distribution/compute/block_loop.rs +++ b/crates/brk_computer/src/distribution/compute/block_loop.rs @@ -6,7 +6,7 @@ use brk_indexer::Indexer; use brk_types::{CentsUnsigned, DateIndex, Dollars, Height, OutputType, Sats, TxIndex, TypeIndex}; use rayon::prelude::*; use rustc_hash::FxHashSet; -use tracing::info; +use tracing::{debug, info}; use vecdb::{Exit, IterableVec, TypedVecIterator, VecIndex}; use crate::{ @@ -51,7 +51,9 @@ pub fn process_blocks( exit: &Exit, ) -> Result<()> { // Create computation context with pre-computed vectors for thread-safe access + debug!("creating ComputeContext"); let ctx = ComputeContext::new(starting_height, last_height, blocks, price); + debug!("ComputeContext created"); if ctx.starting_height > ctx.last_height { return Ok(()); @@ -99,9 +101,12 @@ pub fn process_blocks( let mut height_to_price_iter = height_to_price.map(|v| v.into_iter()); let mut dateindex_to_price_iter = dateindex_to_price.map(|v| v.into_iter()); + debug!("creating VecsReaders"); let mut vr = VecsReaders::new(&vecs.any_address_indexes, &vecs.addresses_data); + debug!("VecsReaders created"); // Build txindex -> height lookup map for efficient prev_height computation + debug!("building txindex_to_height RangeMap"); let mut txindex_to_height: RangeMap = { let mut map = RangeMap::with_capacity(last_height.to_usize() + 1); for first_txindex in indexer.vecs.transactions.first_txindex.into_iter() { @@ -109,6 +114,7 @@ pub fn process_blocks( } map }; + debug!("txindex_to_height RangeMap built"); // Create reusable iterators for sequential txout/txin reads (16KB buffered) let mut txout_iters = TxOutIterators::new(indexer); @@ -125,6 +131,7 @@ pub fn process_blocks( let mut first_p2wsh_iter = indexer.vecs.addresses.first_p2wshaddressindex.into_iter(); // Track running totals - recover from previous height if resuming + debug!("recovering addr_counts from height {}", starting_height); let (mut addr_counts, mut empty_addr_counts) = if starting_height > Height::ZERO { let addr_counts = AddressTypeToAddressCount::from((&vecs.addr_count.by_addresstype, starting_height)); @@ -139,11 +146,14 @@ pub fn process_blocks( AddressTypeToAddressCount::default(), ) }; + debug!("addr_counts recovered"); // Track activity counts - reset each block let mut activity_counts = AddressTypeToActivityCounts::default(); + debug!("creating AddressCache"); let mut cache = AddressCache::new(); + debug!("AddressCache created, entering main loop"); // Main block iteration for height in starting_height.to_usize()..=last_height.to_usize() { @@ -390,6 +400,21 @@ pub fn process_blocks( .unwrap_or(Dollars::NAN); vecs.utxo_cohorts .truncate_push_aggregate_percentiles(dateindex, spot)?; + + // Compute unrealized peak regret by age range (once per day) + // Aggregate cohorts (all, term, etc.) get values via compute_from_stateful + if let Some(spot_cents) = block_price + && let Some(price_range_max) = ctx.price_range_max.as_ref() + { + vecs.utxo_cohorts.compute_and_push_peak_regret( + chain_state, + height, + timestamp, + spot_cents, + price_range_max, + dateindex, + )?; + } } // Periodic checkpoint flush diff --git a/crates/brk_computer/src/distribution/compute/context.rs b/crates/brk_computer/src/distribution/compute/context.rs index 086ee90cb..92fb50eba 100644 --- a/crates/brk_computer/src/distribution/compute/context.rs +++ b/crates/brk_computer/src/distribution/compute/context.rs @@ -109,7 +109,7 @@ pub struct ComputeContext { pub height_to_price: Option>, /// Sparse table for O(1) range max queries on high prices. - /// Used for computing max price during UTXO holding periods (ATH regret). + /// Used for computing max price during UTXO holding periods (peak regret). pub price_range_max: Option, } @@ -129,7 +129,7 @@ impl ComputeContext { .map(|v| v.into_iter().map(|c| *c).collect()); // Build sparse table for O(1) range max queries on HIGH prices - // Used for computing peak price during UTXO holding periods (ATH regret) + // Used for computing peak price during UTXO holding periods (peak regret) let price_range_max = price .map(|p| &p.cents.split.height.high) .map(|v| v.into_iter().map(|c| *c).collect::>()) diff --git a/crates/brk_computer/src/distribution/compute/recover.rs b/crates/brk_computer/src/distribution/compute/recover.rs index 119fdadd1..d28fb8efa 100644 --- a/crates/brk_computer/src/distribution/compute/recover.rs +++ b/crates/brk_computer/src/distribution/compute/recover.rs @@ -71,20 +71,24 @@ pub fn recover_state( } // Import UTXO cohort states - all must succeed + debug!("importing UTXO cohort states at height {}", consistent_height); if !utxo_cohorts.import_separate_states(consistent_height) { warn!("UTXO cohort state import failed at height {}", consistent_height); return Ok(RecoveredState { starting_height: Height::ZERO, }); } + debug!("UTXO cohort states imported"); // Import address cohort states - all must succeed + debug!("importing address cohort states at height {}", consistent_height); if !address_cohorts.import_separate_states(consistent_height) { warn!("Address cohort state import failed at height {}", consistent_height); return Ok(RecoveredState { starting_height: Height::ZERO, }); } + debug!("address cohort states imported"); Ok(RecoveredState { starting_height: consistent_height, diff --git a/crates/brk_computer/src/distribution/compute/write.rs b/crates/brk_computer/src/distribution/compute/write.rs index 2fde94ec8..f7d0b85e8 100644 --- a/crates/brk_computer/src/distribution/compute/write.rs +++ b/crates/brk_computer/src/distribution/compute/write.rs @@ -66,9 +66,9 @@ pub fn write( let stamp = Stamp::from(height); // Prepare chain_state before parallel write - vecs.chain_state.truncate_if_needed(Height::ZERO)?; + vecs.supply_state.truncate_if_needed(Height::ZERO)?; for block_state in chain_state { - vecs.chain_state.push(block_state.supply.clone()); + vecs.supply_state.push(block_state.supply.clone()); } vecs.any_address_indexes @@ -78,7 +78,7 @@ pub fn write( .chain(vecs.empty_addr_count.par_iter_height_mut()) .chain(vecs.address_activity.par_iter_height_mut()) .chain(rayon::iter::once( - &mut vecs.chain_state as &mut dyn AnyStoredVec, + &mut vecs.supply_state as &mut dyn AnyStoredVec, )) .chain(vecs.utxo_cohorts.par_iter_vecs_mut()) .chain(vecs.address_cohorts.par_iter_vecs_mut()) diff --git a/crates/brk_computer/src/distribution/metrics/activity.rs b/crates/brk_computer/src/distribution/metrics/activity.rs index d0d36614b..a28794607 100644 --- a/crates/brk_computer/src/distribution/metrics/activity.rs +++ b/crates/brk_computer/src/distribution/metrics/activity.rs @@ -6,7 +6,7 @@ use vecdb::{AnyStoredVec, AnyVec, EagerVec, Exit, GenericStoredVec, ImportableVe use crate::{ ComputeIndexes, indexes, - internal::{ComputedFromHeightSumCum, LazyComputedValueFromHeightSumCum}, + internal::{ComputedFromHeightSumCum, LazyComputedValueFromHeightSumCum, ValueFromDateLast}, }; use super::ImportConfig; @@ -17,6 +17,9 @@ pub struct ActivityMetrics { /// Total satoshis sent at each height + derived indexes pub sent: LazyComputedValueFromHeightSumCum, + /// 14-day EMA of sent supply (sats, btc, usd) + pub sent_14d_ema: ValueFromDateLast, + /// Satoshi-blocks destroyed (supply * blocks_old when spent) pub satblocks_destroyed: EagerVec>, @@ -42,6 +45,14 @@ impl ActivityMetrics { cfg.price, )?, + sent_14d_ema: ValueFromDateLast::forced_import( + cfg.db, + &cfg.name("sent_14d_ema"), + cfg.version, + cfg.compute_dollars(), + cfg.indexes, + )?, + satblocks_destroyed: EagerVec::forced_import( cfg.db, &cfg.name("satblocks_destroyed"), @@ -155,6 +166,15 @@ impl ActivityMetrics { ) -> Result<()> { self.sent.compute_rest(indexes, starting_indexes, exit)?; + // 14-day EMA of sent (sats and dollars) + self.sent_14d_ema.compute_ema( + starting_indexes.dateindex, + &self.sent.sats.dateindex.sum.0, + self.sent.dollars.as_ref().map(|d| &d.dateindex.sum.0), + 14, + exit, + )?; + self.coinblocks_destroyed .compute_all(indexes, starting_indexes, exit, |v| { v.compute_transform( diff --git a/crates/brk_computer/src/distribution/metrics/config.rs b/crates/brk_computer/src/distribution/metrics/config.rs index eeae93bd3..9e9236da7 100644 --- a/crates/brk_computer/src/distribution/metrics/config.rs +++ b/crates/brk_computer/src/distribution/metrics/config.rs @@ -1,4 +1,4 @@ -use brk_cohort::{CohortContext, Filter}; +use brk_cohort::{CohortContext, Filter, TimeFilter}; use brk_types::Version; use vecdb::Database; @@ -56,4 +56,24 @@ impl<'a> ImportConfig<'a> { format!("{}_{suffix}", self.full_name) } } + + /// Whether this cohort needs peak_regret metric. + /// True for UTXO cohorts with age-based filters (all, term, time). + /// age_range cohorts compute directly, others aggregate from age_range. + pub fn compute_peak_regret(&self) -> bool { + matches!(self.context, CohortContext::Utxo) + && matches!( + self.filter, + Filter::All | Filter::Term(_) | Filter::Time(_) + ) + } + + /// Whether this is an age_range cohort (UTXO context with Time::Range filter). + /// These cohorts have peak_regret computed directly from chain_state. + pub fn is_age_range(&self) -> bool { + matches!( + (&self.context, &self.filter), + (CohortContext::Utxo, Filter::Time(TimeFilter::Range(_))) + ) + } } diff --git a/crates/brk_computer/src/distribution/metrics/realized.rs b/crates/brk_computer/src/distribution/metrics/realized.rs index d2e0a12d7..8b6ab3717 100644 --- a/crates/brk_computer/src/distribution/metrics/realized.rs +++ b/crates/brk_computer/src/distribution/metrics/realized.rs @@ -17,9 +17,10 @@ use crate::{ internal::{ CentsUnsignedToDollars, ComputedFromDateLast, ComputedFromDateRatio, ComputedFromHeightLast, ComputedFromHeightSum, ComputedFromHeightSumCum, DollarsMinus, - DollarsPlus, LazyBinaryFromHeightSum, LazyBinaryFromHeightSumCum, LazyFromDateLast, - LazyFromHeightLast, LazyFromHeightSum, LazyFromHeightSumCum, LazyPriceFromCents, - PercentageDollarsF32, PriceFromHeight, StoredF32Identity, + DollarsPlus, LazyBinaryFromHeightSum, LazyBinaryFromHeightSumCum, + LazyComputedValueFromHeightSumCum, LazyFromDateLast, LazyFromHeightLast, LazyFromHeightSum, + LazyFromHeightSumCum, LazyPriceFromCents, PercentageDollarsF32, PriceFromHeight, + StoredF32Identity, ValueFromDateLast, }, price, }; @@ -54,9 +55,12 @@ pub struct RealizedMetrics { // === Realized Profit/Loss === pub realized_profit: ComputedFromHeightSumCum, + pub realized_profit_7d_ema: ComputedFromDateLast, pub realized_loss: ComputedFromHeightSumCum, + pub realized_loss_7d_ema: ComputedFromDateLast, pub neg_realized_loss: LazyFromHeightSumCum, pub net_realized_pnl: ComputedFromHeightSumCum, + pub net_realized_pnl_7d_ema: ComputedFromDateLast, pub realized_value: ComputedFromHeightSum, // === Realized vs Realized Cap Ratios (lazy) === @@ -106,10 +110,23 @@ pub struct RealizedMetrics { pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: ComputedFromDateLast, pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: ComputedFromDateLast, - // === ATH Regret === - /// Realized ATH regret: Σ((ath - sell_price) × sats) - /// "How much more could have been made by selling at ATH instead" - pub ath_regret: ComputedFromHeightSumCum, + // === Peak Regret === + /// Realized peak regret: Σ((peak - sell_price) × sats) + /// where peak = max price during holding period. + /// "How much more could have been made by selling at peak instead" + pub peak_regret: ComputedFromHeightSumCum, + /// Peak regret as % of realized cap + pub peak_regret_rel_to_realized_cap: LazyBinaryFromHeightSum, + + // === Sent in Profit/Loss === + /// Sats sent in profit (sats/btc/usd) + pub sent_in_profit: LazyComputedValueFromHeightSumCum, + /// 14-day EMA of sent in profit (sats, btc, usd) + pub sent_in_profit_14d_ema: ValueFromDateLast, + /// Sats sent in loss (sats/btc/usd) + pub sent_in_loss: LazyComputedValueFromHeightSumCum, + /// 14-day EMA of sent in loss (sats, btc, usd) + pub sent_in_loss_14d_ema: ValueFromDateLast, } impl RealizedMetrics { @@ -143,6 +160,13 @@ impl RealizedMetrics { cfg.indexes, )?; + let realized_profit_7d_ema = ComputedFromDateLast::forced_import( + cfg.db, + &cfg.name("realized_profit_7d_ema"), + cfg.version, + cfg.indexes, + )?; + let realized_loss = ComputedFromHeightSumCum::forced_import( cfg.db, &cfg.name("realized_loss"), @@ -150,6 +174,13 @@ impl RealizedMetrics { cfg.indexes, )?; + let realized_loss_7d_ema = ComputedFromDateLast::forced_import( + cfg.db, + &cfg.name("realized_loss_7d_ema"), + cfg.version, + cfg.indexes, + )?; + let neg_realized_loss = LazyFromHeightSumCum::from_computed::( &cfg.name("neg_realized_loss"), cfg.version + v1, @@ -164,6 +195,20 @@ impl RealizedMetrics { cfg.indexes, )?; + let net_realized_pnl_7d_ema = ComputedFromDateLast::forced_import( + cfg.db, + &cfg.name("net_realized_pnl_7d_ema"), + cfg.version, + cfg.indexes, + )?; + + let peak_regret = ComputedFromHeightSumCum::forced_import( + cfg.db, + &cfg.name("realized_peak_regret"), + cfg.version + v2, + cfg.indexes, + )?; + // realized_value is the source for total_realized_pnl (they're identical) let realized_value = ComputedFromHeightSum::forced_import( cfg.db, @@ -360,7 +405,7 @@ impl RealizedMetrics { Ok(Self { // === Realized Cap === realized_cap_cents, - realized_cap, + realized_cap: realized_cap.clone(), realized_price, realized_price_extra, realized_cap_rel_to_own_market_cap: extended @@ -392,9 +437,12 @@ impl RealizedMetrics { // === Realized Profit/Loss === realized_profit, + realized_profit_7d_ema, realized_loss, + realized_loss_7d_ema, neg_realized_loss, net_realized_pnl, + net_realized_pnl_7d_ema, realized_value, // === Realized vs Realized Cap Ratios (lazy) === @@ -508,11 +556,46 @@ impl RealizedMetrics { )?, // === ATH Regret === - // v2: Changed to use max HIGH price during holding period instead of global ATH at send time - ath_regret: ComputedFromHeightSumCum::forced_import( + peak_regret: peak_regret.clone(), + peak_regret_rel_to_realized_cap: LazyBinaryFromHeightSum::from_sumcum_lazy_last::< + PercentageDollarsF32, + _, + >( + &cfg.name("peak_regret_rel_to_realized_cap"), + cfg.version + v1, + peak_regret.height.boxed_clone(), + realized_cap.height.boxed_clone(), + &peak_regret, + &realized_cap, + ), + + // === Sent in Profit/Loss === + sent_in_profit: LazyComputedValueFromHeightSumCum::forced_import( cfg.db, - &cfg.name("realized_ath_regret"), - cfg.version + v2, + &cfg.name("sent_in_profit"), + cfg.version, + cfg.indexes, + cfg.price, + )?, + sent_in_profit_14d_ema: ValueFromDateLast::forced_import( + cfg.db, + &cfg.name("sent_in_profit_14d_ema"), + cfg.version, + cfg.compute_dollars(), + cfg.indexes, + )?, + sent_in_loss: LazyComputedValueFromHeightSumCum::forced_import( + cfg.db, + &cfg.name("sent_in_loss"), + cfg.version, + cfg.indexes, + cfg.price, + )?, + sent_in_loss_14d_ema: ValueFromDateLast::forced_import( + cfg.db, + &cfg.name("sent_in_loss_14d_ema"), + cfg.version, + cfg.compute_dollars(), cfg.indexes, )?, }) @@ -532,7 +615,9 @@ impl RealizedMetrics { .min(self.profit_value_destroyed.height.len()) .min(self.loss_value_created.height.len()) .min(self.loss_value_destroyed.height.len()) - .min(self.ath_regret.height.len()) + .min(self.peak_regret.height.len()) + .min(self.sent_in_profit.sats.height.len()) + .min(self.sent_in_loss.sats.height.len()) } /// Push realized state values to height-indexed vectors. @@ -568,9 +653,19 @@ impl RealizedMetrics { .height .truncate_push(height, state.loss_value_destroyed().to_dollars())?; // ATH regret - self.ath_regret + self.peak_regret .height - .truncate_push(height, state.ath_regret().to_dollars())?; + .truncate_push(height, state.peak_regret().to_dollars())?; + + // Volume at profit/loss + self.sent_in_profit + .sats + .height + .truncate_push(height, state.sent_in_profit())?; + self.sent_in_loss + .sats + .height + .truncate_push(height, state.sent_in_loss())?; Ok(()) } @@ -591,7 +686,10 @@ impl RealizedMetrics { &mut self.loss_value_created.height, &mut self.loss_value_destroyed.height, // ATH regret - &mut self.ath_regret.height, + &mut self.peak_regret.height, + // Sent in profit/loss + &mut self.sent_in_profit.sats.height, + &mut self.sent_in_loss.sats.height, ] .into_par_iter() } @@ -725,11 +823,29 @@ impl RealizedMetrics { exit, )?; // ATH regret - self.ath_regret.height.compute_sum_of_others( + self.peak_regret.height.compute_sum_of_others( starting_indexes.height, &others .iter() - .map(|v| &v.ath_regret.height) + .map(|v| &v.peak_regret.height) + .collect::>(), + exit, + )?; + + // Volume at profit/loss + self.sent_in_profit.sats.height.compute_sum_of_others( + starting_indexes.height, + &others + .iter() + .map(|v| &v.sent_in_profit.sats.height) + .collect::>(), + exit, + )?; + self.sent_in_loss.sats.height.compute_sum_of_others( + starting_indexes.height, + &others + .iter() + .map(|v| &v.sent_in_loss.sats.height) .collect::>(), exit, )?; @@ -790,7 +906,13 @@ impl RealizedMetrics { self.loss_value_destroyed .compute_rest(indexes, starting_indexes, exit)?; // ATH regret - self.ath_regret + self.peak_regret + .compute_rest(indexes, starting_indexes, exit)?; + + // Volume at profit/loss + self.sent_in_profit + .compute_rest(indexes, starting_indexes, exit)?; + self.sent_in_loss .compute_rest(indexes, starting_indexes, exit)?; Ok(()) @@ -856,6 +978,52 @@ impl RealizedMetrics { exit, )?; + // 7d EMA of realized profit/loss + self.realized_profit_7d_ema.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_ema( + starting_indexes.dateindex, + &self.realized_profit.dateindex.sum.0, + 7, + exit, + )?) + })?; + + self.realized_loss_7d_ema.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_ema( + starting_indexes.dateindex, + &self.realized_loss.dateindex.sum.0, + 7, + exit, + )?) + })?; + + self.net_realized_pnl_7d_ema.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_ema( + starting_indexes.dateindex, + &self.net_realized_pnl.dateindex.sum.0, + 7, + exit, + )?) + })?; + + // 14-day EMA of sent in profit (sats and dollars) + self.sent_in_profit_14d_ema.compute_ema( + starting_indexes.dateindex, + &self.sent_in_profit.sats.dateindex.sum.0, + self.sent_in_profit.dollars.as_ref().map(|d| &d.dateindex.sum.0), + 14, + exit, + )?; + + // 14-day EMA of sent in loss (sats and dollars) + self.sent_in_loss_14d_ema.compute_ema( + starting_indexes.dateindex, + &self.sent_in_loss.sats.dateindex.sum.0, + self.sent_in_loss.dollars.as_ref().map(|d| &d.dateindex.sum.0), + 14, + exit, + )?; + self.sopr_7d_ema .compute_ema(starting_indexes.dateindex, &self.sopr, 7, exit)?; diff --git a/crates/brk_computer/src/distribution/metrics/relative.rs b/crates/brk_computer/src/distribution/metrics/relative.rs index e449b8bc8..5590f4345 100644 --- a/crates/brk_computer/src/distribution/metrics/relative.rs +++ b/crates/brk_computer/src/distribution/metrics/relative.rs @@ -1,3 +1,4 @@ +use brk_cohort::Filter; use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Dollars, Sats, StoredF32, StoredF64, Version}; @@ -64,6 +65,10 @@ pub struct RelativeMetrics { Option>, pub invested_capital_in_loss_pct: Option>, + + // === Unrealized Peak Regret Relative to Market Cap (date-only, lazy) === + pub unrealized_peak_regret_rel_to_market_cap: + Option>, } impl RelativeMetrics { @@ -94,6 +99,11 @@ impl RelativeMetrics { // Own market cap source let own_market_cap = supply.total.dollars.as_ref(); + // For "all" cohort, own_market_cap IS the global market cap + let market_cap = global_market_cap.or_else(|| { + matches!(cfg.filter, Filter::All).then_some(own_market_cap).flatten() + }); + Ok(Self { // === Supply Relative to Circulating Supply (lazy from global supply) === supply_rel_to_circulating_supply: (compute_rel_to_all @@ -189,7 +199,7 @@ impl RelativeMetrics { // === Unrealized vs Market Cap (lazy from global market cap) === unrealized_profit_rel_to_market_cap: - global_market_cap.map(|mc| { + market_cap.map(|mc| { LazyBinaryFromHeightLast::from_computed_height_date_and_lazy_binary_block_last::< PercentageDollarsF32, _, @@ -202,7 +212,7 @@ impl RelativeMetrics { ) }), unrealized_loss_rel_to_market_cap: - global_market_cap.map(|mc| { + market_cap.map(|mc| { LazyBinaryFromHeightLast::from_computed_height_date_and_lazy_binary_block_last::< PercentageDollarsF32, _, @@ -214,7 +224,7 @@ impl RelativeMetrics { mc, ) }), - neg_unrealized_loss_rel_to_market_cap: global_market_cap.map(|mc| { + neg_unrealized_loss_rel_to_market_cap: market_cap.map(|mc| { LazyBinaryFromHeightLast::from_computed_height_date_and_lazy_binary_block_last::< NegPercentageDollarsF32, _, @@ -226,7 +236,7 @@ impl RelativeMetrics { mc, ) }), - net_unrealized_pnl_rel_to_market_cap: global_market_cap.map(|mc| { + net_unrealized_pnl_rel_to_market_cap: market_cap.map(|mc| { LazyBinaryFromHeightLast::from_binary_block_and_lazy_binary_block_last::< PercentageDollarsF32, _, @@ -242,7 +252,7 @@ impl RelativeMetrics { }), // NUPL is a proxy for net_unrealized_pnl_rel_to_market_cap - nupl: global_market_cap.map(|mc| { + nupl: market_cap.map(|mc| { LazyBinaryFromHeightLast::from_binary_block_and_lazy_binary_block_last::< PercentageDollarsF32, _, @@ -382,6 +392,21 @@ impl RelativeMetrics { &r.realized_cap, ) }), + + // === Peak Regret Relative to Market Cap (date-only, lazy) === + unrealized_peak_regret_rel_to_market_cap: unrealized + .peak_regret + .as_ref() + .zip(market_cap) + .map(|(pr, mc)| { + LazyBinaryFromDateLast::from_computed_and_derived_last::( + &cfg.name("unrealized_peak_regret_rel_to_market_cap"), + cfg.version, + pr, + mc.rest.dateindex.boxed_clone(), + &mc.rest.dates, + ) + }), }) } } diff --git a/crates/brk_computer/src/distribution/metrics/supply.rs b/crates/brk_computer/src/distribution/metrics/supply.rs index 8062cb3f2..1b96ae8b1 100644 --- a/crates/brk_computer/src/distribution/metrics/supply.rs +++ b/crates/brk_computer/src/distribution/metrics/supply.rs @@ -10,7 +10,7 @@ use crate::{ indexes, internal::{ HalfClosePriceTimesSats, HalveDollars, HalveSats, HalveSatsToBitcoin, - LazyBinaryValueFromHeightLast, ValueFromHeightLast, + LazyBinaryValueFromHeightLast, ValueChangeFromDate, ValueFromHeightLast, }, }; @@ -21,6 +21,8 @@ use super::ImportConfig; pub struct SupplyMetrics { pub total: ValueFromHeightLast, pub halved: LazyBinaryValueFromHeightLast, + /// 30-day change in supply (net position change) - sats, btc, usd + pub _30d_change: ValueChangeFromDate, } impl SupplyMetrics { @@ -41,9 +43,18 @@ impl SupplyMetrics { HalveDollars, >(&cfg.name("supply_halved"), &supply, cfg.price, cfg.version); + let _30d_change = ValueChangeFromDate::forced_import( + cfg.db, + &cfg.name("_30d_change"), + cfg.version, + cfg.compute_dollars(), + cfg.indexes, + )?; + Ok(Self { total: supply, halved: supply_halved, + _30d_change, }) } @@ -94,6 +105,17 @@ impl SupplyMetrics { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.total.compute_rest(indexes, starting_indexes, exit) + self.total.compute_rest(indexes, starting_indexes, exit)?; + + // 30-day change in supply + self._30d_change.compute_change( + starting_indexes.dateindex, + &self.total.sats.dateindex.0, + self.total.dollars.as_ref().map(|d| &d.dateindex.0), + 30, + exit, + )?; + + Ok(()) } } diff --git a/crates/brk_computer/src/distribution/metrics/unrealized.rs b/crates/brk_computer/src/distribution/metrics/unrealized.rs index e79a2feaa..5f780e625 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized.rs @@ -1,10 +1,10 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{CentsSats, CentsSquaredSats, CentsUnsigned, DateIndex, Dollars, Height, Sats}; +use brk_types::{CentsSats, CentsSquaredSats, CentsUnsigned, DateIndex, Dollars, Height}; use rayon::prelude::*; use vecdb::{ AnyStoredVec, AnyVec, BytesVec, Exit, GenericStoredVec, ImportableVec, Negate, - TypedVecIterator, Version, + TypedVecIterator, }; use crate::{ @@ -12,8 +12,8 @@ use crate::{ distribution::state::UnrealizedState, indexes, internal::{ - ComputedFromHeightAndDateLast, ComputedFromHeightLast, DollarsMinus, DollarsPlus, - LazyBinaryFromHeightLast, LazyFromHeightLast, ValueFromHeightAndDateLast, + ComputedFromDateLast, ComputedFromHeightAndDateLast, ComputedFromHeightLast, DollarsMinus, + DollarsPlus, LazyBinaryFromHeightLast, LazyFromHeightLast, ValueFromHeightAndDateLast, }, price, }; @@ -60,10 +60,11 @@ pub struct UnrealizedMetrics { pub net_unrealized_pnl: LazyBinaryFromHeightLast, pub total_unrealized_pnl: LazyBinaryFromHeightLast, - // === ATH Regret === - /// Unrealized ATH regret: (ATH - spot) × supply_in_profit + ATH × supply_in_loss - invested_capital_in_loss - /// "How much more I'd have if I sold at ATH instead of now" (refined formula accounting for cost basis) - pub ath_regret: ComputedFromHeightLast, + // === Peak Regret (age_range cohorts only) === + /// Unrealized peak regret: sum of (peak_price - reference_price) × supply + /// where reference_price = max(spot, cost_basis) and peak = max price during holding period. + /// Only computed for age_range cohorts, then aggregated for overlapping cohorts. + pub peak_regret: Option>, } impl UnrealizedMetrics { @@ -176,16 +177,18 @@ impl UnrealizedMetrics { &unrealized_loss, ); - // === ATH Regret === - // v2: Changed to use HIGH prices consistently for ATH instead of mixing HIGH/CLOSE - // v3: Changed to ComputedFromHeightLast to derive dateindex from height (avoids precision loss) - let v3 = Version::new(3); - let ath_regret = ComputedFromHeightLast::forced_import( - cfg.db, - &cfg.name("unrealized_ath_regret"), - cfg.version + v3, - cfg.indexes, - )?; + // Peak regret: only for age-based UTXO cohorts + let peak_regret = cfg + .compute_peak_regret() + .then(|| { + ComputedFromDateLast::forced_import( + cfg.db, + &cfg.name("unrealized_peak_regret"), + cfg.version, + cfg.indexes, + ) + }) + .transpose()?; Ok(Self { supply_in_profit, @@ -204,7 +207,7 @@ impl UnrealizedMetrics { neg_unrealized_loss, net_unrealized_pnl, total_unrealized_pnl, - ath_regret, + peak_regret, }) } @@ -226,7 +229,8 @@ impl UnrealizedMetrics { /// Get minimum length across dateindex-indexed vectors written in block loop. pub fn min_stateful_dateindex_len(&self) -> usize { - self.supply_in_profit + let mut min = self + .supply_in_profit .indexes .sats_dateindex .len() @@ -234,7 +238,11 @@ impl UnrealizedMetrics { .min(self.unrealized_profit.dateindex.len()) .min(self.unrealized_loss.dateindex.len()) .min(self.invested_capital_in_profit.dateindex.len()) - .min(self.invested_capital_in_loss.dateindex.len()) + .min(self.invested_capital_in_loss.dateindex.len()); + if let Some(pr) = &self.peak_regret { + min = min.min(pr.dateindex.len()); + } + min } /// Push unrealized state values to height-indexed vectors. @@ -311,25 +319,28 @@ impl UnrealizedMetrics { /// Returns a parallel iterator over all vecs for parallel writing. pub fn par_iter_mut(&mut self) -> impl ParallelIterator { - vec![ - &mut self.supply_in_profit.height as &mut dyn AnyStoredVec, - &mut self.supply_in_loss.height as &mut dyn AnyStoredVec, - &mut self.unrealized_profit.height as &mut dyn AnyStoredVec, - &mut self.unrealized_loss.height as &mut dyn AnyStoredVec, - &mut self.invested_capital_in_profit.height as &mut dyn AnyStoredVec, - &mut self.invested_capital_in_loss.height as &mut dyn AnyStoredVec, - &mut self.invested_capital_in_profit_raw as &mut dyn AnyStoredVec, - &mut self.invested_capital_in_loss_raw as &mut dyn AnyStoredVec, - &mut self.investor_cap_in_profit_raw as &mut dyn AnyStoredVec, - &mut self.investor_cap_in_loss_raw as &mut dyn AnyStoredVec, - &mut self.supply_in_profit.indexes.sats_dateindex as &mut dyn AnyStoredVec, - &mut self.supply_in_loss.indexes.sats_dateindex as &mut dyn AnyStoredVec, - &mut self.unrealized_profit.rest.dateindex as &mut dyn AnyStoredVec, - &mut self.unrealized_loss.rest.dateindex as &mut dyn AnyStoredVec, - &mut self.invested_capital_in_profit.rest.dateindex as &mut dyn AnyStoredVec, - &mut self.invested_capital_in_loss.rest.dateindex as &mut dyn AnyStoredVec, - ] - .into_par_iter() + let mut vecs: Vec<&mut dyn AnyStoredVec> = vec![ + &mut self.supply_in_profit.height, + &mut self.supply_in_loss.height, + &mut self.unrealized_profit.height, + &mut self.unrealized_loss.height, + &mut self.invested_capital_in_profit.height, + &mut self.invested_capital_in_loss.height, + &mut self.invested_capital_in_profit_raw, + &mut self.invested_capital_in_loss_raw, + &mut self.investor_cap_in_profit_raw, + &mut self.investor_cap_in_loss_raw, + &mut self.supply_in_profit.indexes.sats_dateindex, + &mut self.supply_in_loss.indexes.sats_dateindex, + &mut self.unrealized_profit.rest.dateindex, + &mut self.unrealized_loss.rest.dateindex, + &mut self.invested_capital_in_profit.rest.dateindex, + &mut self.invested_capital_in_loss.rest.dateindex, + ]; + if let Some(pr) = &mut self.peak_regret { + vecs.push(&mut pr.dateindex); + } + vecs.into_par_iter() } /// Compute aggregate values from separate cohorts. @@ -501,6 +512,22 @@ impl UnrealizedMetrics { .collect::>(), exit, )?; + + // Peak regret aggregation (only if this cohort has peak_regret) + if let Some(pr) = &mut self.peak_regret { + let other_prs: Vec<_> = others.iter().filter_map(|v| v.peak_regret.as_ref()).collect(); + if !other_prs.is_empty() { + pr.dateindex.compute_sum_of_others( + starting_indexes.dateindex, + &other_prs + .iter() + .map(|v| &v.dateindex) + .collect::>(), + exit, + )?; + } + } + Ok(()) } @@ -582,58 +609,6 @@ impl UnrealizedMetrics { )?) })?; - // ATH regret: (ATH - spot) × supply_in_profit + ATH × supply_in_loss - invested_capital_in_loss - // This is the refined formula that accounts for cost basis: - // - For UTXOs in profit: regret = ATH - spot (they could have sold at ATH instead of now) - // - For UTXOs in loss: regret = ATH - cost_basis (they could have sold at ATH instead of holding) - // ath = running max of high prices - - // Height computation - { - // Pre-compute ATH as running max of high prices - let height_ath: Vec = { - let mut ath = CentsUnsigned::ZERO; - price - .cents - .split - .height - .high - .into_iter() - .map(|high| { - if *high > ath { - ath = *high; - } - ath - }) - .collect() - }; - - self.ath_regret.height.compute_transform4( - starting_indexes.height, - &price.cents.split.height.close, - &self.supply_in_profit.height, - &self.supply_in_loss.height, - &self.invested_capital_in_loss_raw, - |(h, spot, supply_profit, supply_loss, invested_loss_raw, ..)| { - let ath = height_ath[usize::from(h)]; - // (ATH - spot) × supply_in_profit + ATH × supply_in_loss - invested_capital_in_loss - let ath_u128 = ath.as_u128(); - let spot_u128 = spot.as_u128(); - let profit_regret = (ath_u128 - spot_u128) * supply_profit.as_u128(); - // invested_loss_raw is CentsSats (already in cents*sats scale) - let loss_regret = ath_u128 * supply_loss.as_u128() - invested_loss_raw.inner(); - let regret_raw = profit_regret + loss_regret; - let regret_cents = CentsUnsigned::new((regret_raw / Sats::ONE_BTC_U128) as u64); - (h, regret_cents.to_dollars()) - }, - exit, - )?; - } - - // DateIndex computation: derive from height values using last-value aggregation - self.ath_regret - .compute_rest(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 b419a6025..c5210937c 100644 --- a/crates/brk_computer/src/distribution/state/cohort/base.rs +++ b/crates/brk_computer/src/distribution/state/cohort/base.rs @@ -237,7 +237,7 @@ impl CohortState { let ath_ps = CentsSats::from_price_sats(ath_price, sats); let prev_investor_cap = prev_ps.to_investor_cap(pp); - realized.send(current_ps, prev_ps, ath_ps, prev_investor_cap); + realized.send(sats, current_ps, prev_ps, ath_ps, prev_investor_cap); self.cost_basis_data.as_mut().unwrap().decrement( pp, @@ -284,7 +284,7 @@ impl CohortState { let ath_ps = CentsSats::from_price_sats(ath, sats); let prev_investor_cap = prev_ps.to_investor_cap(prev_price); - realized.send(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( diff --git a/crates/brk_computer/src/distribution/state/cost_basis/realized.rs b/crates/brk_computer/src/distribution/state/cost_basis/realized.rs index e309cf7ab..346125da0 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/realized.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/realized.rs @@ -23,8 +23,12 @@ pub struct RealizedState { loss_value_created_raw: u128, /// cost_basis × sats for loss cases (= capitulation_flow) loss_value_destroyed_raw: u128, - /// Raw realized ATH regret: Σ((ath - sell_price) × sats) - ath_regret_raw: u128, + /// Raw realized peak regret: Σ((peak - sell_price) × sats) + peak_regret_raw: u128, + /// Sats sent in profit + sent_in_profit: Sats, + /// Sats sent in loss + sent_in_loss: Sats, } impl RealizedState { @@ -137,12 +141,24 @@ impl RealizedState { self.profit_value_destroyed() } - /// Get realized ATH regret as CentsUnsigned. - /// This is Σ((ath - sell_price) × sats) - how much more could have been made - /// by selling at ATH instead of when actually sold. + /// Get realized peak regret as CentsUnsigned. + /// This is Σ((peak - sell_price) × sats) - how much more could have been made + /// by selling at peak instead of when actually sold. #[inline] - pub fn ath_regret(&self) -> CentsUnsigned { - CentsUnsigned::new((self.ath_regret_raw / Sats::ONE_BTC_U128) as u64) + pub fn peak_regret(&self) -> CentsUnsigned { + CentsUnsigned::new((self.peak_regret_raw / Sats::ONE_BTC_U128) as u64) + } + + /// Get sats sent in profit. + #[inline] + pub fn sent_in_profit(&self) -> Sats { + self.sent_in_profit + } + + /// Get sats sent in loss. + #[inline] + pub fn sent_in_loss(&self) -> Sats { + self.sent_in_loss } pub fn reset_single_iteration_values(&mut self) { @@ -152,7 +168,9 @@ impl RealizedState { self.profit_value_destroyed_raw = 0; self.loss_value_created_raw = 0; self.loss_value_destroyed_raw = 0; - self.ath_regret_raw = 0; + self.peak_regret_raw = 0; + self.sent_in_profit = Sats::ZERO; + self.sent_in_loss = Sats::ZERO; } /// Increment using pre-computed values (for UTXO path) @@ -189,6 +207,7 @@ impl RealizedState { #[inline] pub fn send( &mut self, + sats: Sats, current_ps: CentsSats, prev_ps: CentsSats, ath_ps: CentsSats, @@ -199,21 +218,24 @@ impl RealizedState { self.profit_raw += (current_ps - prev_ps).as_u128(); self.profit_value_created_raw += current_ps.as_u128(); self.profit_value_destroyed_raw += prev_ps.as_u128(); + self.sent_in_profit += sats; } Ordering::Less => { self.loss_raw += (prev_ps - current_ps).as_u128(); self.loss_value_created_raw += current_ps.as_u128(); self.loss_value_destroyed_raw += prev_ps.as_u128(); + self.sent_in_loss += sats; } Ordering::Equal => { // Break-even: count as profit side (arbitrary but consistent) self.profit_value_created_raw += current_ps.as_u128(); self.profit_value_destroyed_raw += prev_ps.as_u128(); + self.sent_in_profit += sats; } } - // Track ATH regret: (ath - sell_price) × sats - self.ath_regret_raw += (ath_ps - current_ps).as_u128(); + // Track peak regret: (peak - sell_price) × sats + self.peak_regret_raw += (ath_ps - current_ps).as_u128(); // Inline decrement to avoid recomputation self.cap_raw -= prev_ps.as_u128(); diff --git a/crates/brk_computer/src/distribution/vecs.rs b/crates/brk_computer/src/distribution/vecs.rs index 794195755..2b567761e 100644 --- a/crates/brk_computer/src/distribution/vecs.rs +++ b/crates/brk_computer/src/distribution/vecs.rs @@ -7,7 +7,7 @@ use brk_types::{ DateIndex, EmptyAddressData, EmptyAddressIndex, Height, LoadedAddressData, LoadedAddressIndex, SupplyState, Version, }; -use tracing::info; +use tracing::{debug, info}; use vecdb::{ AnyVec, BytesVec, Database, Exit, GenericStoredVec, ImportableVec, IterableCloneableVec, LazyVecFrom1, PAGE_SIZE, Stamp, TypedVecIterator, VecIndex, @@ -38,7 +38,7 @@ pub struct Vecs { #[traversable(skip)] db: Database, - pub chain_state: BytesVec, + pub supply_state: BytesVec, pub any_address_indexes: AnyAddressIndexesVecs, pub addresses_data: AddressesDataVecs, pub utxo_cohorts: UTXOCohorts, @@ -139,8 +139,8 @@ impl Vecs { GrowthRateVecs::forced_import(&db, version, indexes, &new_addr_count, &addr_count)?; let this = Self { - chain_state: BytesVec::forced_import_with( - vecdb::ImportOptions::new(&db, "chain", version) + supply_state: BytesVec::forced_import_with( + vecdb::ImportOptions::new(&db, "supply_state", version) .with_saved_stamped_changes(SAVED_STAMPED_CHANGES), )?, @@ -197,7 +197,7 @@ impl Vecs { exit: &Exit, ) -> Result<()> { // 1. Find minimum height we have data for across stateful vecs - let current_height = Height::from(self.chain_state.len()); + let current_height = Height::from(self.supply_state.len()); let height_based_min = self.min_stateful_height_len(); let dateindex_min = self.min_stateful_dateindex_len(); let min_stateful = adjust_for_dateindex_gap(height_based_min, dateindex_min, indexes)?; @@ -219,7 +219,7 @@ impl Vecs { let stamp = Stamp::from(height); // Rollback BytesVec state and capture results for validation - let chain_state_rollback = self.chain_state.rollback_before(stamp); + let chain_state_rollback = self.supply_state.rollback_before(stamp); // Validate all rollbacks and imports are consistent let recovered = recover_state( @@ -234,14 +234,20 @@ impl Vecs { if recovered.starting_height.is_zero() { info!("State recovery validation failed, falling back to fresh start"); } + debug!( + "recover_state completed, starting_height={}", + recovered.starting_height + ); recovered.starting_height } StartMode::Fresh => Height::ZERO, }; + debug!("recovered_height={}", recovered_height); + // Fresh start: reset all state let (starting_height, mut chain_state) = if recovered_height.is_zero() { - self.chain_state.reset()?; + self.supply_state.reset()?; self.addr_count.reset_height()?; self.empty_addr_count.reset_height()?; self.address_activity.reset_height()?; @@ -256,13 +262,15 @@ impl Vecs { (Height::ZERO, vec![]) } else { // Recover chain_state from stored values + debug!("recovering chain_state from stored values"); let height_to_timestamp = &blocks.time.timestamp_monotonic; let height_to_price = price.map(|p| &p.cents.split.height.close); let mut height_to_timestamp_iter = height_to_timestamp.into_iter(); let mut height_to_price_iter = height_to_price.map(|v| v.into_iter()); - let mut chain_state_iter = self.chain_state.into_iter(); + let mut chain_state_iter = self.supply_state.into_iter(); + debug!("building supply_state vec for {} heights", recovered_height); let chain_state = (0..recovered_height.to_usize()) .map(|h| { let h = Height::from(h); @@ -274,6 +282,7 @@ impl Vecs { } }) .collect(); + debug!("chain_state vec built"); (recovered_height, chain_state) }; @@ -293,16 +302,23 @@ impl Vecs { } // 2b. Validate computed versions + debug!("validating computed versions"); let base_version = VERSION; self.utxo_cohorts.validate_computed_versions(base_version)?; self.address_cohorts .validate_computed_versions(base_version)?; + debug!("computed versions validated"); // 3. Get last height from indexer let last_height = Height::from(indexer.vecs.blocks.blockhash.len().saturating_sub(1)); + debug!( + "last_height={}, starting_height={}", + last_height, starting_height + ); // 4. Process blocks if starting_height <= last_height { + debug!("calling process_blocks"); process_blocks( self, indexer, @@ -401,7 +417,7 @@ impl Vecs { self.utxo_cohorts .min_separate_stateful_height_len() .min(self.address_cohorts.min_separate_stateful_height_len()) - .min(Height::from(self.chain_state.len())) + .min(Height::from(self.supply_state.len())) .min(self.any_address_indexes.min_stamped_height()) .min(self.addresses_data.min_stamped_height()) .min(Height::from(self.addr_count.min_stateful_height())) diff --git a/crates/brk_computer/src/internal/multi/from_date/binary_last.rs b/crates/brk_computer/src/internal/multi/from_date/binary_last.rs index 62df62ef9..f37834081 100644 --- a/crates/brk_computer/src/internal/multi/from_date/binary_last.rs +++ b/crates/brk_computer/src/internal/multi/from_date/binary_last.rs @@ -832,4 +832,41 @@ where decadeindex: period!(decadeindex), } } + + /// Create from a ComputedFromDateLast and a LazyDateDerivedLast. + pub fn from_computed_and_derived_last>( + name: &str, + version: Version, + source1: &ComputedFromDateLast, + dateindex_source2: IterableBoxedVec, + source2: &LazyDateDerivedLast, + ) -> Self { + let v = version + VERSION; + + macro_rules! period { + ($p:ident) => { + LazyBinaryTransformLast::from_lazy_last::( + name, + v, + &source1.$p, + &source2.$p, + ) + }; + } + + Self { + dateindex: LazyVecFrom2::transformed::( + name, + v, + source1.dateindex.boxed_clone(), + dateindex_source2, + ), + weekindex: period!(weekindex), + monthindex: period!(monthindex), + quarterindex: period!(quarterindex), + semesterindex: period!(semesterindex), + yearindex: period!(yearindex), + decadeindex: period!(decadeindex), + } + } } diff --git a/crates/brk_computer/src/internal/multi/from_date/binary_sum.rs b/crates/brk_computer/src/internal/multi/from_date/binary_sum.rs index ee7c951c8..767ff933d 100644 --- a/crates/brk_computer/src/internal/multi/from_date/binary_sum.rs +++ b/crates/brk_computer/src/internal/multi/from_date/binary_sum.rs @@ -7,7 +7,10 @@ use brk_types::{ use schemars::JsonSchema; use vecdb::{BinaryTransform, IterableCloneableVec}; -use crate::internal::{ComputedVecValue, ComputedHeightDerivedSum, LazyBinaryTransformSum, NumericValue}; +use crate::internal::{ + ComputedFromHeightSumCum, ComputedHeightDerivedSum, ComputedVecValue, LazyBinaryTransformSum, + LazyFromHeightLast, NumericValue, +}; const VERSION: Version = Version::ZERO; @@ -91,4 +94,41 @@ where decadeindex: period!(decadeindex), } } + + /// Create from a SumCum source (using only sum) and a LazyLast source. + pub fn from_sumcum_lazy_last( + name: &str, + version: Version, + source1: &ComputedFromHeightSumCum, + source2: &LazyFromHeightLast, + ) -> Self + where + F: BinaryTransform, + S2ST: ComputedVecValue + JsonSchema, + { + let v = version + VERSION; + + // source1 has SumCum pattern with .dateindex.sum, .weekindex.sum, etc. + // source2 has Last pattern via deref chain: .dates.dateindex, .dates.weekindex, etc. + macro_rules! period { + ($p:ident) => { + LazyBinaryTransformSum::from_boxed::( + name, + v, + source1.$p.sum.boxed_clone(), + source2.dates.$p.boxed_clone(), + ) + }; + } + + Self { + dateindex: period!(dateindex), + weekindex: period!(weekindex), + monthindex: period!(monthindex), + quarterindex: period!(quarterindex), + semesterindex: period!(semesterindex), + yearindex: period!(yearindex), + decadeindex: period!(decadeindex), + } + } } diff --git a/crates/brk_computer/src/internal/multi/from_date/mod.rs b/crates/brk_computer/src/internal/multi/from_date/mod.rs index 24c0a8406..e936df028 100644 --- a/crates/brk_computer/src/internal/multi/from_date/mod.rs +++ b/crates/brk_computer/src/internal/multi/from_date/mod.rs @@ -19,6 +19,8 @@ mod price; mod ratio; mod stddev; mod unary_last; +mod value_change; +mod value_change_derived; mod value_derived_last; mod value_last; mod value_lazy_last; @@ -44,6 +46,8 @@ pub use price::*; pub use ratio::*; pub use stddev::*; pub use unary_last::*; +pub use value_change::*; +pub use value_change_derived::*; pub use value_derived_last::*; pub use value_last::*; pub use value_lazy_last::*; diff --git a/crates/brk_computer/src/internal/multi/from_date/value_change.rs b/crates/brk_computer/src/internal/multi/from_date/value_change.rs new file mode 100644 index 000000000..ec56374dc --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_date/value_change.rs @@ -0,0 +1,77 @@ +//! Change values from DateIndex - stores signed sats (changes can be negative). + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Dollars, Sats, SatsSigned, Version}; +use vecdb::{CollectableVec, Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes, price}; + +use super::LazyValueChangeDateDerived; + +const VERSION: Version = Version::ZERO; + +/// Change values indexed by date - uses signed sats since changes can be negative. +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct ValueChangeFromDate { + #[traversable(rename = "sats")] + pub sats: EagerVec>, + #[traversable(flatten)] + pub rest: LazyValueChangeDateDerived, +} + +impl ValueChangeFromDate { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + compute_dollars: bool, + indexes: &indexes::Vecs, + ) -> Result { + let sats = EagerVec::forced_import(db, name, version + VERSION)?; + + let rest = LazyValueChangeDateDerived::from_source( + db, + name, + sats.boxed_clone(), + version + VERSION, + compute_dollars, + indexes, + )?; + + Ok(Self { sats, rest }) + } + + /// Compute N-day change from unsigned sats source and optional dollars source. + pub fn compute_change( + &mut self, + starting_dateindex: DateIndex, + sats_source: &impl CollectableVec, + dollars_source: Option<&impl CollectableVec>, + period: usize, + exit: &Exit, + ) -> Result<()> { + self.sats + .compute_change(starting_dateindex, sats_source, period, exit)?; + + if let (Some(dollars), Some(source)) = (self.rest.dollars.as_mut(), dollars_source) { + dollars + .dateindex + .compute_change(starting_dateindex, source, period, exit)?; + } + + Ok(()) + } + + /// Compute dollars from price after sats change is computed. + pub fn compute_dollars_from_price( + &mut self, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + ) -> Result<()> { + self.rest + .compute_dollars_from_price(price, starting_indexes, exit) + } +} diff --git a/crates/brk_computer/src/internal/multi/from_date/value_change_derived.rs b/crates/brk_computer/src/internal/multi/from_date/value_change_derived.rs new file mode 100644 index 000000000..f3c880000 --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_date/value_change_derived.rs @@ -0,0 +1,84 @@ +//! Lazy derived values for change (bitcoin from sats, period aggregations). + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, DateIndex, Dollars, SatsSigned, Version}; +use vecdb::{Database, Exit, IterableBoxedVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedFromDateLast, LazyDateDerivedLast, LazyFromDateLast, SatsSignedToBitcoin}, + price, + traits::ComputeFromBitcoin, + utils::OptionExt, +}; + +const VERSION: Version = Version::ZERO; + +/// Lazy derived values for change (bitcoin from sats, period aggregations). +#[derive(Clone, Traversable)] +pub struct LazyValueChangeDateDerived { + pub sats: LazyDateDerivedLast, + pub bitcoin: LazyFromDateLast, + pub dollars: Option>, +} + +impl LazyValueChangeDateDerived { + pub fn from_source( + db: &Database, + name: &str, + source: IterableBoxedVec, + version: Version, + compute_dollars: bool, + indexes: &indexes::Vecs, + ) -> Result { + let sats = + LazyDateDerivedLast::from_source(name, version + VERSION, source.clone(), indexes); + + let bitcoin = LazyFromDateLast::from_derived::( + &format!("{name}_btc"), + version + VERSION, + source, + &sats, + ); + + let dollars = compute_dollars + .then(|| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_usd"), + version + VERSION, + indexes, + ) + }) + .transpose()?; + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn compute_dollars_from_price( + &mut self, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + ) -> Result<()> { + if let Some(dollars) = self.dollars.as_mut() { + let dateindex_to_bitcoin = &*self.bitcoin.dateindex; + let dateindex_to_price_close = &price.u().usd.split.close.dateindex; + + dollars.compute_all(starting_indexes, exit, |v| { + v.compute_from_bitcoin( + starting_indexes.dateindex, + dateindex_to_bitcoin, + dateindex_to_price_close, + exit, + ) + })?; + } + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/multi/from_date/value_last.rs b/crates/brk_computer/src/internal/multi/from_date/value_last.rs index 17c609ffa..c2ee55ca6 100644 --- a/crates/brk_computer/src/internal/multi/from_date/value_last.rs +++ b/crates/brk_computer/src/internal/multi/from_date/value_last.rs @@ -2,13 +2,13 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{DateIndex, Sats, Version}; +use brk_types::{DateIndex, Dollars, Sats, Version}; use derive_more::{Deref, DerefMut}; -use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; +use vecdb::{CollectableVec, Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; use crate::{ComputeIndexes, indexes, price}; -use super::LazyValueDateDerivedLast; +use super::{ComputedFromDateLast, LazyValueDateDerivedLast}; #[derive(Clone, Deref, DerefMut, Traversable)] #[traversable(merge)] @@ -70,7 +70,7 @@ impl ValueFromDateLast { pub fn compute_dollars(&mut self, compute: F) -> Result<()> where - F: FnMut(&mut crate::internal::ComputedFromDateLast) -> Result<()>, + F: FnMut(&mut ComputedFromDateLast) -> Result<()>, { self.rest.compute_dollars(compute) } @@ -84,4 +84,63 @@ impl ValueFromDateLast { self.rest .compute_dollars_from_price(price, starting_indexes, exit) } + + /// Compute both sats and dollars using provided closures. + pub fn compute_both( + &mut self, + compute_sats: S, + compute_dollars: D, + ) -> Result<()> + where + S: FnOnce(&mut EagerVec>) -> Result<()>, + D: FnOnce(&mut ComputedFromDateLast) -> Result<()>, + { + compute_sats(&mut self.sats_dateindex)?; + if let Some(dollars) = self.rest.dollars.as_mut() { + compute_dollars(dollars)?; + } + Ok(()) + } + + /// Compute EMA for sats and optionally dollars from source vecs. + pub fn compute_ema( + &mut self, + starting_dateindex: DateIndex, + sats_source: &impl CollectableVec, + dollars_source: Option<&impl CollectableVec>, + period: usize, + exit: &Exit, + ) -> Result<()> { + self.sats_dateindex + .compute_ema(starting_dateindex, sats_source, period, exit)?; + + if let (Some(dollars), Some(source)) = (self.rest.dollars.as_mut(), dollars_source) { + dollars + .dateindex + .compute_ema(starting_dateindex, source, period, exit)?; + } + + Ok(()) + } + + /// Compute N-day change for sats and optionally dollars from source vecs. + pub fn compute_change( + &mut self, + starting_dateindex: DateIndex, + sats_source: &impl CollectableVec, + dollars_source: Option<&impl CollectableVec>, + period: usize, + exit: &Exit, + ) -> Result<()> { + self.sats_dateindex + .compute_change(starting_dateindex, sats_source, period, exit)?; + + if let (Some(dollars), Some(source)) = (self.rest.dollars.as_mut(), dollars_source) { + dollars + .dateindex + .compute_change(starting_dateindex, source, period, exit)?; + } + + Ok(()) + } } diff --git a/crates/brk_computer/src/internal/multi/from_height/binary_sum.rs b/crates/brk_computer/src/internal/multi/from_height/binary_sum.rs index 38a84203b..d6e7214b5 100644 --- a/crates/brk_computer/src/internal/multi/from_height/binary_sum.rs +++ b/crates/brk_computer/src/internal/multi/from_height/binary_sum.rs @@ -7,8 +7,8 @@ use schemars::JsonSchema; use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2}; use crate::internal::{ - ComputedFromHeightSum, ComputedHeightDerivedSum, ComputedVecValue, LazyBinaryHeightDerivedSum, - NumericValue, + ComputedFromHeightSum, ComputedFromHeightSumCum, ComputedHeightDerivedSum, ComputedVecValue, + LazyBinaryHeightDerivedSum, LazyFromHeightLast, NumericValue, }; const VERSION: Version = Version::ZERO; @@ -100,4 +100,31 @@ where ), } } + + /// Create from a SumCum source (using only sum) and a LazyLast source. + /// Produces sum-only output (no cumulative). + pub fn from_sumcum_lazy_last( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &ComputedFromHeightSumCum, + source2: &LazyFromHeightLast, + ) -> Self + where + F: BinaryTransform, + S2ST: ComputedVecValue + JsonSchema, + { + let v = version + VERSION; + + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyBinaryHeightDerivedSum::from_sumcum_lazy_last::( + name, + v, + source1, + source2, + ), + } + } } diff --git a/crates/brk_computer/src/internal/multi/height_derived/binary_sum.rs b/crates/brk_computer/src/internal/multi/height_derived/binary_sum.rs index 58381aaa3..057c1b1d9 100644 --- a/crates/brk_computer/src/internal/multi/height_derived/binary_sum.rs +++ b/crates/brk_computer/src/internal/multi/height_derived/binary_sum.rs @@ -6,7 +6,10 @@ use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use vecdb::{BinaryTransform, IterableCloneableVec}; -use crate::internal::{ComputedVecValue, ComputedHeightDerivedSum, LazyBinaryFromDateSum, LazyBinaryTransformSum, NumericValue}; +use crate::internal::{ + ComputedFromHeightSumCum, ComputedHeightDerivedSum, ComputedVecValue, LazyBinaryFromDateSum, + LazyBinaryTransformSum, LazyFromHeightLast, NumericValue, +}; const VERSION: Version = Version::ZERO; @@ -80,4 +83,33 @@ where ), } } + + /// Create from a SumCum source (using only sum) and a LazyLast source. + pub fn from_sumcum_lazy_last( + name: &str, + version: Version, + source1: &ComputedFromHeightSumCum, + source2: &LazyFromHeightLast, + ) -> Self + where + F: BinaryTransform, + S2ST: ComputedVecValue + JsonSchema, + { + let v = version + VERSION; + + Self { + dates: LazyBinaryFromDateSum::from_sumcum_lazy_last::( + name, + v, + source1, + source2, + ), + difficultyepoch: LazyBinaryTransformSum::from_boxed::( + name, + v, + source1.difficultyepoch.sum.boxed_clone(), + source2.difficultyepoch.boxed_clone(), + ), + } + } } diff --git a/crates/brk_computer/src/internal/single/transform/sat_to_bitcoin.rs b/crates/brk_computer/src/internal/single/transform/sat_to_bitcoin.rs index f3cfe4bb7..2509913b5 100644 --- a/crates/brk_computer/src/internal/single/transform/sat_to_bitcoin.rs +++ b/crates/brk_computer/src/internal/single/transform/sat_to_bitcoin.rs @@ -1,4 +1,4 @@ -use brk_types::{Bitcoin, Sats}; +use brk_types::{Bitcoin, Sats, SatsSigned}; use vecdb::UnaryTransform; /// Sats -> Bitcoin (divide by 1e8) @@ -10,3 +10,13 @@ impl UnaryTransform for SatsToBitcoin { Bitcoin::from(sats) } } + +/// SatsSigned -> Bitcoin (divide by 1e8, preserves sign) +pub struct SatsSignedToBitcoin; + +impl UnaryTransform for SatsSignedToBitcoin { + #[inline(always)] + fn apply(sats: SatsSigned) -> Bitcoin { + Bitcoin::from(sats) + } +} diff --git a/crates/brk_types/src/lib.rs b/crates/brk_types/src/lib.rs index 7184d60ac..2a02dcb13 100644 --- a/crates/brk_types/src/lib.rs +++ b/crates/brk_types/src/lib.rs @@ -130,6 +130,7 @@ mod rawlocktime; mod recommendedfees; mod rewardstats; mod sats; +mod sats_signed; mod satsfract; mod semesterindex; mod stored_bool; @@ -305,6 +306,7 @@ pub use rawlocktime::*; pub use recommendedfees::*; pub use rewardstats::*; pub use sats::*; +pub use sats_signed::*; pub use satsfract::*; pub use semesterindex::*; pub use stored_bool::*; diff --git a/crates/brk_types/src/sats.rs b/crates/brk_types/src/sats.rs index 258b8cbca..1edd78ecf 100644 --- a/crates/brk_types/src/sats.rs +++ b/crates/brk_types/src/sats.rs @@ -268,6 +268,20 @@ impl From for Sats { } } +impl From for Sats { + #[inline] + fn from(value: f32) -> Self { + Self(value.round() as u64) + } +} + +impl From for f32 { + #[inline] + fn from(value: Sats) -> Self { + value.0 as f32 + } +} + impl From for Sats { #[inline] fn from(value: f64) -> Self { diff --git a/crates/brk_types/src/sats_signed.rs b/crates/brk_types/src/sats_signed.rs new file mode 100644 index 000000000..4a4ddb59b --- /dev/null +++ b/crates/brk_types/src/sats_signed.rs @@ -0,0 +1,220 @@ +use std::{ + iter::Sum, + ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}, +}; + +use derive_more::Deref; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use vecdb::{CheckedSub, Formattable, Pco}; + +use super::{Bitcoin, Sats}; + +/// Signed satoshis (i64) - for values that can be negative. +/// Used for changes, deltas, profit/loss calculations, etc. +#[derive( + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Clone, + Copy, + Deref, + Default, + Serialize, + Deserialize, + Pco, + JsonSchema, +)] +pub struct SatsSigned(i64); + +impl SatsSigned { + pub const ZERO: Self = Self(0); + + #[inline] + pub const fn new(value: i64) -> Self { + Self(value) + } + + #[inline] + pub const fn inner(self) -> i64 { + self.0 + } + + #[inline] + pub fn is_zero(&self) -> bool { + self.0 == 0 + } + + #[inline] + pub fn is_negative(&self) -> bool { + self.0 < 0 + } + + #[inline] + pub fn is_positive(&self) -> bool { + self.0 > 0 + } + + #[inline] + pub fn abs(self) -> Self { + Self(self.0.abs()) + } +} + +impl Add for SatsSigned { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for SatsSigned { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl AddAssign for SatsSigned { + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0; + } +} + +impl SubAssign for SatsSigned { + fn sub_assign(&mut self, rhs: Self) { + self.0 -= rhs.0; + } +} + +impl Neg for SatsSigned { + type Output = Self; + fn neg(self) -> Self::Output { + Self(-self.0) + } +} + +impl CheckedSub for SatsSigned { + fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } +} + +impl Mul for SatsSigned { + type Output = Self; + fn mul(self, rhs: i64) -> Self::Output { + Self(self.0.checked_mul(rhs).expect("SatsSigned overflow")) + } +} + +impl Mul for SatsSigned { + type Output = Self; + fn mul(self, rhs: usize) -> Self::Output { + Self(self.0.checked_mul(rhs as i64).expect("SatsSigned overflow")) + } +} + +impl Div for SatsSigned { + type Output = Self; + fn div(self, rhs: usize) -> Self::Output { + if rhs == 0 { + Self::ZERO + } else { + Self(self.0 / rhs as i64) + } + } +} + +impl Sum for SatsSigned { + fn sum>(iter: I) -> Self { + let sats: i64 = iter.map(|s| s.0).sum(); + Self(sats) + } +} + +impl From for SatsSigned { + #[inline] + fn from(value: i64) -> Self { + Self(value) + } +} + +impl From for i64 { + #[inline] + fn from(value: SatsSigned) -> Self { + value.0 + } +} + +impl From for SatsSigned { + #[inline] + fn from(value: usize) -> Self { + Self(value as i64) + } +} + +impl From for SatsSigned { + #[inline] + fn from(value: f32) -> Self { + Self(value.round() as i64) + } +} + +impl From for f32 { + #[inline] + fn from(value: SatsSigned) -> Self { + value.0 as f32 + } +} + +impl From for SatsSigned { + #[inline] + fn from(value: f64) -> Self { + Self(value.round() as i64) + } +} + +impl From for f64 { + #[inline] + fn from(value: SatsSigned) -> Self { + value.0 as f64 + } +} + +impl From for SatsSigned { + #[inline] + fn from(value: Sats) -> Self { + Self(*value as i64) + } +} + +impl From for SatsSigned { + #[inline] + fn from(value: Bitcoin) -> Self { + Self::from(Sats::from(value)) + } +} + +impl From for Bitcoin { + #[inline] + fn from(value: SatsSigned) -> Self { + Self::from(value.0 as f64 / Sats::ONE_BTC_U64 as f64) + } +} + +impl std::fmt::Display for SatsSigned { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut buf = itoa::Buffer::new(); + let str = buf.format(self.0); + f.write_str(str) + } +} + +impl Formattable for SatsSigned { + #[inline(always)] + fn may_need_escaping() -> bool { + false + } +} diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 59b18c833..43605644d 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -625,6 +625,12 @@ * * @typedef {number} SatsFract */ +/** + * Signed satoshis (i64) - for values that can be negative. + * Used for changes, deltas, profit/loss calculations, etc. + * + * @typedef {number} SatsSigned + */ /** @typedef {number} SemesterIndex */ /** * Fixed-size boolean value optimized for on-disk storage (stored as u8) @@ -1369,13 +1375,12 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } // Reusable structural pattern factories /** - * @typedef {Object} AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern + * @typedef {Object} AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern * @property {MetricPattern6} adjustedSopr * @property {MetricPattern6} adjustedSopr30dEma * @property {MetricPattern6} adjustedSopr7dEma * @property {MetricPattern1} adjustedValueCreated * @property {MetricPattern1} adjustedValueDestroyed - * @property {CumulativeSumPattern} athRegret * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow * @property {MetricPattern11} investorCapRaw @@ -1387,10 +1392,13 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } * @property {MetricPattern4} mvrv * @property {CumulativeSumPattern2} negRealizedLoss * @property {CumulativeSumPattern} netRealizedPnl + * @property {MetricPattern4} netRealizedPnl7dEma * @property {MetricPattern4} netRealizedPnlCumulative30dDelta * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap * @property {CumulativeSumPattern} netRealizedPnlRelToRealizedCap + * @property {CumulativeSumPattern} peakRegret + * @property {MetricPattern1} peakRegretRelToRealizedCap * @property {MetricPattern1} profitFlow * @property {MetricPattern1} profitValueCreated * @property {MetricPattern1} profitValueDestroyed @@ -1399,16 +1407,22 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } * @property {MetricPattern1} realizedCapCents * @property {MetricPattern1} realizedCapRelToOwnMarketCap * @property {CumulativeSumPattern} realizedLoss + * @property {MetricPattern4} realizedLoss7dEma * @property {CumulativeSumPattern} realizedLossRelToRealizedCap * @property {DollarsSatsPattern} realizedPrice * @property {RatioPattern} realizedPriceExtra * @property {CumulativeSumPattern} realizedProfit + * @property {MetricPattern4} realizedProfit7dEma * @property {CumulativeSumPattern} realizedProfitRelToRealizedCap * @property {MetricPattern6} realizedProfitToLossRatio * @property {MetricPattern1} realizedValue * @property {MetricPattern6} sellSideRiskRatio * @property {MetricPattern6} sellSideRiskRatio30dEma * @property {MetricPattern6} sellSideRiskRatio7dEma + * @property {BitcoinDollarsSatsPattern3} sentInLoss + * @property {BitcoinDollarsSatsPattern5} sentInLoss14dEma + * @property {BitcoinDollarsSatsPattern3} sentInProfit + * @property {BitcoinDollarsSatsPattern5} sentInProfit14dEma * @property {MetricPattern6} sopr * @property {MetricPattern6} sopr30dEma * @property {MetricPattern6} sopr7dEma @@ -1418,19 +1432,18 @@ function createMetricPattern32(client, name) { return _mp(client, name, _i32); } */ /** - * Create a AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern pattern node + * Create a AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} + * @returns {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} */ -function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc) { +function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) { return { adjustedSopr: createMetricPattern6(client, _m(acc, 'adjusted_sopr')), adjustedSopr30dEma: createMetricPattern6(client, _m(acc, 'adjusted_sopr_30d_ema')), adjustedSopr7dEma: createMetricPattern6(client, _m(acc, 'adjusted_sopr_7d_ema')), adjustedValueCreated: createMetricPattern1(client, _m(acc, 'adjusted_value_created')), adjustedValueDestroyed: createMetricPattern1(client, _m(acc, 'adjusted_value_destroyed')), - athRegret: createCumulativeSumPattern(client, _m(acc, 'realized_ath_regret')), capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), @@ -1442,10 +1455,13 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), negRealizedLoss: createCumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl')), + netRealizedPnl7dEma: createMetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')), netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), netRealizedPnlRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + peakRegret: createCumulativeSumPattern(client, _m(acc, 'realized_peak_regret')), + peakRegretRelToRealizedCap: createMetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')), profitFlow: createMetricPattern1(client, _m(acc, 'profit_flow')), profitValueCreated: createMetricPattern1(client, _m(acc, 'profit_value_created')), profitValueDestroyed: createMetricPattern1(client, _m(acc, 'profit_value_destroyed')), @@ -1454,16 +1470,22 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel realizedCapCents: createMetricPattern1(client, _m(acc, 'realized_cap_cents')), realizedCapRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')), realizedLoss: createCumulativeSumPattern(client, _m(acc, 'realized_loss')), + realizedLoss7dEma: createMetricPattern4(client, _m(acc, 'realized_loss_7d_ema')), realizedLossRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createDollarsSatsPattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createRatioPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createCumulativeSumPattern(client, _m(acc, 'realized_profit')), + realizedProfit7dEma: createMetricPattern4(client, _m(acc, 'realized_profit_7d_ema')), realizedProfitRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), realizedProfitToLossRatio: createMetricPattern6(client, _m(acc, 'realized_profit_to_loss_ratio')), realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), sellSideRiskRatio: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio')), sellSideRiskRatio30dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), sellSideRiskRatio7dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sentInLoss: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')), + sentInLoss14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')), + sentInProfit: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')), + sentInProfit14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')), sopr: createMetricPattern6(client, _m(acc, 'sopr')), sopr30dEma: createMetricPattern6(client, _m(acc, 'sopr_30d_ema')), sopr7dEma: createMetricPattern6(client, _m(acc, 'sopr_7d_ema')), @@ -1474,13 +1496,12 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel } /** - * @typedef {Object} AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 + * @typedef {Object} AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 * @property {MetricPattern6} adjustedSopr * @property {MetricPattern6} adjustedSopr30dEma * @property {MetricPattern6} adjustedSopr7dEma * @property {MetricPattern1} adjustedValueCreated * @property {MetricPattern1} adjustedValueDestroyed - * @property {CumulativeSumPattern} athRegret * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow * @property {MetricPattern11} investorCapRaw @@ -1492,10 +1513,13 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel * @property {MetricPattern4} mvrv * @property {CumulativeSumPattern2} negRealizedLoss * @property {CumulativeSumPattern} netRealizedPnl + * @property {MetricPattern4} netRealizedPnl7dEma * @property {MetricPattern4} netRealizedPnlCumulative30dDelta * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap * @property {CumulativeSumPattern} netRealizedPnlRelToRealizedCap + * @property {CumulativeSumPattern} peakRegret + * @property {MetricPattern1} peakRegretRelToRealizedCap * @property {MetricPattern1} profitFlow * @property {MetricPattern1} profitValueCreated * @property {MetricPattern1} profitValueDestroyed @@ -1503,15 +1527,21 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel * @property {MetricPattern4} realizedCap30dDelta * @property {MetricPattern1} realizedCapCents * @property {CumulativeSumPattern} realizedLoss + * @property {MetricPattern4} realizedLoss7dEma * @property {CumulativeSumPattern} realizedLossRelToRealizedCap * @property {DollarsSatsPattern} realizedPrice * @property {RatioPattern2} realizedPriceExtra * @property {CumulativeSumPattern} realizedProfit + * @property {MetricPattern4} realizedProfit7dEma * @property {CumulativeSumPattern} realizedProfitRelToRealizedCap * @property {MetricPattern1} realizedValue * @property {MetricPattern6} sellSideRiskRatio * @property {MetricPattern6} sellSideRiskRatio30dEma * @property {MetricPattern6} sellSideRiskRatio7dEma + * @property {BitcoinDollarsSatsPattern3} sentInLoss + * @property {BitcoinDollarsSatsPattern5} sentInLoss14dEma + * @property {BitcoinDollarsSatsPattern3} sentInProfit + * @property {BitcoinDollarsSatsPattern5} sentInProfit14dEma * @property {MetricPattern6} sopr * @property {MetricPattern6} sopr30dEma * @property {MetricPattern6} sopr7dEma @@ -1521,19 +1551,18 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel */ /** - * Create a AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 pattern node + * Create a AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} + * @returns {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} */ -function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, acc) { +function createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) { return { adjustedSopr: createMetricPattern6(client, _m(acc, 'adjusted_sopr')), adjustedSopr30dEma: createMetricPattern6(client, _m(acc, 'adjusted_sopr_30d_ema')), adjustedSopr7dEma: createMetricPattern6(client, _m(acc, 'adjusted_sopr_7d_ema')), adjustedValueCreated: createMetricPattern1(client, _m(acc, 'adjusted_value_created')), adjustedValueDestroyed: createMetricPattern1(client, _m(acc, 'adjusted_value_destroyed')), - athRegret: createCumulativeSumPattern(client, _m(acc, 'realized_ath_regret')), capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), @@ -1545,10 +1574,13 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), negRealizedLoss: createCumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl')), + netRealizedPnl7dEma: createMetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')), netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), netRealizedPnlRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + peakRegret: createCumulativeSumPattern(client, _m(acc, 'realized_peak_regret')), + peakRegretRelToRealizedCap: createMetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')), profitFlow: createMetricPattern1(client, _m(acc, 'profit_flow')), profitValueCreated: createMetricPattern1(client, _m(acc, 'profit_value_created')), profitValueDestroyed: createMetricPattern1(client, _m(acc, 'profit_value_destroyed')), @@ -1556,15 +1588,21 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), realizedCapCents: createMetricPattern1(client, _m(acc, 'realized_cap_cents')), realizedLoss: createCumulativeSumPattern(client, _m(acc, 'realized_loss')), + realizedLoss7dEma: createMetricPattern4(client, _m(acc, 'realized_loss_7d_ema')), realizedLossRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createDollarsSatsPattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createRatioPattern2(client, _m(acc, 'realized_price_ratio')), realizedProfit: createCumulativeSumPattern(client, _m(acc, 'realized_profit')), + realizedProfit7dEma: createMetricPattern4(client, _m(acc, 'realized_profit_7d_ema')), realizedProfitRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), sellSideRiskRatio: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio')), sellSideRiskRatio30dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), sellSideRiskRatio7dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sentInLoss: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')), + sentInLoss14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')), + sentInProfit: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')), + sentInProfit14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')), sopr: createMetricPattern6(client, _m(acc, 'sopr')), sopr30dEma: createMetricPattern6(client, _m(acc, 'sopr_30d_ema')), sopr7dEma: createMetricPattern6(client, _m(acc, 'sopr_7d_ema')), @@ -1575,8 +1613,7 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel } /** - * @typedef {Object} AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 - * @property {CumulativeSumPattern} athRegret + * @typedef {Object} CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow * @property {MetricPattern11} investorCapRaw @@ -1588,10 +1625,13 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel * @property {MetricPattern4} mvrv * @property {CumulativeSumPattern2} negRealizedLoss * @property {CumulativeSumPattern} netRealizedPnl + * @property {MetricPattern4} netRealizedPnl7dEma * @property {MetricPattern4} netRealizedPnlCumulative30dDelta * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap * @property {CumulativeSumPattern} netRealizedPnlRelToRealizedCap + * @property {CumulativeSumPattern} peakRegret + * @property {MetricPattern1} peakRegretRelToRealizedCap * @property {MetricPattern1} profitFlow * @property {MetricPattern1} profitValueCreated * @property {MetricPattern1} profitValueDestroyed @@ -1600,16 +1640,22 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel * @property {MetricPattern1} realizedCapCents * @property {MetricPattern1} realizedCapRelToOwnMarketCap * @property {CumulativeSumPattern} realizedLoss + * @property {MetricPattern4} realizedLoss7dEma * @property {CumulativeSumPattern} realizedLossRelToRealizedCap * @property {DollarsSatsPattern} realizedPrice * @property {RatioPattern} realizedPriceExtra * @property {CumulativeSumPattern} realizedProfit + * @property {MetricPattern4} realizedProfit7dEma * @property {CumulativeSumPattern} realizedProfitRelToRealizedCap * @property {MetricPattern6} realizedProfitToLossRatio * @property {MetricPattern1} realizedValue * @property {MetricPattern6} sellSideRiskRatio * @property {MetricPattern6} sellSideRiskRatio30dEma * @property {MetricPattern6} sellSideRiskRatio7dEma + * @property {BitcoinDollarsSatsPattern3} sentInLoss + * @property {BitcoinDollarsSatsPattern5} sentInLoss14dEma + * @property {BitcoinDollarsSatsPattern3} sentInProfit + * @property {BitcoinDollarsSatsPattern5} sentInProfit14dEma * @property {MetricPattern6} sopr * @property {MetricPattern6} sopr30dEma * @property {MetricPattern6} sopr7dEma @@ -1619,14 +1665,13 @@ function createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSel */ /** - * Create a AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 pattern node + * Create a CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} + * @returns {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} */ -function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, acc) { +function createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) { return { - athRegret: createCumulativeSumPattern(client, _m(acc, 'realized_ath_regret')), capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), @@ -1638,10 +1683,13 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), negRealizedLoss: createCumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl')), + netRealizedPnl7dEma: createMetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')), netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), netRealizedPnlRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + peakRegret: createCumulativeSumPattern(client, _m(acc, 'realized_peak_regret')), + peakRegretRelToRealizedCap: createMetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')), profitFlow: createMetricPattern1(client, _m(acc, 'profit_flow')), profitValueCreated: createMetricPattern1(client, _m(acc, 'profit_value_created')), profitValueDestroyed: createMetricPattern1(client, _m(acc, 'profit_value_destroyed')), @@ -1650,16 +1698,22 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot realizedCapCents: createMetricPattern1(client, _m(acc, 'realized_cap_cents')), realizedCapRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')), realizedLoss: createCumulativeSumPattern(client, _m(acc, 'realized_loss')), + realizedLoss7dEma: createMetricPattern4(client, _m(acc, 'realized_loss_7d_ema')), realizedLossRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createDollarsSatsPattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createRatioPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createCumulativeSumPattern(client, _m(acc, 'realized_profit')), + realizedProfit7dEma: createMetricPattern4(client, _m(acc, 'realized_profit_7d_ema')), realizedProfitRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), realizedProfitToLossRatio: createMetricPattern6(client, _m(acc, 'realized_profit_to_loss_ratio')), realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), sellSideRiskRatio: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio')), sellSideRiskRatio30dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), sellSideRiskRatio7dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sentInLoss: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')), + sentInLoss14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')), + sentInProfit: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')), + sentInProfit14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')), sopr: createMetricPattern6(client, _m(acc, 'sopr')), sopr30dEma: createMetricPattern6(client, _m(acc, 'sopr_30d_ema')), sopr7dEma: createMetricPattern6(client, _m(acc, 'sopr_7d_ema')), @@ -1670,8 +1724,7 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot } /** - * @typedef {Object} AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern - * @property {CumulativeSumPattern} athRegret + * @typedef {Object} CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern * @property {MetricPattern11} capRaw * @property {MetricPattern1} capitulationFlow * @property {MetricPattern11} investorCapRaw @@ -1683,10 +1736,13 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot * @property {MetricPattern4} mvrv * @property {CumulativeSumPattern2} negRealizedLoss * @property {CumulativeSumPattern} netRealizedPnl + * @property {MetricPattern4} netRealizedPnl7dEma * @property {MetricPattern4} netRealizedPnlCumulative30dDelta * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap * @property {CumulativeSumPattern} netRealizedPnlRelToRealizedCap + * @property {CumulativeSumPattern} peakRegret + * @property {MetricPattern1} peakRegretRelToRealizedCap * @property {MetricPattern1} profitFlow * @property {MetricPattern1} profitValueCreated * @property {MetricPattern1} profitValueDestroyed @@ -1694,15 +1750,21 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot * @property {MetricPattern4} realizedCap30dDelta * @property {MetricPattern1} realizedCapCents * @property {CumulativeSumPattern} realizedLoss + * @property {MetricPattern4} realizedLoss7dEma * @property {CumulativeSumPattern} realizedLossRelToRealizedCap * @property {DollarsSatsPattern} realizedPrice * @property {RatioPattern2} realizedPriceExtra * @property {CumulativeSumPattern} realizedProfit + * @property {MetricPattern4} realizedProfit7dEma * @property {CumulativeSumPattern} realizedProfitRelToRealizedCap * @property {MetricPattern1} realizedValue * @property {MetricPattern6} sellSideRiskRatio * @property {MetricPattern6} sellSideRiskRatio30dEma * @property {MetricPattern6} sellSideRiskRatio7dEma + * @property {BitcoinDollarsSatsPattern3} sentInLoss + * @property {BitcoinDollarsSatsPattern5} sentInLoss14dEma + * @property {BitcoinDollarsSatsPattern3} sentInProfit + * @property {BitcoinDollarsSatsPattern5} sentInProfit14dEma * @property {MetricPattern6} sopr * @property {MetricPattern6} sopr30dEma * @property {MetricPattern6} sopr7dEma @@ -1712,14 +1774,13 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot */ /** - * Create a AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern pattern node + * Create a CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} + * @returns {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} */ -function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc) { +function createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) { return { - athRegret: createCumulativeSumPattern(client, _m(acc, 'realized_ath_regret')), capRaw: createMetricPattern11(client, _m(acc, 'cap_raw')), capitulationFlow: createMetricPattern1(client, _m(acc, 'capitulation_flow')), investorCapRaw: createMetricPattern11(client, _m(acc, 'investor_cap_raw')), @@ -1731,10 +1792,13 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), negRealizedLoss: createCumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl')), + netRealizedPnl7dEma: createMetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')), netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), netRealizedPnlRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + peakRegret: createCumulativeSumPattern(client, _m(acc, 'realized_peak_regret')), + peakRegretRelToRealizedCap: createMetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')), profitFlow: createMetricPattern1(client, _m(acc, 'profit_flow')), profitValueCreated: createMetricPattern1(client, _m(acc, 'profit_value_created')), profitValueDestroyed: createMetricPattern1(client, _m(acc, 'profit_value_destroyed')), @@ -1742,15 +1806,21 @@ function createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTot realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), realizedCapCents: createMetricPattern1(client, _m(acc, 'realized_cap_cents')), realizedLoss: createCumulativeSumPattern(client, _m(acc, 'realized_loss')), + realizedLoss7dEma: createMetricPattern4(client, _m(acc, 'realized_loss_7d_ema')), realizedLossRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createDollarsSatsPattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createRatioPattern2(client, _m(acc, 'realized_price_ratio')), realizedProfit: createCumulativeSumPattern(client, _m(acc, 'realized_profit')), + realizedProfit7dEma: createMetricPattern4(client, _m(acc, 'realized_profit_7d_ema')), realizedProfitRelToRealizedCap: createCumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), sellSideRiskRatio: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio')), sellSideRiskRatio30dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), sellSideRiskRatio7dEma: createMetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sentInLoss: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')), + sentInLoss14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')), + sentInProfit: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')), + sentInProfit14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')), sopr: createMetricPattern6(client, _m(acc, 'sopr')), sopr30dEma: createMetricPattern6(client, _m(acc, 'sopr_30d_ema')), sopr7dEma: createMetricPattern6(client, _m(acc, 'sopr_7d_ema')), @@ -1832,7 +1902,7 @@ function create_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern(client } /** - * @typedef {Object} InvestedNegNetNuplSupplyUnrealizedPattern2 + * @typedef {Object} InvestedNegNetNuplSupplyUnrealizedPattern4 * @property {MetricPattern1} investedCapitalInLossPct * @property {MetricPattern1} investedCapitalInProfitPct * @property {MetricPattern1} negUnrealizedLossRelToMarketCap @@ -1850,18 +1920,19 @@ function create_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern(client * @property {MetricPattern1} unrealizedLossRelToMarketCap * @property {MetricPattern1} unrealizedLossRelToOwnMarketCap * @property {MetricPattern1} unrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern4} unrealizedPeakRegretRelToMarketCap * @property {MetricPattern1} unrealizedProfitRelToMarketCap * @property {MetricPattern1} unrealizedProfitRelToOwnMarketCap * @property {MetricPattern1} unrealizedProfitRelToOwnTotalUnrealizedPnl */ /** - * Create a InvestedNegNetNuplSupplyUnrealizedPattern2 pattern node + * Create a InvestedNegNetNuplSupplyUnrealizedPattern4 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {InvestedNegNetNuplSupplyUnrealizedPattern2} + * @returns {InvestedNegNetNuplSupplyUnrealizedPattern4} */ -function createInvestedNegNetNuplSupplyUnrealizedPattern2(client, acc) { +function createInvestedNegNetNuplSupplyUnrealizedPattern4(client, acc) { return { investedCapitalInLossPct: createMetricPattern1(client, _m(acc, 'invested_capital_in_loss_pct')), investedCapitalInProfitPct: createMetricPattern1(client, _m(acc, 'invested_capital_in_profit_pct')), @@ -1880,6 +1951,7 @@ function createInvestedNegNetNuplSupplyUnrealizedPattern2(client, acc) { unrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')), unrealizedLossRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), + unrealizedPeakRegretRelToMarketCap: createMetricPattern4(client, _m(acc, 'unrealized_peak_regret_rel_to_market_cap')), unrealizedProfitRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')), unrealizedProfitRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), @@ -2048,8 +2120,56 @@ function createRatioPattern(client, acc) { } /** - * @typedef {Object} AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern - * @property {MetricPattern1} athRegret + * @typedef {Object} GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern + * @property {MetricPattern1} greedIndex + * @property {MetricPattern1} investedCapitalInLoss + * @property {MetricPattern11} investedCapitalInLossRaw + * @property {MetricPattern1} investedCapitalInProfit + * @property {MetricPattern11} investedCapitalInProfitRaw + * @property {MetricPattern11} investorCapInLossRaw + * @property {MetricPattern11} investorCapInProfitRaw + * @property {MetricPattern1} negUnrealizedLoss + * @property {MetricPattern1} netSentiment + * @property {MetricPattern1} netUnrealizedPnl + * @property {MetricPattern1} painIndex + * @property {MetricPattern4} peakRegret + * @property {BitcoinDollarsSatsPattern4} supplyInLoss + * @property {BitcoinDollarsSatsPattern4} supplyInProfit + * @property {MetricPattern1} totalUnrealizedPnl + * @property {MetricPattern1} unrealizedLoss + * @property {MetricPattern1} unrealizedProfit + */ + +/** + * Create a GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} + */ +function createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) { + return { + greedIndex: createMetricPattern1(client, _m(acc, 'greed_index')), + investedCapitalInLoss: createMetricPattern1(client, _m(acc, 'invested_capital_in_loss')), + investedCapitalInLossRaw: createMetricPattern11(client, _m(acc, 'invested_capital_in_loss_raw')), + investedCapitalInProfit: createMetricPattern1(client, _m(acc, 'invested_capital_in_profit')), + investedCapitalInProfitRaw: createMetricPattern11(client, _m(acc, 'invested_capital_in_profit_raw')), + investorCapInLossRaw: createMetricPattern11(client, _m(acc, 'investor_cap_in_loss_raw')), + investorCapInProfitRaw: createMetricPattern11(client, _m(acc, 'investor_cap_in_profit_raw')), + negUnrealizedLoss: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss')), + netSentiment: createMetricPattern1(client, _m(acc, 'net_sentiment')), + netUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl')), + painIndex: createMetricPattern1(client, _m(acc, 'pain_index')), + peakRegret: createMetricPattern4(client, _m(acc, 'unrealized_peak_regret')), + supplyInLoss: createBitcoinDollarsSatsPattern4(client, _m(acc, 'supply_in_loss')), + supplyInProfit: createBitcoinDollarsSatsPattern4(client, _m(acc, 'supply_in_profit')), + totalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'total_unrealized_pnl')), + unrealizedLoss: createMetricPattern1(client, _m(acc, 'unrealized_loss')), + unrealizedProfit: createMetricPattern1(client, _m(acc, 'unrealized_profit')), + }; +} + +/** + * @typedef {Object} GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern * @property {MetricPattern1} greedIndex * @property {MetricPattern1} investedCapitalInLoss * @property {MetricPattern11} investedCapitalInLossRaw @@ -2069,14 +2189,13 @@ function createRatioPattern(client, acc) { */ /** - * Create a AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern pattern node + * Create a GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} + * @returns {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} */ -function createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) { +function createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) { return { - athRegret: createMetricPattern1(client, _m(acc, 'unrealized_ath_regret')), greedIndex: createMetricPattern1(client, _m(acc, 'greed_index')), investedCapitalInLoss: createMetricPattern1(client, _m(acc, 'invested_capital_in_loss')), investedCapitalInLossRaw: createMetricPattern11(client, _m(acc, 'invested_capital_in_loss_raw')), @@ -2141,6 +2260,47 @@ function create_1m1w1y24hBlocksCoinbaseDaysDominanceFeeSubsidyPattern(client, ac }; } +/** + * @typedef {Object} InvestedNegNetNuplSupplyUnrealizedPattern3 + * @property {MetricPattern1} investedCapitalInLossPct + * @property {MetricPattern1} investedCapitalInProfitPct + * @property {MetricPattern1} negUnrealizedLossRelToMarketCap + * @property {MetricPattern1} netUnrealizedPnlRelToMarketCap + * @property {MetricPattern1} nupl + * @property {MetricPattern1} supplyInLossRelToCirculatingSupply + * @property {MetricPattern1} supplyInLossRelToOwnSupply + * @property {MetricPattern1} supplyInProfitRelToCirculatingSupply + * @property {MetricPattern1} supplyInProfitRelToOwnSupply + * @property {MetricPattern4} supplyRelToCirculatingSupply + * @property {MetricPattern1} unrealizedLossRelToMarketCap + * @property {MetricPattern4} unrealizedPeakRegretRelToMarketCap + * @property {MetricPattern1} unrealizedProfitRelToMarketCap + */ + +/** + * Create a InvestedNegNetNuplSupplyUnrealizedPattern3 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {InvestedNegNetNuplSupplyUnrealizedPattern3} + */ +function createInvestedNegNetNuplSupplyUnrealizedPattern3(client, acc) { + return { + investedCapitalInLossPct: createMetricPattern1(client, _m(acc, 'invested_capital_in_loss_pct')), + investedCapitalInProfitPct: createMetricPattern1(client, _m(acc, 'invested_capital_in_profit_pct')), + negUnrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')), + netUnrealizedPnlRelToMarketCap: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')), + nupl: createMetricPattern1(client, _m(acc, 'nupl')), + supplyInLossRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')), + supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), + supplyInProfitRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), + supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')), + unrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')), + unrealizedPeakRegretRelToMarketCap: createMetricPattern4(client, _m(acc, 'unrealized_peak_regret_rel_to_market_cap')), + unrealizedProfitRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')), + }; +} + /** * @typedef {Object} _10y1m1w1y2y3m3y4y5y6m6y8yPattern3 * @property {BitcoinDollarsSatsPattern5} _10y @@ -2562,10 +2722,10 @@ function createAverageBaseMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, acc) { * @property {MetricPattern1} addrCount * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} realized + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedNegNetNuplSupplyUnrealizedPattern} relative - * @property {HalvedTotalPattern} supply - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized */ /** @@ -2580,10 +2740,10 @@ function createActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern(cl addrCount: createMetricPattern1(client, _m(acc, 'addr_count')), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedNegNetNuplSupplyUnrealizedPattern(client, acc), - supply: createHalvedTotalPattern(client, _m(acc, 'supply')), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), }; } @@ -2621,10 +2781,10 @@ function create_10y2y3y4y5y6y8yPattern(client, acc) { * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {InvestedMaxMinPercentilesSpotPattern} costBasis * @property {UtxoPattern} outputs - * @property {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} realized + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized * @property {InvestedNegNetSupplyUnrealizedPattern} relative - * @property {HalvedTotalPattern} supply - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized */ /** @@ -2638,10 +2798,10 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern(client activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createInvestedMaxMinPercentilesSpotPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, acc), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc), relative: createInvestedNegNetSupplyUnrealizedPattern(client, acc), - supply: createHalvedTotalPattern(client, _m(acc, 'supply')), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc), }; } @@ -2650,10 +2810,10 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern(client * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} realized - * @property {InvestedNegNetNuplSupplyUnrealizedPattern} relative - * @property {HalvedTotalPattern} supply - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized + * @property {InvestedNegNetNuplSupplyUnrealizedPattern3} relative + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized */ /** @@ -2667,10 +2827,10 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, acc), - relative: createInvestedNegNetNuplSupplyUnrealizedPattern(client, acc), - supply: createHalvedTotalPattern(client, _m(acc, 'supply')), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + realized: createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc), + relative: createInvestedNegNetNuplSupplyUnrealizedPattern3(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc), }; } @@ -2679,10 +2839,10 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} realized + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedNegNetNuplSupplyUnrealizedPattern} relative - * @property {HalvedTotalPattern} supply - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized */ /** @@ -2696,10 +2856,39 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedNegNetNuplSupplyUnrealizedPattern(client, acc), - supply: createHalvedTotalPattern(client, _m(acc, 'supply')), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + }; +} + +/** + * @typedef {Object} ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 + * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity + * @property {MaxMinPattern} costBasis + * @property {UtxoPattern} outputs + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {InvestedNegNetNuplSupplyUnrealizedPattern3} relative + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized + */ + +/** + * Create a ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} + */ +function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, acc) { + return { + activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), + costBasis: createMaxMinPattern(client, acc), + outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + relative: createInvestedNegNetNuplSupplyUnrealizedPattern3(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc), }; } @@ -2708,10 +2897,10 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} realized + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized * @property {InvestedSupplyPattern} relative - * @property {HalvedTotalPattern} supply - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized */ /** @@ -2725,10 +2914,10 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3(clien activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), relative: createInvestedSupplyPattern(client, acc), - supply: createHalvedTotalPattern(client, _m(acc, 'supply')), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), }; } @@ -2737,9 +2926,9 @@ function createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3(clien * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity * @property {MaxMinPattern} costBasis * @property {UtxoPattern} outputs - * @property {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} realized - * @property {HalvedTotalPattern} supply - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {_30dHalvedTotalPattern} supply + * @property {GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized */ /** @@ -2753,9 +2942,9 @@ function createActivityCostOutputsRealizedSupplyUnrealizedPattern(client, acc) { activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc), costBasis: createMaxMinPattern(client, acc), outputs: createUtxoPattern(client, _m(acc, 'utxo_count')), - realized: createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc), - supply: createHalvedTotalPattern(client, _m(acc, 'supply')), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc), + supply: create_30dHalvedTotalPattern(client, acc), + unrealized: createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc), }; } @@ -2786,6 +2975,33 @@ function createBalanceBothReactivatedReceivingSendingPattern(client, acc) { }; } +/** + * @typedef {Object} CoinblocksCoindaysSatblocksSatdaysSentPattern + * @property {CumulativeSumPattern} coinblocksDestroyed + * @property {CumulativeSumPattern} coindaysDestroyed + * @property {MetricPattern11} satblocksDestroyed + * @property {MetricPattern11} satdaysDestroyed + * @property {BitcoinDollarsSatsPattern3} sent + * @property {BitcoinDollarsSatsPattern5} sent14dEma + */ + +/** + * Create a CoinblocksCoindaysSatblocksSatdaysSentPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CoinblocksCoindaysSatblocksSatdaysSentPattern} + */ +function createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) { + return { + coinblocksDestroyed: createCumulativeSumPattern(client, _m(acc, 'coinblocks_destroyed')), + coindaysDestroyed: createCumulativeSumPattern(client, _m(acc, 'coindays_destroyed')), + satblocksDestroyed: createMetricPattern11(client, _m(acc, 'satblocks_destroyed')), + satdaysDestroyed: createMetricPattern11(client, _m(acc, 'satdays_destroyed')), + sent: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent')), + sent14dEma: createBitcoinDollarsSatsPattern5(client, _m(acc, 'sent_14d_ema')), + }; +} + /** * @typedef {Object} InvestedMaxMinPercentilesSpotPattern * @property {Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern} investedCapital @@ -2813,31 +3029,6 @@ function createInvestedMaxMinPercentilesSpotPattern(client, acc) { }; } -/** - * @typedef {Object} CoinblocksCoindaysSatblocksSatdaysSentPattern - * @property {CumulativeSumPattern} coinblocksDestroyed - * @property {CumulativeSumPattern} coindaysDestroyed - * @property {MetricPattern11} satblocksDestroyed - * @property {MetricPattern11} satdaysDestroyed - * @property {BitcoinDollarsSatsPattern3} sent - */ - -/** - * Create a CoinblocksCoindaysSatblocksSatdaysSentPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CoinblocksCoindaysSatblocksSatdaysSentPattern} - */ -function createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) { - return { - coinblocksDestroyed: createCumulativeSumPattern(client, _m(acc, 'coinblocks_destroyed')), - coindaysDestroyed: createCumulativeSumPattern(client, _m(acc, 'coindays_destroyed')), - satblocksDestroyed: createMetricPattern11(client, _m(acc, 'satblocks_destroyed')), - satdaysDestroyed: createMetricPattern11(client, _m(acc, 'satdays_destroyed')), - sent: createBitcoinDollarsSatsPattern3(client, _m(acc, 'sent')), - }; -} - /** * @typedef {Object} InvestedSupplyPattern * @property {MetricPattern1} investedCapitalInLossPct @@ -2886,6 +3077,27 @@ function createCloseHighLowOpenPattern2(client, acc) { }; } +/** + * @typedef {Object} _30dHalvedTotalPattern + * @property {BitcoinDollarsSatsPattern5} _30dChange + * @property {BitcoinDollarsSatsPattern4} halved + * @property {BitcoinDollarsSatsPattern4} total + */ + +/** + * Create a _30dHalvedTotalPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_30dHalvedTotalPattern} + */ +function create_30dHalvedTotalPattern(client, acc) { + return { + _30dChange: createBitcoinDollarsSatsPattern5(client, _m(acc, '_30d_change')), + halved: createBitcoinDollarsSatsPattern4(client, _m(acc, 'supply_halved')), + total: createBitcoinDollarsSatsPattern4(client, _m(acc, 'supply')), + }; +} + /** * @typedef {Object} BaseCumulativeSumPattern * @property {MetricPattern11} base @@ -3050,25 +3262,6 @@ function createDollarsSatsPattern2(client, acc) { }; } -/** - * @typedef {Object} HalvedTotalPattern - * @property {BitcoinDollarsSatsPattern4} halved - * @property {BitcoinDollarsSatsPattern4} total - */ - -/** - * Create a HalvedTotalPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {HalvedTotalPattern} - */ -function createHalvedTotalPattern(client, acc) { - return { - halved: createBitcoinDollarsSatsPattern4(client, _m(acc, 'halved')), - total: createBitcoinDollarsSatsPattern4(client, acc), - }; -} - /** * @typedef {Object} MaxMinPattern * @property {DollarsSatsPattern} max @@ -4277,7 +4470,7 @@ function createUtxoPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution - * @property {MetricPattern11} chainState + * @property {MetricPattern11} supplyState * @property {MetricsTree_Distribution_AnyAddressIndexes} anyAddressIndexes * @property {MetricsTree_Distribution_AddressesData} addressesData * @property {MetricsTree_Distribution_UtxoCohorts} utxoCohorts @@ -4327,11 +4520,11 @@ function createUtxoPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All - * @property {HalvedTotalPattern} supply + * @property {_30dHalvedTotalPattern} supply * @property {UtxoPattern} outputs * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity - * @property {AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} realized - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized * @property {InvestedMaxMinPercentilesSpotPattern} costBasis * @property {MetricsTree_Distribution_UtxoCohorts_All_Relative} relative */ @@ -4340,12 +4533,18 @@ function createUtxoPattern(client, acc) { * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All_Relative * @property {MetricPattern1} supplyInProfitRelToOwnSupply * @property {MetricPattern1} supplyInLossRelToOwnSupply + * @property {MetricPattern1} unrealizedProfitRelToMarketCap + * @property {MetricPattern1} unrealizedLossRelToMarketCap + * @property {MetricPattern1} negUnrealizedLossRelToMarketCap + * @property {MetricPattern1} netUnrealizedPnlRelToMarketCap + * @property {MetricPattern1} nupl * @property {MetricPattern1} unrealizedProfitRelToOwnTotalUnrealizedPnl * @property {MetricPattern1} unrealizedLossRelToOwnTotalUnrealizedPnl * @property {MetricPattern1} negUnrealizedLossRelToOwnTotalUnrealizedPnl * @property {MetricPattern1} netUnrealizedPnlRelToOwnTotalUnrealizedPnl * @property {MetricPattern1} investedCapitalInProfitPct * @property {MetricPattern1} investedCapitalInLossPct + * @property {MetricPattern4} unrealizedPeakRegretRelToMarketCap */ /** @@ -4406,24 +4605,24 @@ function createUtxoPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_MinAge - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _1d - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _1w - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _1m - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _2m - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _3m - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _4m - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _5m - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _6m - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _1y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _2y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _3y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _4y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _5y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _6y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _7y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _8y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _10y - * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} _12y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _1d + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _1w + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _1m + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _2m + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _3m + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _4m + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _5m + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _6m + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _1y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _2y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _3y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _4y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _5y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _6y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _7y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _8y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _10y + * @property {ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} _12y */ /** @@ -4470,24 +4669,24 @@ function createUtxoPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_Term_Short - * @property {HalvedTotalPattern} supply + * @property {_30dHalvedTotalPattern} supply * @property {UtxoPattern} outputs * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity - * @property {AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} realized - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern} realized + * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized * @property {InvestedMaxMinPercentilesSpotPattern} costBasis - * @property {InvestedNegNetNuplSupplyUnrealizedPattern2} relative + * @property {InvestedNegNetNuplSupplyUnrealizedPattern4} relative */ /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_Term_Long - * @property {HalvedTotalPattern} supply + * @property {_30dHalvedTotalPattern} supply * @property {UtxoPattern} outputs * @property {CoinblocksCoindaysSatblocksSatdaysSentPattern} activity - * @property {AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} realized - * @property {AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} unrealized + * @property {CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2} realized + * @property {GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} unrealized * @property {InvestedMaxMinPercentilesSpotPattern} costBasis - * @property {InvestedNegNetNuplSupplyUnrealizedPattern2} relative + * @property {InvestedNegNetNuplSupplyUnrealizedPattern4} relative */ /** @@ -6414,7 +6613,7 @@ class BrkClient extends BrkClientBase { sats: createOhlcSplitPattern2(this, 'price'), }, distribution: { - chainState: createMetricPattern11(this, 'chain'), + supplyState: createMetricPattern11(this, 'supply_state'), anyAddressIndexes: { p2a: createMetricPattern16(this, 'anyaddressindex'), p2pk33: createMetricPattern18(this, 'anyaddressindex'), @@ -6431,21 +6630,27 @@ class BrkClient extends BrkClientBase { }, utxoCohorts: { all: { - supply: createHalvedTotalPattern(this, 'supply'), + supply: create_30dHalvedTotalPattern(this, ''), outputs: createUtxoPattern(this, 'utxo_count'), activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(this, ''), - realized: createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(this, ''), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(this, ''), + realized: createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(this, ''), + unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(this, ''), costBasis: createInvestedMaxMinPercentilesSpotPattern(this, ''), relative: { supplyInProfitRelToOwnSupply: createMetricPattern1(this, 'supply_in_profit_rel_to_own_supply'), supplyInLossRelToOwnSupply: createMetricPattern1(this, 'supply_in_loss_rel_to_own_supply'), + unrealizedProfitRelToMarketCap: createMetricPattern1(this, 'unrealized_profit_rel_to_market_cap'), + unrealizedLossRelToMarketCap: createMetricPattern1(this, 'unrealized_loss_rel_to_market_cap'), + negUnrealizedLossRelToMarketCap: createMetricPattern1(this, 'neg_unrealized_loss_rel_to_market_cap'), + netUnrealizedPnlRelToMarketCap: createMetricPattern1(this, 'net_unrealized_pnl_rel_to_market_cap'), + nupl: createMetricPattern1(this, 'nupl'), unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern1(this, 'unrealized_profit_rel_to_own_total_unrealized_pnl'), unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(this, 'unrealized_loss_rel_to_own_total_unrealized_pnl'), negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(this, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl'), netUnrealizedPnlRelToOwnTotalUnrealizedPnl: createMetricPattern1(this, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl'), investedCapitalInProfitPct: createMetricPattern1(this, 'invested_capital_in_profit_pct'), investedCapitalInLossPct: createMetricPattern1(this, 'invested_capital_in_loss_pct'), + unrealizedPeakRegretRelToMarketCap: createMetricPattern4(this, 'unrealized_peak_regret_rel_to_market_cap'), }, }, ageRange: { @@ -6499,24 +6704,24 @@ class BrkClient extends BrkClientBase { _2026: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3(this, 'year_2026'), }, minAge: { - _1d: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_1d_old'), - _1w: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_1w_old'), - _1m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_1m_old'), - _2m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_2m_old'), - _3m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_3m_old'), - _4m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_4m_old'), - _5m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_5m_old'), - _6m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_6m_old'), - _1y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_1y_old'), - _2y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_2y_old'), - _3y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_3y_old'), - _4y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_4y_old'), - _5y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_5y_old'), - _6y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_6y_old'), - _7y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_7y_old'), - _8y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_8y_old'), - _10y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_10y_old'), - _12y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_12y_old'), + _1d: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_1d_old'), + _1w: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_1w_old'), + _1m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_1m_old'), + _2m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_2m_old'), + _3m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_3m_old'), + _4m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_4m_old'), + _5m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_5m_old'), + _6m: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_6m_old'), + _1y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_1y_old'), + _2y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_2y_old'), + _3y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_3y_old'), + _4y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_4y_old'), + _5y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_5y_old'), + _6y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_6y_old'), + _7y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_7y_old'), + _8y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_8y_old'), + _10y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_10y_old'), + _12y: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(this, 'utxos_over_12y_old'), }, geAmount: { _1sat: createActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(this, 'utxos_over_1sat'), @@ -6552,22 +6757,22 @@ class BrkClient extends BrkClientBase { }, term: { short: { - supply: createHalvedTotalPattern(this, 'sth_supply'), + supply: create_30dHalvedTotalPattern(this, 'sth'), outputs: createUtxoPattern(this, 'sth_utxo_count'), activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(this, 'sth'), - realized: createAdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(this, 'sth'), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(this, 'sth'), + realized: createAdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(this, 'sth'), + unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(this, 'sth'), costBasis: createInvestedMaxMinPercentilesSpotPattern(this, 'sth'), - relative: createInvestedNegNetNuplSupplyUnrealizedPattern2(this, 'sth'), + relative: createInvestedNegNetNuplSupplyUnrealizedPattern4(this, 'sth'), }, long: { - supply: createHalvedTotalPattern(this, 'lth_supply'), + supply: create_30dHalvedTotalPattern(this, 'lth'), outputs: createUtxoPattern(this, 'lth_utxo_count'), activity: createCoinblocksCoindaysSatblocksSatdaysSentPattern(this, 'lth'), - realized: createAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(this, 'lth'), - unrealized: createAthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(this, 'lth'), + realized: createCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(this, 'lth'), + unrealized: createGreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(this, 'lth'), costBasis: createInvestedMaxMinPercentilesSpotPattern(this, 'lth'), - relative: createInvestedNegNetNuplSupplyUnrealizedPattern2(this, 'lth'), + relative: createInvestedNegNetNuplSupplyUnrealizedPattern4(this, 'lth'), }, }, type: { diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 49f92a10a..b0b6aa504 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -123,6 +123,9 @@ RawLockTime = int # - $0.001 = 1 sat # - $0.0001 = 0.1 sats (fractional) SatsFract = float +# Signed satoshis (i64) - for values that can be negative. +# Used for changes, deltas, profit/loss calculations, etc. +SatsSigned = int SemesterIndex = int # Fixed-size boolean value optimized for on-disk storage (stored as u8) StoredBool = int @@ -1826,7 +1829,7 @@ class MetricPattern32(Generic[T]): # Reusable structural pattern classes -class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern: +class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -1836,7 +1839,6 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.adjusted_sopr_7d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'adjusted_sopr_7d_ema')) self.adjusted_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_created')) self.adjusted_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed')) - self.ath_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_ath_regret')) self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) @@ -1848,10 +1850,13 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) self.neg_realized_loss: CumulativeSumPattern2[Dollars] = CumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl')) + self.net_realized_pnl_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')) self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) self.net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.peak_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_peak_regret')) + self.peak_regret_rel_to_realized_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')) self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_flow')) self.profit_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_created')) self.profit_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_destroyed')) @@ -1860,16 +1865,22 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.realized_cap_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'realized_cap_cents')) self.realized_cap_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')) self.realized_loss: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_loss')) + self.realized_loss_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_loss_7d_ema')) self.realized_loss_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'realized_price')) self.realized_price_extra: RatioPattern = RatioPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_profit')) + self.realized_profit_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_profit_7d_ema')) self.realized_profit_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) self.realized_profit_to_loss_ratio: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'realized_profit_to_loss_ratio')) self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) self.sell_side_risk_ratio: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio')) self.sell_side_risk_ratio_30d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) self.sell_side_risk_ratio_7d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sent_in_loss: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')) + self.sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')) + self.sent_in_profit: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')) + self.sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')) self.sopr: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr')) self.sopr_30d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_30d_ema')) self.sopr_7d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_7d_ema')) @@ -1877,7 +1888,7 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) -class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2: +class AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -1887,7 +1898,6 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.adjusted_sopr_7d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'adjusted_sopr_7d_ema')) self.adjusted_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_created')) self.adjusted_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed')) - self.ath_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_ath_regret')) self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) @@ -1899,10 +1909,13 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) self.neg_realized_loss: CumulativeSumPattern2[Dollars] = CumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl')) + self.net_realized_pnl_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')) self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) self.net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.peak_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_peak_regret')) + self.peak_regret_rel_to_realized_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')) self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_flow')) self.profit_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_created')) self.profit_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_destroyed')) @@ -1910,15 +1923,21 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) self.realized_cap_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'realized_cap_cents')) self.realized_loss: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_loss')) + self.realized_loss_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_loss_7d_ema')) self.realized_loss_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'realized_price')) self.realized_price_extra: RatioPattern2 = RatioPattern2(client, _m(acc, 'realized_price_ratio')) self.realized_profit: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_profit')) + self.realized_profit_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_profit_7d_ema')) self.realized_profit_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) self.sell_side_risk_ratio: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio')) self.sell_side_risk_ratio_30d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) self.sell_side_risk_ratio_7d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sent_in_loss: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')) + self.sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')) + self.sent_in_profit: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')) + self.sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')) self.sopr: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr')) self.sopr_30d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_30d_ema')) self.sopr_7d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_7d_ema')) @@ -1926,12 +1945,11 @@ class AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTota self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) -class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2: +class CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.ath_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_ath_regret')) self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) @@ -1943,10 +1961,13 @@ class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePa self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) self.neg_realized_loss: CumulativeSumPattern2[Dollars] = CumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl')) + self.net_realized_pnl_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')) self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) self.net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.peak_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_peak_regret')) + self.peak_regret_rel_to_realized_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')) self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_flow')) self.profit_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_created')) self.profit_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_destroyed')) @@ -1955,16 +1976,22 @@ class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePa self.realized_cap_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'realized_cap_cents')) self.realized_cap_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')) self.realized_loss: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_loss')) + self.realized_loss_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_loss_7d_ema')) self.realized_loss_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'realized_price')) self.realized_price_extra: RatioPattern = RatioPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_profit')) + self.realized_profit_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_profit_7d_ema')) self.realized_profit_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) self.realized_profit_to_loss_ratio: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'realized_profit_to_loss_ratio')) self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) self.sell_side_risk_ratio: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio')) self.sell_side_risk_ratio_30d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) self.sell_side_risk_ratio_7d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sent_in_loss: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')) + self.sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')) + self.sent_in_profit: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')) + self.sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')) self.sopr: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr')) self.sopr_30d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_30d_ema')) self.sopr_7d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_7d_ema')) @@ -1972,12 +1999,11 @@ class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePa self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) -class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern: +class CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.ath_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_ath_regret')) self.cap_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'cap_raw')) self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow')) self.investor_cap_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_raw')) @@ -1989,10 +2015,13 @@ class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePa self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) self.neg_realized_loss: CumulativeSumPattern2[Dollars] = CumulativeSumPattern2(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl')) + self.net_realized_pnl_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_7d_ema')) self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) self.net_realized_pnl_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.peak_regret: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_peak_regret')) + self.peak_regret_rel_to_realized_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'peak_regret_rel_to_realized_cap')) self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_flow')) self.profit_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_created')) self.profit_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_value_destroyed')) @@ -2000,15 +2029,21 @@ class AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePa self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) self.realized_cap_cents: MetricPattern1[CentsUnsigned] = MetricPattern1(client, _m(acc, 'realized_cap_cents')) self.realized_loss: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_loss')) + self.realized_loss_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_loss_7d_ema')) self.realized_loss_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: DollarsSatsPattern = DollarsSatsPattern(client, _m(acc, 'realized_price')) self.realized_price_extra: RatioPattern2 = RatioPattern2(client, _m(acc, 'realized_price_ratio')) self.realized_profit: CumulativeSumPattern[Dollars] = CumulativeSumPattern(client, _m(acc, 'realized_profit')) + self.realized_profit_7d_ema: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_profit_7d_ema')) self.realized_profit_rel_to_realized_cap: CumulativeSumPattern[StoredF32] = CumulativeSumPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) self.sell_side_risk_ratio: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio')) self.sell_side_risk_ratio_30d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) self.sell_side_risk_ratio_7d_ema: MetricPattern6[StoredF32] = MetricPattern6(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sent_in_loss: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_loss')) + self.sent_in_loss_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_loss_14d_ema')) + self.sent_in_profit: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent_in_profit')) + self.sent_in_profit_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_in_profit_14d_ema')) self.sopr: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr')) self.sopr_30d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_30d_ema')) self.sopr_7d_ema: MetricPattern6[StoredF64] = MetricPattern6(client, _m(acc, 'sopr_7d_ema')) @@ -2050,7 +2085,7 @@ class _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern: self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) self.zscore: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'zscore')) -class InvestedNegNetNuplSupplyUnrealizedPattern2: +class InvestedNegNetNuplSupplyUnrealizedPattern4: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -2072,6 +2107,7 @@ class InvestedNegNetNuplSupplyUnrealizedPattern2: self.unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) self.unrealized_loss_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.unrealized_peak_regret_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'unrealized_peak_regret_rel_to_market_cap')) self.unrealized_profit_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) self.unrealized_profit_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) @@ -2152,12 +2188,34 @@ class RatioPattern: self.ratio_pct99_usd: DollarsSatsPattern2 = DollarsSatsPattern2(client, _m(acc, 'pct99_usd')) self.ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern = _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern(client, acc) -class AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern: +class GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.greed_index: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'greed_index')) + self.invested_capital_in_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'invested_capital_in_loss')) + self.invested_capital_in_loss_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'invested_capital_in_loss_raw')) + self.invested_capital_in_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'invested_capital_in_profit')) + self.invested_capital_in_profit_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'invested_capital_in_profit_raw')) + self.investor_cap_in_loss_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_in_loss_raw')) + self.investor_cap_in_profit_raw: MetricPattern11[CentsSquaredSats] = MetricPattern11(client, _m(acc, 'investor_cap_in_profit_raw')) + self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss')) + self.net_sentiment: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'net_sentiment')) + self.net_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl')) + self.pain_index: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'pain_index')) + self.peak_regret: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'unrealized_peak_regret')) + self.supply_in_loss: BitcoinDollarsSatsPattern4 = BitcoinDollarsSatsPattern4(client, _m(acc, 'supply_in_loss')) + self.supply_in_profit: BitcoinDollarsSatsPattern4 = BitcoinDollarsSatsPattern4(client, _m(acc, 'supply_in_profit')) + self.total_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_unrealized_pnl')) + self.unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_loss')) + self.unrealized_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_profit')) + +class GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.ath_regret: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_ath_regret')) self.greed_index: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'greed_index')) self.invested_capital_in_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'invested_capital_in_loss')) self.invested_capital_in_loss_raw: MetricPattern11[CentsSats] = MetricPattern11(client, _m(acc, 'invested_capital_in_loss_raw')) @@ -2196,6 +2254,25 @@ class _1m1w1y24hBlocksCoinbaseDaysDominanceFeeSubsidyPattern: self.fee: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'fee')) self.subsidy: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'subsidy')) +class InvestedNegNetNuplSupplyUnrealizedPattern3: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.invested_capital_in_loss_pct: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'invested_capital_in_loss_pct')) + self.invested_capital_in_profit_pct: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'invested_capital_in_profit_pct')) + self.neg_unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')) + self.net_unrealized_pnl_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')) + self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'nupl')) + self.supply_in_loss_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')) + self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) + self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')) + self.unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) + self.unrealized_peak_regret_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'unrealized_peak_regret_rel_to_market_cap')) + self.unrealized_profit_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) + class _10y1m1w1y2y3m3y4y5y6m6y8yPattern3: """Pattern struct for repeated tree structure.""" @@ -2390,10 +2467,10 @@ class ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern: self.addr_count: MetricPattern1[StoredU64] = MetricPattern1(client, _m(acc, 'addr_count')) self.cost_basis: MaxMinPattern = MaxMinPattern(client, acc) self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count')) - self.realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern = AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedNegNetNuplSupplyUnrealizedPattern = InvestedNegNetNuplSupplyUnrealizedPattern(client, acc) - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, _m(acc, 'supply')) - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) class _10y2y3y4y5y6y8yPattern: """Pattern struct for repeated tree structure.""" @@ -2416,10 +2493,10 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 = AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, acc) + self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) self.relative: InvestedNegNetSupplyUnrealizedPattern = InvestedNegNetSupplyUnrealizedPattern(client, acc) - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, _m(acc, 'supply')) - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern5: """Pattern struct for repeated tree structure.""" @@ -2429,10 +2506,10 @@ 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: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 = AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, acc) - self.relative: InvestedNegNetNuplSupplyUnrealizedPattern = InvestedNegNetNuplSupplyUnrealizedPattern(client, acc) - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, _m(acc, 'supply')) - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + self.realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, acc) + self.relative: InvestedNegNetNuplSupplyUnrealizedPattern3 = InvestedNegNetNuplSupplyUnrealizedPattern3(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4: """Pattern struct for repeated tree structure.""" @@ -2442,10 +2519,23 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern = AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedNegNetNuplSupplyUnrealizedPattern = InvestedNegNetNuplSupplyUnrealizedPattern(client, acc) - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, _m(acc, 'supply')) - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + +class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + 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.relative: InvestedNegNetNuplSupplyUnrealizedPattern3 = InvestedNegNetNuplSupplyUnrealizedPattern3(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, acc) class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3: """Pattern struct for repeated tree structure.""" @@ -2455,10 +2545,10 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern = AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc) + self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) self.relative: InvestedSupplyPattern = InvestedSupplyPattern(client, acc) - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, _m(acc, 'supply')) - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) class ActivityCostOutputsRealizedSupplyUnrealizedPattern: """Pattern struct for repeated tree structure.""" @@ -2468,9 +2558,9 @@ 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: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern = AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, acc) - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, _m(acc, 'supply')) - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) + self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, acc) + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, acc) + self.unrealized: GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, acc) class BalanceBothReactivatedReceivingSendingPattern: """Pattern struct for repeated tree structure.""" @@ -2484,6 +2574,18 @@ class BalanceBothReactivatedReceivingSendingPattern: self.receiving: AverageBaseMaxMedianMinPct10Pct25Pct75Pct90Pattern[StoredU32] = AverageBaseMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, _m(acc, 'receiving')) self.sending: AverageBaseMaxMedianMinPct10Pct25Pct75Pct90Pattern[StoredU32] = AverageBaseMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, _m(acc, 'sending')) +class CoinblocksCoindaysSatblocksSatdaysSentPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.coinblocks_destroyed: CumulativeSumPattern[StoredF64] = CumulativeSumPattern(client, _m(acc, 'coinblocks_destroyed')) + self.coindays_destroyed: CumulativeSumPattern[StoredF64] = CumulativeSumPattern(client, _m(acc, 'coindays_destroyed')) + self.satblocks_destroyed: MetricPattern11[Sats] = MetricPattern11(client, _m(acc, 'satblocks_destroyed')) + self.satdays_destroyed: MetricPattern11[Sats] = MetricPattern11(client, _m(acc, 'satdays_destroyed')) + self.sent: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent')) + self.sent_14d_ema: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, 'sent_14d_ema')) + class InvestedMaxMinPercentilesSpotPattern: """Pattern struct for repeated tree structure.""" @@ -2496,17 +2598,6 @@ class InvestedMaxMinPercentilesSpotPattern: self.spot_cost_basis_percentile: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'spot_cost_basis_percentile')) self.spot_invested_capital_percentile: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'spot_invested_capital_percentile')) -class CoinblocksCoindaysSatblocksSatdaysSentPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.coinblocks_destroyed: CumulativeSumPattern[StoredF64] = CumulativeSumPattern(client, _m(acc, 'coinblocks_destroyed')) - self.coindays_destroyed: CumulativeSumPattern[StoredF64] = CumulativeSumPattern(client, _m(acc, 'coindays_destroyed')) - self.satblocks_destroyed: MetricPattern11[Sats] = MetricPattern11(client, _m(acc, 'satblocks_destroyed')) - self.satdays_destroyed: MetricPattern11[Sats] = MetricPattern11(client, _m(acc, 'satdays_destroyed')) - self.sent: BitcoinDollarsSatsPattern3 = BitcoinDollarsSatsPattern3(client, _m(acc, 'sent')) - class InvestedSupplyPattern: """Pattern struct for repeated tree structure.""" @@ -2527,6 +2618,15 @@ class CloseHighLowOpenPattern2(Generic[T]): self.low: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'low')) self.open: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'open')) +class _30dHalvedTotalPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self._30d_change: BitcoinDollarsSatsPattern5 = BitcoinDollarsSatsPattern5(client, _m(acc, '_30d_change')) + self.halved: BitcoinDollarsSatsPattern4 = BitcoinDollarsSatsPattern4(client, _m(acc, 'supply_halved')) + self.total: BitcoinDollarsSatsPattern4 = BitcoinDollarsSatsPattern4(client, _m(acc, 'supply')) + class BaseCumulativeSumPattern: """Pattern struct for repeated tree structure.""" @@ -2597,14 +2697,6 @@ class DollarsSatsPattern2: self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, acc) self.sats: MetricPattern4[SatsFract] = MetricPattern4(client, _m(acc, 'sats')) -class HalvedTotalPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.halved: BitcoinDollarsSatsPattern4 = BitcoinDollarsSatsPattern4(client, _m(acc, 'halved')) - self.total: BitcoinDollarsSatsPattern4 = BitcoinDollarsSatsPattern4(client, acc) - class MaxMinPattern: """Pattern struct for repeated tree structure.""" @@ -3822,22 +3914,28 @@ class MetricsTree_Distribution_UtxoCohorts_All_Relative: def __init__(self, client: BrkClientBase, base_path: str = ''): self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, 'supply_in_profit_rel_to_own_supply') self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, 'supply_in_loss_rel_to_own_supply') + self.unrealized_profit_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, 'unrealized_profit_rel_to_market_cap') + self.unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, 'unrealized_loss_rel_to_market_cap') + self.neg_unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, 'neg_unrealized_loss_rel_to_market_cap') + self.net_unrealized_pnl_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, 'net_unrealized_pnl_rel_to_market_cap') + self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, 'nupl') self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, 'unrealized_profit_rel_to_own_total_unrealized_pnl') self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, 'unrealized_loss_rel_to_own_total_unrealized_pnl') self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl') self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl') self.invested_capital_in_profit_pct: MetricPattern1[StoredF32] = MetricPattern1(client, 'invested_capital_in_profit_pct') self.invested_capital_in_loss_pct: MetricPattern1[StoredF32] = MetricPattern1(client, 'invested_capital_in_loss_pct') + self.unrealized_peak_regret_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, 'unrealized_peak_regret_rel_to_market_cap') class MetricsTree_Distribution_UtxoCohorts_All: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, 'supply') + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, '') self.outputs: UtxoPattern = UtxoPattern(client, 'utxo_count') self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, '') - self.realized: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern = AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, '') - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, '') + self.realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(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) @@ -3904,24 +4002,24 @@ class MetricsTree_Distribution_UtxoCohorts_MinAge: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1d_old') - self._1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1w_old') - self._1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1m_old') - self._2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_2m_old') - self._3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_3m_old') - self._4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_4m_old') - self._5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_5m_old') - self._6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_6m_old') - self._1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1y_old') - self._2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_2y_old') - self._3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_3y_old') - self._4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_4y_old') - self._5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_5y_old') - self._6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_6y_old') - self._7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_7y_old') - self._8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_8y_old') - self._10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_10y_old') - self._12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_12y_old') + self._1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_1d_old') + self._1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_1w_old') + self._1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_1m_old') + self._2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_2m_old') + self._3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_3m_old') + self._4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_4m_old') + self._5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_5m_old') + self._6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_6m_old') + self._1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_1y_old') + self._2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_2y_old') + self._3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_3y_old') + self._4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_4y_old') + self._5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_5y_old') + self._6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_6y_old') + self._7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_7y_old') + self._8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_8y_old') + self._10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_10y_old') + self._12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6(client, 'utxos_over_12y_old') class MetricsTree_Distribution_UtxoCohorts_GeAmount: """Metrics tree node.""" @@ -3965,25 +4063,25 @@ class MetricsTree_Distribution_UtxoCohorts_Term_Short: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, 'sth_supply') + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, 'sth') self.outputs: UtxoPattern = UtxoPattern(client, 'sth_utxo_count') self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, 'sth') - self.realized: AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern = AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern(client, 'sth') - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, 'sth') + self.realized: AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern = AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern(client, 'sth') + self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, 'sth') self.cost_basis: InvestedMaxMinPercentilesSpotPattern = InvestedMaxMinPercentilesSpotPattern(client, 'sth') - self.relative: InvestedNegNetNuplSupplyUnrealizedPattern2 = InvestedNegNetNuplSupplyUnrealizedPattern2(client, 'sth') + self.relative: InvestedNegNetNuplSupplyUnrealizedPattern4 = InvestedNegNetNuplSupplyUnrealizedPattern4(client, 'sth') class MetricsTree_Distribution_UtxoCohorts_Term_Long: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.supply: HalvedTotalPattern = HalvedTotalPattern(client, 'lth_supply') + self.supply: _30dHalvedTotalPattern = _30dHalvedTotalPattern(client, 'lth') self.outputs: UtxoPattern = UtxoPattern(client, 'lth_utxo_count') self.activity: CoinblocksCoindaysSatblocksSatdaysSentPattern = CoinblocksCoindaysSatblocksSatdaysSentPattern(client, 'lth') - self.realized: AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2 = AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2(client, 'lth') - self.unrealized: AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern = AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(client, 'lth') + self.realized: CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2 = CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSentSoprTotalValuePattern2(client, 'lth') + self.unrealized: GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern = GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern(client, 'lth') self.cost_basis: InvestedMaxMinPercentilesSpotPattern = InvestedMaxMinPercentilesSpotPattern(client, 'lth') - self.relative: InvestedNegNetNuplSupplyUnrealizedPattern2 = InvestedNegNetNuplSupplyUnrealizedPattern2(client, 'lth') + self.relative: InvestedNegNetNuplSupplyUnrealizedPattern4 = InvestedNegNetNuplSupplyUnrealizedPattern4(client, 'lth') class MetricsTree_Distribution_UtxoCohorts_Term: """Metrics tree node.""" @@ -4175,7 +4273,7 @@ class MetricsTree_Distribution: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.chain_state: MetricPattern11[SupplyState] = MetricPattern11(client, 'chain') + self.supply_state: MetricPattern11[SupplyState] = MetricPattern11(client, 'supply_state') self.any_address_indexes: MetricsTree_Distribution_AnyAddressIndexes = MetricsTree_Distribution_AnyAddressIndexes(client) self.addresses_data: MetricsTree_Distribution_AddressesData = MetricsTree_Distribution_AddressesData(client) self.utxo_cohorts: MetricsTree_Distribution_UtxoCohorts = MetricsTree_Distribution_UtxoCohorts(client) diff --git a/website/.gitignore b/website/.gitignore index 4c0699949..301552ca6 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -1,3 +1,4 @@ */**/*.md !scripts/**/_*.js *_old.js +_*.js diff --git a/website/scripts/chart/index.js b/website/scripts/chart/index.js index 7c6658d7c..b2795c627 100644 --- a/website/scripts/chart/index.js +++ b/website/scripts/chart/index.js @@ -79,6 +79,9 @@ const lineWidth = /** @type {any} */ (1.5); export function createChart({ parent, id: chartId, brk, fitContent }) { const baseUrl = brk.baseUrl.replace(/\/$/, ""); + /** @type {string} */ + let storageId = ""; + /** @param {ChartableIndex} idx */ const getTimeEndpoint = (idx) => idx === "height" @@ -500,7 +503,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { const active = createPersistedValue({ defaultValue: defaultActive ?? true, - storageKey: `${chartId}-p${paneIndex}-${key}`, + storageKey: `${storageId}-p${paneIndex}-${key}`, urlKey: `${paneIndex === 0 ? "t" : "b"}-${key}`, ...serdeBool, }); @@ -1275,12 +1278,12 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { * @param {Unit} unit */ function applyScaleForUnit(paneIndex, unit) { - const id = `${chartId}-scale`; - const defaultValue = unit.id === "usd" ? "log" : "lin"; + const id = `${storageId}-scale`; + const defaultValue = paneIndex === 0 ? "log" : "lin"; const persisted = createPersistedValue({ defaultValue: /** @type {"lin" | "log"} */ (defaultValue), - storageKey: `${id}-${paneIndex}-${unit.id}`, + storageKey: `${storageId}-p${paneIndex}-scale`, urlKey: paneIndex === 0 ? "price_scale" : "unit_scale", serialize: (v) => v, deserialize: (s) => /** @type {"lin" | "log"} */ (s), @@ -1457,11 +1460,13 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { /** * @param {Object} args + * @param {string} args.name * @param {Map} args.top * @param {Map} args.bottom * @param {VoidFunction} [args.onDataLoaded] */ - setBlueprints({ top, bottom, onDataLoaded }) { + setBlueprints({ name, top, bottom, onDataLoaded }) { + storageId = stringToId(name); blueprints.panes[0].map = top; blueprints.panes[1].map = bottom; blueprints.onDataLoaded = onDataLoaded; @@ -1481,7 +1486,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { .join(","); const persistedUnit = createPersistedValue({ defaultValue: /** @type {string} */ (defaultUnit.id), - storageKey: `unit-${sortedUnitIds}`, + storageKey: `${storageId}-p${paneIndex}-unit`, urlKey: paneIndex === 0 ? "u0" : "u1", serialize: (v) => v, deserialize: (s) => s, diff --git a/website/scripts/options/distribution/address.js b/website/scripts/options/distribution/address.js index 216b532c8..3b8752d77 100644 --- a/website/scripts/options/distribution/address.js +++ b/website/scripts/options/distribution/address.js @@ -7,7 +7,7 @@ import { Unit } from "../../utils/units.js"; import { priceLine } from "../constants.js"; import { line, baseline, price } from "../series.js"; -import { formatCohortTitle } from "../shared.js"; +import { formatCohortTitle, satsBtcUsd } from "../shared.js"; import { createSingleSupplySeries, createGroupedSupplySection, @@ -19,9 +19,6 @@ import { createGroupedCoinblocksDestroyedSeries, createGroupedCoindaysDestroyedSeries, createSingleSentSeries, - createGroupedSentSatsSeries, - createGroupedSentBitcoinSeries, - createGroupedSentDollarsSeries, groupedSupplyRelativeGenerators, createSingleSupplyRelativeOptions, createSingleSellSideRiskSeries, @@ -139,13 +136,13 @@ export function createAddressCohortFolder(ctx, args) { }), ), }, - ...(!useGroupName - ? createRealizedPnlSection( + ...(useGroupName + ? createGroupedRealizedPnlSection(ctx, list, title) + : createRealizedPnlSection( ctx, /** @type {AddressCohortObject} */ (args), title, - ) - : []), + )), ], }, @@ -255,6 +252,12 @@ function createRealizedPnlSection(ctx, args, title) { color: colors.green, unit: Unit.usd, }), + line({ + metric: realized.realizedProfit7dEma, + name: "Profit 7d EMA", + color: colors.green, + unit: Unit.usd, + }), line({ metric: realized.realizedProfit.cumulative, name: "Profit Cumulative", @@ -268,6 +271,12 @@ function createRealizedPnlSection(ctx, args, title) { color: colors.red, unit: Unit.usd, }), + line({ + metric: realized.realizedLoss7dEma, + name: "Loss 7d EMA", + color: colors.red, + unit: Unit.usd, + }), line({ metric: realized.realizedLoss.cumulative, name: "Loss Cumulative", @@ -333,6 +342,11 @@ function createRealizedPnlSection(ctx, args, title) { name: "Net", unit: Unit.usd, }), + baseline({ + metric: realized.netRealizedPnl7dEma, + name: "Net 7d EMA", + unit: Unit.usd, + }), baseline({ metric: realized.netRealizedPnl.cumulative, name: "Net Cumulative", @@ -419,6 +433,179 @@ function createRealizedPnlSection(ctx, args, title) { }, ], }, + { + name: "Peak Regret", + title: title("Peak Regret"), + bottom: [ + line({ metric: realized.peakRegret.sum, name: "Sum", color: colors.red, unit: Unit.usd }), + line({ metric: realized.peakRegret.cumulative, name: "Cumulative", color: colors.red, unit: Unit.usd, defaultActive: false }), + baseline({ metric: realized.peakRegretRelToRealizedCap, name: "Rel. to Realized Cap", color: colors.orange, unit: Unit.pctRcap }), + ], + }, + { + name: "Sent In P/L", + tree: [ + { + name: "In Profit", + title: title("Sent In Profit"), + bottom: [ + line({ metric: realized.sentInProfit.bitcoin.sum, name: "Sum", color: colors.green, unit: Unit.btc }), + line({ metric: realized.sentInProfit.bitcoin.cumulative, name: "Cumulative", color: colors.green, unit: Unit.btc, defaultActive: false }), + line({ metric: realized.sentInProfit.sats.sum, name: "Sum", color: colors.green, unit: Unit.sats }), + line({ metric: realized.sentInProfit.sats.cumulative, name: "Cumulative", color: colors.green, unit: Unit.sats, defaultActive: false }), + line({ metric: realized.sentInProfit.dollars.sum, name: "Sum", color: colors.green, unit: Unit.usd }), + line({ metric: realized.sentInProfit.dollars.cumulative, name: "Cumulative", color: colors.green, unit: Unit.usd, defaultActive: false }), + ], + }, + { + name: "In Loss", + title: title("Sent In Loss"), + bottom: [ + line({ metric: realized.sentInLoss.bitcoin.sum, name: "Sum", color: colors.red, unit: Unit.btc }), + line({ metric: realized.sentInLoss.bitcoin.cumulative, name: "Cumulative", color: colors.red, unit: Unit.btc, defaultActive: false }), + line({ metric: realized.sentInLoss.sats.sum, name: "Sum", color: colors.red, unit: Unit.sats }), + line({ metric: realized.sentInLoss.sats.cumulative, name: "Cumulative", color: colors.red, unit: Unit.sats, defaultActive: false }), + line({ metric: realized.sentInLoss.dollars.sum, name: "Sum", color: colors.red, unit: Unit.usd }), + line({ metric: realized.sentInLoss.dollars.cumulative, name: "Cumulative", color: colors.red, unit: Unit.usd, defaultActive: false }), + ], + }, + { + name: "In Profit 14d EMA", + title: title("Sent In Profit 14d EMA"), + bottom: satsBtcUsd({ pattern: realized.sentInProfit14dEma, name: "14d EMA", color: colors.green }), + }, + { + name: "In Loss 14d EMA", + title: title("Sent In Loss 14d EMA"), + bottom: satsBtcUsd({ pattern: realized.sentInLoss14dEma, name: "14d EMA", color: colors.red }), + }, + ], + }, + ]; +} + +/** + * Create grouped realized P&L section for address cohorts (for compare view) + * @param {PartialContext} ctx + * @param {readonly AddressCohortObject[]} list + * @param {(metric: string) => string} title + * @returns {PartialOptionsTree} + */ +function createGroupedRealizedPnlSection(ctx, list, title) { + const pnlConfigs = /** @type {const} */ ([ + { name: "Profit", sum: "realizedProfit", ema: "realizedProfit7dEma", rel: "realizedProfitRelToRealizedCap", isNet: false }, + { name: "Loss", sum: "realizedLoss", ema: "realizedLoss7dEma", rel: "realizedLossRelToRealizedCap", isNet: false }, + { name: "Net P&L", sum: "netRealizedPnl", ema: "netRealizedPnl7dEma", rel: "netRealizedPnlRelToRealizedCap", isNet: true }, + ]); + + return [ + ...pnlConfigs.map(({ name, sum, ema, rel, isNet }) => ({ + name, + tree: [ + { + name: "Sum", + title: title(`Realized ${name}`), + bottom: [ + ...list.flatMap(({ color, name, tree }) => [ + (isNet ? baseline : line)({ metric: tree.realized[sum].sum, name, color, unit: Unit.usd }), + baseline({ metric: tree.realized[rel].sum, name, color, unit: Unit.pctRcap }), + ]), + priceLine({ ctx, unit: Unit.usd }), + ], + }, + { + name: "7d EMA", + title: title(`Realized ${name} 7d EMA`), + bottom: [ + ...list.map(({ color, name, tree }) => + (isNet ? baseline : line)({ metric: tree.realized[ema], name, color, unit: Unit.usd }), + ), + priceLine({ ctx, unit: Unit.usd }), + ], + }, + ], + })), + { + name: "Peak Regret", + tree: [ + { + name: "Sum", + title: title("Peak Regret"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.peakRegret.sum, name, color, unit: Unit.usd }), + ]), + }, + { + name: "Cumulative", + title: title("Peak Regret Cumulative"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.peakRegret.cumulative, name, color, unit: Unit.usd }), + ]), + }, + { + name: "Rel. to Realized Cap", + title: title("Peak Regret Rel. to Realized Cap"), + bottom: list.flatMap(({ color, name, tree }) => [ + baseline({ metric: tree.realized.peakRegretRelToRealizedCap, name, color, unit: Unit.pctRcap }), + ]), + }, + ], + }, + { + name: "Sent In P/L", + tree: [ + { + name: "In Profit", + title: title("Sent In Profit"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInProfit.bitcoin.sum, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInProfit.sats.sum, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInProfit.dollars.sum, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Profit Cumulative", + title: title("Sent In Profit Cumulative"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInProfit.bitcoin.cumulative, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInProfit.sats.cumulative, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInProfit.dollars.cumulative, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Loss", + title: title("Sent In Loss"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInLoss.bitcoin.sum, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInLoss.sats.sum, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInLoss.dollars.sum, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Loss Cumulative", + title: title("Sent In Loss Cumulative"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInLoss.bitcoin.cumulative, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInLoss.sats.cumulative, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInLoss.dollars.cumulative, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Profit 14d EMA", + title: title("Sent In Profit 14d EMA"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.realized.sentInProfit14dEma, name, color }), + ), + }, + { + name: "In Loss 14d EMA", + title: title("Sent In Loss 14d EMA"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.realized.sentInLoss14dEma, name, color }), + ), + }, + ], + }, ]; } @@ -620,6 +807,22 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { }), ]), }, + { + name: "Net Sentiment", + title: title("Net Sentiment"), + bottom: list.flatMap(({ color, name, tree }) => [ + baseline({ + metric: tree.unrealized.netSentiment, + name: useGroupName ? name : "Net Sentiment", + color: useGroupName ? color : undefined, + unit: Unit.usd, + }), + priceLine({ + ctx, + unit: Unit.usd, + }), + ]), + }, ], }, ]; @@ -715,19 +918,26 @@ function createActivitySection(args, title) { name: "Sent", tree: [ { - name: "Sats", - title: title("Sent (Sats)"), - bottom: createGroupedSentSatsSeries(list), + name: "Sum", + title: title("Sent"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ + pattern: { + sats: tree.activity.sent.sats.sum, + bitcoin: tree.activity.sent.bitcoin.sum, + dollars: tree.activity.sent.dollars.sum, + }, + name, + color, + }), + ), }, { - name: "Bitcoin", - title: title("Sent (BTC)"), - bottom: createGroupedSentBitcoinSeries(list), - }, - { - name: "Dollars", - title: title("Sent ($)"), - bottom: createGroupedSentDollarsSeries(list), + name: "14d EMA", + title: title("Sent 14d EMA"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.activity.sent14dEma, name, color }), + ), }, ], }, diff --git a/website/scripts/options/distribution/index.js b/website/scripts/options/distribution/index.js index ba22cae7e..4be0516d7 100644 --- a/website/scripts/options/distribution/index.js +++ b/website/scripts/options/distribution/index.js @@ -12,6 +12,7 @@ export { createCohortFolderWithAdjusted, createCohortFolderWithNupl, createCohortFolderAgeRange, + createCohortFolderMinAge, createCohortFolderBasicWithMarketCap, createCohortFolderBasicWithoutMarketCap, createCohortFolderWithoutRelative, diff --git a/website/scripts/options/distribution/shared.js b/website/scripts/options/distribution/shared.js index 291d7ade8..0fc79425b 100644 --- a/website/scripts/options/distribution/shared.js +++ b/website/scripts/options/distribution/shared.js @@ -125,6 +125,7 @@ function createSingleSupplySeriesBase(ctx, cohort) { return [ ...satsBtcUsd({ pattern: tree.supply.total, name: "Supply", color: colors.default }), + ...satsBtcUsd({ pattern: tree.supply._30dChange, name: "30d Change", color: colors.orange }), ...satsBtcUsd({ pattern: tree.unrealized.supplyInProfit, name: "In Profit", color: colors.green }), ...satsBtcUsd({ pattern: tree.unrealized.supplyInLoss, name: "In Loss", color: colors.red }), ...satsBtcUsd({ pattern: tree.supply.halved, name: "half", color: colors.gray }).map((s) => ({ @@ -261,6 +262,13 @@ export function createGroupedSupplySection(list, title, { supplyRelativeMetrics, title: title("Supply"), bottom: createGroupedSupplyTotalSeries(list, { relativeMetrics: supplyRelativeMetrics }), }, + { + name: "30d Change", + title: title("Supply 30d Change"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.supply._30dChange, name, color }), + ), + }, { name: "In Profit", title: title("Supply In Profit"), @@ -692,57 +700,10 @@ export function createSingleSentSeries(cohort) { unit: Unit.usd, defaultActive: false, }), + ...satsBtcUsd({ pattern: tree.activity.sent14dEma, name: "14d EMA" }), ]; } -/** - * Create sent (sats) series for grouped cohorts (comparison) - * @param {readonly CohortObject[]} list - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createGroupedSentSatsSeries(list) { - return list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.sent.sats.sum, - name, - color, - unit: Unit.sats, - }), - ]); -} - -/** - * Create sent (bitcoin) series for grouped cohorts (comparison) - * @param {readonly CohortObject[]} list - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createGroupedSentBitcoinSeries(list) { - return list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.sent.bitcoin.sum, - name, - color, - unit: Unit.btc, - }), - ]); -} - -/** - * Create sent (dollars) series for grouped cohorts (comparison) - * @param {readonly CohortObject[]} list - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createGroupedSentDollarsSeries(list) { - return list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.sent.dollars.sum, - name, - color, - unit: Unit.usd, - }), - ]); -} - // ============================================================================ // Sell Side Risk Ratio Helpers // ============================================================================ @@ -1036,11 +997,11 @@ export function createGroupedInvestorPriceFolder(list, title) { } // ============================================================================ -// ATH Regret Helpers +// Peak Regret Helpers // ============================================================================ /** - * Create realized ATH regret series for single cohort + * Create realized peak regret series for single cohort * @param {{ realized: AnyRealizedPattern }} tree * @param {Color} color * @returns {AnyFetchedSeriesBlueprint[]} @@ -1048,34 +1009,23 @@ export function createGroupedInvestorPriceFolder(list, title) { export function createSingleRealizedAthRegretSeries(tree, color) { return [ line({ - metric: tree.realized.athRegret.sum, - name: "ATH Regret", + metric: tree.realized.peakRegret.sum, + name: "Peak Regret", color, unit: Unit.usd, }), line({ - metric: tree.realized.athRegret.cumulative, + metric: tree.realized.peakRegret.cumulative, name: "Cumulative", color, unit: Unit.usd, defaultActive: false, }), - ]; -} - -/** - * Create unrealized ATH regret series for single cohort - * @param {{ unrealized: UnrealizedPattern }} tree - * @param {Color} color - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createSingleUnrealizedAthRegretSeries(tree, color) { - return [ - line({ - metric: tree.unrealized.athRegret, - name: "ATH Regret", + baseline({ + metric: tree.realized.peakRegretRelToRealizedCap, + name: "Rel. to Realized Cap", color, - unit: Unit.usd, + unit: Unit.pctRcap, }), ]; } @@ -1088,26 +1038,16 @@ export function createSingleUnrealizedAthRegretSeries(tree, color) { export function createGroupedRealizedAthRegretSeries(list) { return list.flatMap(({ color, name, tree }) => [ line({ - metric: tree.realized.athRegret.sum, + metric: tree.realized.peakRegret.sum, name, color, unit: Unit.usd, }), - ]); -} - -/** - * Create unrealized ATH regret series for grouped cohorts - * @param {readonly { color: Color, name: string, tree: { unrealized: UnrealizedPattern } }[]} list - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createGroupedUnrealizedAthRegretSeries(list) { - return list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.unrealized.athRegret, + baseline({ + metric: tree.realized.peakRegretRelToRealizedCap, name, color, - unit: Unit.usd, + unit: Unit.pctRcap, }), ]); } diff --git a/website/scripts/options/distribution/utxo.js b/website/scripts/options/distribution/utxo.js index 7c9b1f240..a18cd2cda 100644 --- a/website/scripts/options/distribution/utxo.js +++ b/website/scripts/options/distribution/utxo.js @@ -46,9 +46,7 @@ import { createInvestorPriceFolderBasic, createGroupedInvestorPriceFolder, createSingleRealizedAthRegretSeries, - createSingleUnrealizedAthRegretSeries, createGroupedRealizedAthRegretSeries, - createGroupedUnrealizedAthRegretSeries, createSingleSentimentSeries, createGroupedNetSentimentSeries, createGroupedGreedIndexSeries, @@ -57,6 +55,7 @@ import { import { createPriceRatioCharts, formatCohortTitle, + satsBtcUsd, } from "../shared.js"; import { Unit } from "../../utils/units.js"; import { line, baseline, price } from "../series.js"; @@ -67,7 +66,7 @@ import { priceLine } from "../constants.js"; // ============================================================================ /** - * All folder: for the special "All" cohort (adjustedSopr + percentiles but no RelToMarketCap) + * All folder: for the special "All" cohort (adjustedSopr + percentiles + RelToMarketCap) * @param {PartialContext} ctx * @param {CohortAll} args * @returns {PartialOptionsGroup} @@ -266,7 +265,52 @@ export function createCohortFolderAgeRange(ctx, args) { } /** - * Basic folder WITH RelToMarketCap (minAge.*, geAmount.*, ltAmount.*, type.*) + * MinAge folder - has peakRegret in unrealized (minAge.*) + * @param {PartialContext} ctx + * @param {CohortMinAge | CohortGroupMinAge} args + * @returns {PartialOptionsGroup} + */ +export function createCohortFolderMinAge(ctx, args) { + if ("list" in args) { + const { list } = args; + const title = formatCohortTitle(args.title); + return { + name: args.name || "all", + tree: [ + createGroupedSupplySection( + list, + title, + groupedSupplyRelativeGenerators, + ), + createGroupedUtxoCountChart(list, title), + createGroupedRealizedSectionBasic(ctx, list, title), + createGroupedUnrealizedSectionMinAge(ctx, list, title), + createGroupedCostBasisSection({ list, title }), + createGroupedActivitySection({ list, title }), + ], + }; + } + const title = formatCohortTitle(args.name); + return { + name: args.name || "all", + tree: [ + createSingleSupplyChart( + ctx, + args, + title, + createSingleSupplyRelativeOptions(ctx, args), + ), + createSingleUtxoCountChart(args, title), + createSingleRealizedSectionBasic(ctx, args, title), + createSingleUnrealizedSectionMinAge(ctx, args, title), + createCostBasisSection(ctx, { cohort: args, title }), + createActivitySection({ ctx, cohort: args, title }), + ], + }; +} + +/** + * Basic folder WITH RelToMarketCap (geAmount.*, ltAmount.*) * @param {PartialContext} ctx * @param {CohortBasicWithMarketCap | CohortGroupBasicWithMarketCap} args * @returns {PartialOptionsGroup} @@ -546,8 +590,8 @@ function createSingleRealizedSectionFull(ctx, cohort, title) { extra: createRealizedPnlRatioSeries(colors, tree), }), { - name: "ATH Regret", - title: title("Realized ATH Regret"), + name: "Peak Regret", + title: title("Realized Peak Regret"), bottom: createSingleRealizedAthRegretSeries(tree, color), }, createSingleSoprSectionWithAdjusted(ctx, cohort, title), @@ -576,8 +620,8 @@ function createSingleRealizedSectionWithAdjusted(ctx, cohort, title) { }, ...createSingleRealizedPnlSection(ctx, cohort, title), { - name: "ATH Regret", - title: title("Realized ATH Regret"), + name: "Peak Regret", + title: title("Realized Peak Regret"), bottom: createSingleRealizedAthRegretSeries(tree, color), }, createSingleSoprSectionWithAdjusted(ctx, cohort, title), @@ -622,8 +666,8 @@ function createGroupedRealizedSectionWithAdjusted( }, ...createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics }), { - name: "ATH Regret", - title: title("Realized ATH Regret"), + name: "Peak Regret", + title: title("Realized Peak Regret"), bottom: createGroupedRealizedAthRegretSeries(list), }, createGroupedSoprSectionWithAdjusted(list, title), @@ -657,8 +701,8 @@ function createSingleRealizedSectionWithPercentiles(ctx, cohort, title) { extra: createRealizedPnlRatioSeries(colors, tree), }), { - name: "ATH Regret", - title: title("Realized ATH Regret"), + name: "Peak Regret", + title: title("Realized Peak Regret"), bottom: createSingleRealizedAthRegretSeries(tree, color), }, createSingleSoprSectionBasic(ctx, cohort, title), @@ -687,8 +731,8 @@ function createSingleRealizedSectionBasic(ctx, cohort, title) { }, ...createSingleRealizedPnlSection(ctx, cohort, title), { - name: "ATH Regret", - title: title("Realized ATH Regret"), + name: "Peak Regret", + title: title("Realized Peak Regret"), bottom: createSingleRealizedAthRegretSeries(tree, color), }, createSingleSoprSectionBasic(ctx, cohort, title), @@ -733,8 +777,8 @@ function createGroupedRealizedSectionBasic( }, ...createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics }), { - name: "ATH Regret", - title: title("Realized ATH Regret"), + name: "Peak Regret", + title: title("Realized Peak Regret"), bottom: createGroupedRealizedAthRegretSeries(list), }, createGroupedSoprSectionBasic(list, title), @@ -953,12 +997,24 @@ function createSingleRealizedPnlSection( title: "Profit", sumColor: colors.green, }), + line({ + metric: tree.realized.realizedProfit7dEma, + name: "Profit 7d EMA", + color: colors.green, + unit: Unit.usd, + }), ...fromCountPattern({ pattern: tree.realized.realizedLoss, unit: Unit.usd, title: "Loss", sumColor: colors.red, }), + line({ + metric: tree.realized.realizedLoss7dEma, + name: "Loss 7d EMA", + color: colors.red, + unit: Unit.usd, + }), ...fromBitcoinPatternWithUnit({ pattern: tree.realized.negRealizedLoss, unit: Unit.usd, @@ -1013,6 +1069,11 @@ function createSingleRealizedPnlSection( unit: Unit.usd, title: "Net", }), + baseline({ + metric: tree.realized.netRealizedPnl7dEma, + name: "Net 7d EMA", + unit: Unit.usd, + }), baseline({ metric: tree.realized.netRealizedPnlCumulative30dDelta, name: "Cumulative 30d Change", @@ -1047,6 +1108,45 @@ function createSingleRealizedPnlSection( priceLine({ ctx, unit: Unit.usd }), ], }, + { + name: "Sent In P/L", + tree: [ + { + name: "In Profit", + title: title("Sent In Profit"), + bottom: [ + line({ metric: tree.realized.sentInProfit.bitcoin.sum, name: "Sum", color: colors.green, unit: Unit.btc }), + line({ metric: tree.realized.sentInProfit.bitcoin.cumulative, name: "Cumulative", color: colors.green, unit: Unit.btc, defaultActive: false }), + line({ metric: tree.realized.sentInProfit.sats.sum, name: "Sum", color: colors.green, unit: Unit.sats }), + line({ metric: tree.realized.sentInProfit.sats.cumulative, name: "Cumulative", color: colors.green, unit: Unit.sats, defaultActive: false }), + line({ metric: tree.realized.sentInProfit.dollars.sum, name: "Sum", color: colors.green, unit: Unit.usd }), + line({ metric: tree.realized.sentInProfit.dollars.cumulative, name: "Cumulative", color: colors.green, unit: Unit.usd, defaultActive: false }), + ], + }, + { + name: "In Loss", + title: title("Sent In Loss"), + bottom: [ + line({ metric: tree.realized.sentInLoss.bitcoin.sum, name: "Sum", color: colors.red, unit: Unit.btc }), + line({ metric: tree.realized.sentInLoss.bitcoin.cumulative, name: "Cumulative", color: colors.red, unit: Unit.btc, defaultActive: false }), + line({ metric: tree.realized.sentInLoss.sats.sum, name: "Sum", color: colors.red, unit: Unit.sats }), + line({ metric: tree.realized.sentInLoss.sats.cumulative, name: "Cumulative", color: colors.red, unit: Unit.sats, defaultActive: false }), + line({ metric: tree.realized.sentInLoss.dollars.sum, name: "Sum", color: colors.red, unit: Unit.usd }), + line({ metric: tree.realized.sentInLoss.dollars.cumulative, name: "Cumulative", color: colors.red, unit: Unit.usd, defaultActive: false }), + ], + }, + { + name: "In Profit 14d EMA", + title: title("Sent In Profit 14d EMA"), + bottom: satsBtcUsd({ pattern: tree.realized.sentInProfit14dEma, name: "14d EMA", color: colors.green }), + }, + { + name: "In Loss 14d EMA", + title: title("Sent In Loss 14d EMA"), + bottom: satsBtcUsd({ pattern: tree.realized.sentInLoss14dEma, name: "14d EMA", color: colors.red }), + }, + ], + }, ]; } @@ -1066,85 +1166,46 @@ function createGroupedRealizedPnlSections( title, { ratioMetrics } = {}, ) { + const pnlConfigs = /** @type {const} */ ([ + { name: "Profit", sum: "realizedProfit", ema: "realizedProfit7dEma", rel: "realizedProfitRelToRealizedCap", isNet: false }, + { name: "Loss", sum: "realizedLoss", ema: "realizedLoss7dEma", rel: "realizedLossRelToRealizedCap", isNet: false }, + { name: "Net P&L", sum: "netRealizedPnl", ema: "netRealizedPnl7dEma", rel: "netRealizedPnlRelToRealizedCap", isNet: true }, + ]); + return [ - { - name: "Profit", - title: title("Realized Profit"), - bottom: [ - ...list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.realizedProfit.sum, - name, - color, - unit: Unit.usd, - }), - baseline({ - metric: tree.realized.realizedProfitRelToRealizedCap.sum, - name, - color, - unit: Unit.pctRcap, - }), - ]), - priceLine({ ctx, unit: Unit.usd }), + ...pnlConfigs.map(({ name, sum, ema, rel, isNet }) => ({ + name, + tree: [ + { + name: "Sum", + title: title(`Realized ${name}`), + bottom: [ + ...list.flatMap(({ color, name, tree }) => [ + (isNet ? baseline : line)({ metric: tree.realized[sum].sum, name, color, unit: Unit.usd }), + baseline({ metric: tree.realized[rel].sum, name, color, unit: Unit.pctRcap }), + ]), + priceLine({ ctx, unit: Unit.usd }), + ], + }, + { + name: "7d EMA", + title: title(`Realized ${name} 7d EMA`), + bottom: [ + ...list.map(({ color, name, tree }) => + (isNet ? baseline : line)({ metric: tree.realized[ema], name, color, unit: Unit.usd }), + ), + priceLine({ ctx, unit: Unit.usd }), + ], + }, ], - }, - { - name: "Loss", - title: title("Realized Loss"), - bottom: [ - ...list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.realizedLoss.sum, - name, - color, - unit: Unit.usd, - }), - baseline({ - metric: tree.realized.realizedLossRelToRealizedCap.sum, - name, - color, - unit: Unit.pctRcap, - }), - ]), - priceLine({ ctx, unit: Unit.usd }), - ], - }, + })), { name: "Total P&L", title: title("Total Realized P&L"), - bottom: [ - ...list.flatMap((cohort) => [ - line({ - metric: cohort.tree.realized.totalRealizedPnl, - name: cohort.name, - color: cohort.color, - unit: Unit.usd, - }), - ...(ratioMetrics ? ratioMetrics(cohort) : []), - ]), - ], - }, - { - name: "Net P&L", - title: title("Net Realized P&L"), - bottom: [ - ...list.flatMap(({ color, name, tree }) => [ - baseline({ - metric: tree.realized.netRealizedPnl.sum, - name, - color, - unit: Unit.usd, - }), - baseline({ - metric: tree.realized.netRealizedPnlRelToRealizedCap.sum, - name, - color, - unit: Unit.pctRcap, - }), - ]), - priceLine({ ctx, unit: Unit.usd }), - priceLine({ ctx, unit: Unit.pctRcap }), - ], + bottom: list.flatMap((cohort) => [ + line({ metric: cohort.tree.realized.totalRealizedPnl, name: cohort.name, color: cohort.color, unit: Unit.usd }), + ...(ratioMetrics ? ratioMetrics(cohort) : []), + ]), }, { name: "Cumulative", @@ -1222,6 +1283,61 @@ function createGroupedRealizedPnlSections( }, ], }, + { + name: "Sent In P/L", + tree: [ + { + name: "In Profit", + title: title("Sent In Profit"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInProfit.bitcoin.sum, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInProfit.sats.sum, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInProfit.dollars.sum, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Profit Cumulative", + title: title("Sent In Profit Cumulative"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInProfit.bitcoin.cumulative, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInProfit.sats.cumulative, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInProfit.dollars.cumulative, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Loss", + title: title("Sent In Loss"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInLoss.bitcoin.sum, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInLoss.sats.sum, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInLoss.dollars.sum, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Loss Cumulative", + title: title("Sent In Loss Cumulative"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ metric: tree.realized.sentInLoss.bitcoin.cumulative, name, color, unit: Unit.btc }), + line({ metric: tree.realized.sentInLoss.sats.cumulative, name, color, unit: Unit.sats }), + line({ metric: tree.realized.sentInLoss.dollars.cumulative, name, color, unit: Unit.usd }), + ]), + }, + { + name: "In Profit 14d EMA", + title: title("Sent In Profit 14d EMA"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.realized.sentInProfit14dEma, name, color }), + ), + }, + { + name: "In Loss 14d EMA", + title: title("Sent In Loss 14d EMA"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.realized.sentInLoss14dEma, name, color }), + ), + }, + ], + }, ]; } @@ -1670,6 +1786,56 @@ function createNuplChart(ctx, rel, title) { }; } +/** + * Create peak regret chart (basic - just absolute value) + * @param {PartialContext} ctx + * @param {{ unrealized: UnrealizedFullPattern }} tree + * @param {(metric: string) => string} title + * @returns {PartialChartOption} + */ +function createPeakRegretChart(ctx, tree, title) { + return { + name: "Peak Regret", + title: title("Unrealized Peak Regret"), + bottom: [ + line({ + metric: tree.unrealized.peakRegret, + name: "Peak Regret", + color: ctx.colors.orange, + unit: Unit.usd, + }), + ], + }; +} + +/** + * Create peak regret chart with RelToMarketCap metric + * @param {PartialContext} ctx + * @param {{ unrealized: UnrealizedFullPattern, relative: RelativeWithMarketCap }} tree + * @param {(metric: string) => string} title + * @returns {PartialChartOption} + */ +function createPeakRegretChartWithMarketCap(ctx, tree, title) { + return { + name: "Peak Regret", + title: title("Unrealized Peak Regret"), + bottom: [ + line({ + metric: tree.unrealized.peakRegret, + name: "Peak Regret", + color: ctx.colors.orange, + unit: Unit.usd, + }), + baseline({ + metric: tree.relative.unrealizedPeakRegretRelToMarketCap, + name: "Peak Regret", + color: ctx.colors.orange, + unit: Unit.pctMcap, + }), + ], + }; +} + /** * Create invested capital absolute chart * @param {PartialContext} ctx @@ -1773,6 +1939,54 @@ function createGroupedNuplChart(ctx, list, title) { }; } +/** + * Create grouped peak regret chart (basic - no RelToMarketCap) + * @param {readonly { color: Color, name: string, tree: { unrealized: UnrealizedFullPattern } }[]} list + * @param {(metric: string) => string} title + * @returns {PartialChartOption} + */ +function createGroupedPeakRegretChartBasic(list, title) { + return { + name: "Peak Regret", + title: title("Unrealized Peak Regret"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.unrealized.peakRegret, + name, + color, + unit: Unit.usd, + }), + ]), + }; +} + +/** + * Create grouped peak regret chart with RelToMarketCap metric + * @param {readonly { color: Color, name: string, tree: { unrealized: UnrealizedFullPattern, relative: RelativeWithMarketCap } }[]} list + * @param {(metric: string) => string} title + * @returns {PartialChartOption} + */ +function createGroupedPeakRegretChart(list, title) { + return { + name: "Peak Regret", + title: title("Unrealized Peak Regret"), + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.unrealized.peakRegret, + name, + color, + unit: Unit.usd, + }), + baseline({ + metric: tree.relative.unrealizedPeakRegretRelToMarketCap, + name, + color, + unit: Unit.pctMcap, + }), + ]), + }; +} + // ============================================================================ // Unrealized Section Builder (generic, type-safe composition) // ============================================================================ @@ -1826,11 +2040,6 @@ function createUnrealizedSection({ title: title("Market Sentiment"), bottom: createSingleSentimentSeries(colors, tree), }, - { - name: "ATH Regret", - title: title("Unrealized ATH Regret"), - bottom: createSingleUnrealizedAthRegretSeries(tree, colors.orange), - }, ...charts, ], }; @@ -1968,11 +2177,6 @@ function createGroupedUnrealizedSection({ }, ], }, - { - name: "ATH Regret", - title: title("Unrealized ATH Regret"), - bottom: createGroupedUnrealizedAthRegretSeries(list), - }, ...charts, ], }; @@ -2025,11 +2229,6 @@ function createGroupedUnrealizedSectionWithoutRelative(list, title) { }, ], }, - { - name: "ATH Regret", - title: title("Unrealized ATH Regret"), - bottom: createGroupedUnrealizedAthRegretSeries(list), - }, ], }; } @@ -2050,9 +2249,21 @@ function createSingleUnrealizedSectionAll(ctx, cohort, title) { ctx, tree, title, - pnl: createUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative), - netPnl: createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative), + pnl: [ + ...createUnrealizedPnlRelToMarketCapMetrics(ctx, tree.relative), + ...createUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative), + priceLine({ ctx, unit: Unit.pctMcap, defaultActive: false }), + ], + netPnl: [ + ...createNetUnrealizedPnlRelToMarketCapMetrics(tree.relative), + ...createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative), + priceLine({ ctx, unit: Unit.pctMcap }), + ], investedCapitalFolder: createSingleInvestedCapitalFolderFull(ctx, tree, title), + charts: [ + createNuplChart(ctx, tree.relative, title), + createPeakRegretChartWithMarketCap(ctx, tree, title), + ], }); } @@ -2081,7 +2292,10 @@ function createSingleUnrealizedSectionFull(ctx, cohort, title) { priceLine({ ctx, unit: Unit.pctMcap }), ], investedCapitalFolder: createSingleInvestedCapitalFolderFull(ctx, tree, title), - charts: [createNuplChart(ctx, tree.relative, title)], + charts: [ + createNuplChart(ctx, tree.relative, title), + createPeakRegretChartWithMarketCap(ctx, tree, title), + ], }); } @@ -2106,7 +2320,10 @@ function createSingleUnrealizedSectionWithMarketCap(ctx, cohort, title) { priceLine({ ctx, unit: Unit.pctMcap }), ], investedCapitalFolder: createSingleInvestedCapitalFolderFull(ctx, tree, title), - charts: [createNuplChart(ctx, tree.relative, title)], + charts: [ + createNuplChart(ctx, tree.relative, title), + createPeakRegretChartWithMarketCap(ctx, tree, title), + ], }); } @@ -2135,6 +2352,34 @@ function createSingleUnrealizedSectionWithMarketCapOnly(ctx, cohort, title) { }); } +/** + * Unrealized section for minAge cohorts (has peakRegret) + * @param {PartialContext} ctx + * @param {CohortMinAge} cohort + * @param {(metric: string) => string} title + */ +function createSingleUnrealizedSectionMinAge(ctx, cohort, title) { + const { tree } = cohort; + return createUnrealizedSection({ + ctx, + tree, + title, + pnl: [ + ...createUnrealizedPnlRelToMarketCapMetrics(ctx, tree.relative), + priceLine({ ctx, unit: Unit.pctMcap, defaultActive: false }), + ], + netPnl: [ + ...createNetUnrealizedPnlRelToMarketCapMetrics(tree.relative), + priceLine({ ctx, unit: Unit.pctMcap }), + ], + investedCapitalFolder: createSingleInvestedCapitalFolderFull(ctx, tree, title), + charts: [ + createNuplChart(ctx, tree.relative, title), + createPeakRegretChartWithMarketCap(ctx, tree, title), + ], + }); +} + /** * Unrealized section with only base metrics (no RelToMarketCap) * @param {PartialContext} ctx @@ -2169,7 +2414,7 @@ function createSingleUnrealizedSectionWithoutRelative(ctx, cohort, title) { /** * Grouped unrealized base charts (profit, loss, total pnl) - * @param {readonly { color: Color, name: string, tree: { unrealized: PatternAll["unrealized"] } }[]} list + * @param {readonly { color: Color, name: string, tree: { unrealized: UnrealizedPattern } }[]} list * @param {(metric: string) => string} title */ function createGroupedUnrealizedBaseCharts(list, title) { @@ -2243,7 +2488,10 @@ function createGroupedUnrealizedSectionFull(ctx, list, title) { unit: Unit.pctOwnPnl, }), ], - charts: [createGroupedNuplChart(ctx, list, title)], + charts: [ + createGroupedNuplChart(ctx, list, title), + createGroupedPeakRegretChart(list, title), + ], }); } @@ -2265,7 +2513,10 @@ function createGroupedUnrealizedSectionWithMarketCap(ctx, list, title) { unit: Unit.pctMcap, }), ], - charts: [createGroupedNuplChart(ctx, list, title)], + charts: [ + createGroupedNuplChart(ctx, list, title), + createGroupedPeakRegretChart(list, title), + ], }); } @@ -2291,6 +2542,31 @@ function createGroupedUnrealizedSectionWithMarketCapOnly(ctx, list, title) { }); } +/** + * Grouped unrealized section for minAge cohorts (has peakRegret) + * @param {PartialContext} ctx + * @param {readonly CohortMinAge[]} list + * @param {(metric: string) => string} title + */ +function createGroupedUnrealizedSectionMinAge(ctx, list, title) { + return createGroupedUnrealizedSection({ + list, + title, + netPnlMetrics: ({ color, name, tree }) => [ + baseline({ + metric: tree.relative.netUnrealizedPnlRelToMarketCap, + name, + color, + unit: Unit.pctMcap, + }), + ], + charts: [ + createGroupedNuplChart(ctx, list, title), + createGroupedPeakRegretChart(list, title), + ], + }); +} + /** * Grouped unrealized section without RelToMarketCap (for CohortBasicWithoutMarketCap) * @param {readonly CohortBasicWithoutMarketCap[]} list @@ -2324,7 +2600,10 @@ function createSingleUnrealizedSectionWithNupl({ ctx, cohort, title }) { ...createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative), ], investedCapitalFolder: createSingleInvestedCapitalFolderFull(ctx, tree, title), - charts: [createNuplChart(ctx, tree.relative, title)], + charts: [ + createNuplChart(ctx, tree.relative, title), + createPeakRegretChartWithMarketCap(ctx, tree, title), + ], }); } @@ -2359,7 +2638,10 @@ function createGroupedUnrealizedSectionWithNupl({ ctx, list, title }) { unit: Unit.pctOwnPnl, }), ], - charts: [createGroupedNuplChart(ctx, list, title)], + charts: [ + createGroupedNuplChart(ctx, list, title), + createGroupedPeakRegretChart(list, title), + ], }); } @@ -2384,6 +2666,7 @@ function createSingleUnrealizedSectionAgeRange(ctx, cohort, title) { ...createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative), ], investedCapitalFolder: createSingleInvestedCapitalFolderFull(ctx, tree, title), + charts: [createPeakRegretChart(ctx, tree, title)], }); } @@ -2410,6 +2693,7 @@ function createGroupedUnrealizedSectionAgeRange(list, title) { unit: Unit.pctOwnPnl, }), ], + charts: [createGroupedPeakRegretChartBasic(list, title)], }); } @@ -2632,6 +2916,21 @@ function createActivitySection({ ctx, cohort, title, valueMetrics = [] }) { unit: Unit.usd, sumColor: color, }), + line({ + metric: tree.activity.sent14dEma.sats, + name: "14d EMA", + unit: Unit.sats, + }), + line({ + metric: tree.activity.sent14dEma.bitcoin, + name: "14d EMA", + unit: Unit.btc, + }), + line({ + metric: tree.activity.sent14dEma.dollars, + name: "14d EMA", + unit: Unit.usd, + }), ], }, { @@ -2768,6 +3067,33 @@ function createGroupedActivitySection({ list, title, valueTree }) { return { name: "Activity", tree: [ + { + name: "Sent", + tree: [ + { + name: "Sum", + title: title("Sent"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ + pattern: { + sats: tree.activity.sent.sats.sum, + bitcoin: tree.activity.sent.bitcoin.sum, + dollars: tree.activity.sent.dollars.sum, + }, + name, + color, + }), + ), + }, + { + name: "14d EMA", + title: title("Sent 14d EMA"), + bottom: list.flatMap(({ color, name, tree }) => + satsBtcUsd({ pattern: tree.activity.sent14dEma, name, color }), + ), + }, + ], + }, { name: "Sell Side Risk", title: title("Sell Side Risk Ratio"), diff --git a/website/scripts/options/full.js b/website/scripts/options/full.js index cfc69d274..bcd2289c3 100644 --- a/website/scripts/options/full.js +++ b/website/scripts/options/full.js @@ -3,7 +3,8 @@ import { createButtonElement, createAnchorElement } from "../utils/dom.js"; import { pushHistory, resetParams } from "../utils/url.js"; import { readStored, writeToStorage } from "../utils/storage.js"; import { stringToId } from "../utils/format.js"; -import { collect, markUsed, logUnused } from "./unused.js"; +import { collect, markUsed, logUnused, extractTreeStructure } from "./unused.js"; +import { localhost } from "../utils/env.js"; import { setQr } from "../panes/share.js"; import { getConstant } from "./constants.js"; import { colors } from "../chart/colors.js"; @@ -29,6 +30,11 @@ export function initOptions(brk) { brk, }); + // Log tree structure for analysis (localhost only) + if (localhost) { + console.log(extractTreeStructure(partialOptions)); + } + /** @type {Option[]} */ const list = []; diff --git a/website/scripts/options/partial.js b/website/scripts/options/partial.js index 0dfcecc42..39dde3e77 100644 --- a/website/scripts/options/partial.js +++ b/website/scripts/options/partial.js @@ -8,6 +8,7 @@ import { createCohortFolderWithAdjusted, createCohortFolderWithNupl, createCohortFolderAgeRange, + createCohortFolderMinAge, createCohortFolderBasicWithMarketCap, createCohortFolderBasicWithoutMarketCap, createCohortFolderWithoutRelative, @@ -62,6 +63,8 @@ export function createPartialOptions({ brk }) { /** @param {CohortBasicWithMarketCap} cohort */ const mapBasicWithMarketCap = (cohort) => createCohortFolderBasicWithMarketCap(ctx, cohort); + /** @param {CohortMinAge} cohort */ + const mapMinAge = (cohort) => createCohortFolderMinAge(ctx, cohort); /** @param {CohortBasicWithoutMarketCap} cohort */ const mapBasicWithoutMarketCap = (cohort) => createCohortFolderBasicWithoutMarketCap(ctx, cohort); @@ -135,12 +138,12 @@ export function createPartialOptions({ brk }) { { name: "Older Than", tree: [ - createCohortFolderBasicWithMarketCap(ctx, { + createCohortFolderMinAge(ctx, { name: "Compare", title: "Min Age", list: fromDate, }), - ...fromDate.map(mapBasicWithMarketCap), + ...fromDate.map(mapMinAge), ], }, // Range diff --git a/website/scripts/options/types.js b/website/scripts/options/types.js index 4ac7f9b2d..1ef3eb117 100644 --- a/website/scripts/options/types.js +++ b/website/scripts/options/types.js @@ -214,13 +214,20 @@ * @property {Color} color * @property {AgeRangePattern} tree * - * Basic cohort WITH RelToMarketCap (minAge.*, geAmount.*, ltAmount.*) + * Basic cohort WITH RelToMarketCap (geAmount.*, ltAmount.*) * @typedef {Object} CohortBasicWithMarketCap * @property {string} name * @property {string} title * @property {Color} color * @property {PatternBasicWithMarketCap} tree * + * MinAge cohort - has peakRegret in unrealized (minAge.*) + * @typedef {Object} CohortMinAge + * @property {string} name + * @property {string} title + * @property {Color} color + * @property {MinAgePattern} tree + * * Basic cohort WITHOUT RelToMarketCap (epoch.*, amountRange.*, year.*, type.*) * @typedef {Object} CohortBasicWithoutMarketCap * @property {string} name @@ -279,6 +286,11 @@ * @property {string} title * @property {readonly CohortBasicWithMarketCap[]} list * + * @typedef {Object} CohortGroupMinAge + * @property {string} name + * @property {string} title + * @property {readonly CohortMinAge[]} list + * * @typedef {Object} CohortGroupBasicWithoutMarketCap * @property {string} name * @property {string} title diff --git a/website/scripts/options/unused.js b/website/scripts/options/unused.js index 292544b9f..c866f9585 100644 --- a/website/scripts/options/unused.js +++ b/website/scripts/options/unused.js @@ -52,16 +52,6 @@ function walk(node, map, path) { (kn.startsWith("_") && kn.endsWith("start")) ) continue; - // if ( - // kn === "mvrv" || - // kn.endsWith("index") || - // kn.endsWith("indexes") || - // kn.endsWith("start") || - // kn.endsWith("hash") || - // kn.endsWith("data") || - // kn.endsWith("constants") - // ) - // return; walk(/** @type {TreeNode | null | undefined} */ (value), map, [ ...path, key, @@ -108,3 +98,82 @@ export function logUnused() { console.log("Unused metrics:", { count: unused.size, tree }); } + +/** + * Extract tree structure from partial options (names + hierarchy, series grouped by unit) + * @param {PartialOptionsTree} options + * @returns {object[]} + */ +export function extractTreeStructure(options) { + /** + * Group series by unit + * @param {(AnyFetchedSeriesBlueprint | FetchedPriceSeriesBlueprint)[]} series + * @param {boolean} isTop + * @returns {Record} + */ + function groupByUnit(series, isTop) { + /** @type {Record} */ + const grouped = {}; + for (const s of series) { + // Price patterns in top pane have dollars/sats sub-metrics + const metric = /** @type {any} */ (s.metric); + if (isTop && metric?.dollars && metric?.sats) { + const title = s.title || s.key || "unnamed"; + (grouped["USD"] ??= []).push(title); + (grouped["sats"] ??= []).push(title); + } else { + const unit = /** @type {AnyFetchedSeriesBlueprint} */ (s).unit; + const unitName = unit?.name || "unknown"; + const title = s.title || s.key || "unnamed"; + (grouped[unitName] ??= []).push(title); + } + } + return grouped; + } + + /** + * @param {AnyPartialOption | PartialOptionsGroup} node + * @returns {object} + */ + function processNode(node) { + // Group with children + if ("tree" in node && node.tree) { + return { + name: node.name, + children: node.tree.map(processNode), + }; + } + // Chart option + if ("top" in node || "bottom" in node) { + const chartNode = /** @type {PartialChartOption} */ (node); + const top = chartNode.top ? groupByUnit(chartNode.top, true) : undefined; + const bottom = chartNode.bottom + ? groupByUnit(chartNode.bottom, false) + : undefined; + return { + name: node.name, + title: chartNode.title, + ...(top && Object.keys(top).length > 0 ? { top } : {}), + ...(bottom && Object.keys(bottom).length > 0 ? { bottom } : {}), + }; + } + // URL option + if ("url" in node) { + return { name: node.name, url: true }; + } + // Other options (explorer, table, simulation) + return { name: node.name }; + } + + return options.map(processNode); +} + +/** + * Log the options tree structure to console (localhost only) + * @param {PartialOptionsTree} options + */ +export function logTreeStructure(options) { + if (!localhost) return; + const structure = extractTreeStructure(options); + console.log("Options tree structure:", JSON.stringify(structure, null, 2)); +} diff --git a/website/scripts/panes/chart.js b/website/scripts/panes/chart.js index 03da5ee05..ae271f13d 100644 --- a/website/scripts/panes/chart.js +++ b/website/scripts/panes/chart.js @@ -103,6 +103,7 @@ export function init(brk) { setChoices(computeChoices(opt)); blueprints = chart.setBlueprints({ + name: opt.title, top: buildTopBlueprints(opt.top), bottom: opt.bottom, onDataLoaded: updatePriceWithLatest, diff --git a/website/scripts/types.js b/website/scripts/types.js index ae527eb04..019b42c14 100644 --- a/website/scripts/types.js +++ b/website/scripts/types.js @@ -14,7 +14,7 @@ * * @import { WebSockets } from "./utils/ws.js" * - * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, PatternBasicWithMarketCap, PatternBasicWithoutMarketCap, PatternWithoutRelative, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortBasicWithMarketCap, CohortBasicWithoutMarketCap, CohortWithoutRelative, CohortAddress, CohortLongTerm, CohortAgeRange, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupLongTerm, CohortGroupAgeRange, CohortGroupBasic, CohortGroupBasicWithMarketCap, CohortGroupBasicWithoutMarketCap, CohortGroupWithoutRelative, CohortGroupAddress, UtxoCohortGroupObject, AddressCohortGroupObject, FetchedDotsSeriesBlueprint, FetchedCandlestickSeriesBlueprint, FetchedPriceSeriesBlueprint, AnyPricePattern } from "./options/partial.js" + * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, PatternBasicWithMarketCap, PatternBasicWithoutMarketCap, PatternWithoutRelative, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortBasicWithMarketCap, CohortBasicWithoutMarketCap, CohortWithoutRelative, CohortAddress, CohortLongTerm, CohortAgeRange, CohortMinAge, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupLongTerm, CohortGroupAgeRange, CohortGroupBasic, CohortGroupBasicWithMarketCap, CohortGroupBasicWithoutMarketCap, CohortGroupWithoutRelative, CohortGroupMinAge, CohortGroupAddress, UtxoCohortGroupObject, AddressCohortGroupObject, FetchedDotsSeriesBlueprint, FetchedCandlestickSeriesBlueprint, FetchedPriceSeriesBlueprint, AnyPricePattern } from "./options/partial.js" * * * @import { UnitObject as Unit } from "./utils/units.js" @@ -49,6 +49,8 @@ * @typedef {Brk.ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3} UtxoAmountPattern * @typedef {Brk.ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern} AddressAmountPattern * @typedef {Brk.ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4} BasicUtxoPattern + * MinAgePattern: minAge cohorts have peakRegret in unrealized (Pattern6) + * @typedef {Brk.ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern6} MinAgePattern * @typedef {Brk.ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3} EpochPattern * @typedef {Brk.ActivityCostOutputsRealizedSupplyUnrealizedPattern} EmptyPattern * @typedef {Brk._0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern} Ratio1ySdPattern @@ -75,13 +77,14 @@ * @typedef {Brk.InvestedNegNetNuplSupplyUnrealizedPattern} GlobalRelativePattern * @typedef {Brk.InvestedNegNetSupplyUnrealizedPattern} OwnRelativePattern * @typedef {Brk.InvestedNegNetNuplSupplyUnrealizedPattern2} FullRelativePattern - * @typedef {Brk.AthGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} UnrealizedPattern + * @typedef {Brk.GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern} UnrealizedPattern + * @typedef {Brk.GreedInvestedInvestorNegNetPainPeakSupplyTotalUnrealizedPattern} UnrealizedFullPattern * * Realized patterns - * @typedef {Brk.AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} RealizedPattern - * @typedef {Brk.AthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} RealizedPattern2 - * @typedef {Brk.AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern} RealizedPattern3 - * @typedef {Brk.AdjustedAthCapCapitulationInvestorLossMvrvNegNetProfitRealizedSellSoprTotalValuePattern2} RealizedPattern4 + * @typedef {Brk.CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSoprTotalValuePattern} RealizedPattern + * @typedef {Brk.CapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSoprTotalValuePattern2} RealizedPattern2 + * @typedef {Brk.AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSoprTotalValuePattern} RealizedPattern3 + * @typedef {Brk.AdjustedCapCapitulationInvestorLossMvrvNegNetPeakProfitRealizedSellSoprTotalValuePattern2} RealizedPattern4 */ /**