global: snap

This commit is contained in:
nym21
2026-04-17 21:23:11 +02:00
parent 008143ff00
commit 2a93f51e81
47 changed files with 2075 additions and 389 deletions

8
Cargo.lock generated
View File

@@ -2453,9 +2453,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.5" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha", "rand_chacha",
@@ -3100,9 +3100,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.52.0" version = "1.52.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776" checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
dependencies = [ dependencies = [
"libc", "libc",
"mio", "mio",

View File

@@ -84,7 +84,7 @@ serde_bytes = "0.11.19"
serde_derive = "1.0.228" serde_derive = "1.0.228"
serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_order"] } serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_order"] }
smallvec = "1.15.1" smallvec = "1.15.1"
tokio = { version = "1.52.0", features = ["rt-multi-thread"] } tokio = { version = "1.52.1", features = ["rt-multi-thread"] }
tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] } tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] }
tower-layer = "0.3" tower-layer = "0.3"
tracing = { version = "0.1", default-features = false, features = ["std"] } tracing = { version = "0.1", default-features = false, features = ["std"] }

View File

@@ -3,7 +3,10 @@
//! This module detects repeating tree structures and analyzes them //! This module detects repeating tree structures and analyzes them
//! using the bottom-up name deconstruction algorithm. //! using the bottom-up name deconstruction algorithm.
use std::collections::{BTreeMap, BTreeSet}; use std::{
cmp::Reverse,
collections::{BTreeMap, BTreeSet},
};
use brk_types::{TreeNode, extract_json_type}; use brk_types::{TreeNode, extract_json_type};
@@ -111,7 +114,7 @@ pub fn detect_structural_patterns(
// Also collects node bases for each tree path // Also collects node bases for each tree path
let node_bases = analyze_pattern_modes(tree, &mut patterns, &pattern_lookup); let node_bases = analyze_pattern_modes(tree, &mut patterns, &pattern_lookup);
patterns.sort_by(|a, b| b.fields.len().cmp(&a.fields.len())); patterns.sort_by_key(|p| Reverse(p.fields.len()));
(patterns, concrete_to_pattern, type_mappings, node_bases) (patterns, concrete_to_pattern, type_mappings, node_bases)
} }

View File

@@ -31,7 +31,7 @@ impl ClientConstants {
let pools = pools(); let pools = pools();
let mut sorted_pools: Vec<_> = pools.iter().collect(); let mut sorted_pools: Vec<_> = pools.iter().collect();
sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); sorted_pools.sort_by_key(|p| p.name.to_lowercase());
let pool_map: BTreeMap<PoolSlug, &'static str> = let pool_map: BTreeMap<PoolSlug, &'static str> =
sorted_pools.iter().map(|p| (p.slug(), p.name)).collect(); sorted_pools.iter().map(|p| (p.slug(), p.name)).collect();

View File

@@ -1310,7 +1310,7 @@ impl IndexPct0Pct1Pct2Pct5Pct95Pct98Pct99ScorePattern {
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 { pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
pub all: AverageBlockCumulativeSumPattern<StoredU64>, pub all: AverageBlockCumulativeSumPattern<StoredU64>,
pub p2a: AverageBlockCumulativeSumPattern<StoredU64>, pub p2a: AverageBlockCumulativeSumPattern<StoredU64>,
pub p2pk33: AverageBlockCumulativeSumPattern<StoredU64>, pub p2pk33: AverageBlockCumulativeSumPattern<StoredU64>,
@@ -1322,7 +1322,7 @@ pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 {
pub p2wsh: AverageBlockCumulativeSumPattern<StoredU64>, pub p2wsh: AverageBlockCumulativeSumPattern<StoredU64>,
} }
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 { impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
@@ -1340,7 +1340,7 @@ impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 {
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 { pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 {
pub all: SeriesPattern1<StoredU64>, pub all: SeriesPattern1<StoredU64>,
pub p2a: SeriesPattern1<StoredU64>, pub p2a: SeriesPattern1<StoredU64>,
pub p2pk33: SeriesPattern1<StoredU64>, pub p2pk33: SeriesPattern1<StoredU64>,
@@ -1352,7 +1352,7 @@ pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 {
pub p2wsh: SeriesPattern1<StoredU64>, pub p2wsh: SeriesPattern1<StoredU64>,
} }
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 { impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
@@ -1370,7 +1370,7 @@ impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 {
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 { pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 {
pub all: _1m1w1y24hBpsPercentRatioPattern, pub all: _1m1w1y24hBpsPercentRatioPattern,
pub p2a: _1m1w1y24hBpsPercentRatioPattern, pub p2a: _1m1w1y24hBpsPercentRatioPattern,
pub p2pk33: _1m1w1y24hBpsPercentRatioPattern, pub p2pk33: _1m1w1y24hBpsPercentRatioPattern,
@@ -1382,7 +1382,7 @@ pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
pub p2wsh: _1m1w1y24hBpsPercentRatioPattern, pub p2wsh: _1m1w1y24hBpsPercentRatioPattern,
} }
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 { impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
@@ -1434,7 +1434,7 @@ pub struct CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 {
pub capitalized_cap_in_loss_raw: SeriesPattern18<CentsSquaredSats>, pub capitalized_cap_in_loss_raw: SeriesPattern18<CentsSquaredSats>,
pub capitalized_cap_in_profit_raw: SeriesPattern18<CentsSquaredSats>, pub capitalized_cap_in_profit_raw: SeriesPattern18<CentsSquaredSats>,
pub gross_pnl: CentsUsdPattern3, pub gross_pnl: CentsUsdPattern3,
pub invested_capital: InPattern, pub invested_capital: InPattern2,
pub loss: CentsNegativeToUsdPattern2, pub loss: CentsNegativeToUsdPattern2,
pub net_pnl: CentsToUsdPattern3, pub net_pnl: CentsToUsdPattern3,
pub nupl: BpsRatioPattern, pub nupl: BpsRatioPattern,
@@ -1449,7 +1449,7 @@ impl CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 {
capitalized_cap_in_loss_raw: SeriesPattern18::new(client.clone(), _m(&acc, "capitalized_cap_in_loss_raw")), capitalized_cap_in_loss_raw: SeriesPattern18::new(client.clone(), _m(&acc, "capitalized_cap_in_loss_raw")),
capitalized_cap_in_profit_raw: SeriesPattern18::new(client.clone(), _m(&acc, "capitalized_cap_in_profit_raw")), capitalized_cap_in_profit_raw: SeriesPattern18::new(client.clone(), _m(&acc, "capitalized_cap_in_profit_raw")),
gross_pnl: CentsUsdPattern3::new(client.clone(), _m(&acc, "unrealized_gross_pnl")), gross_pnl: CentsUsdPattern3::new(client.clone(), _m(&acc, "unrealized_gross_pnl")),
invested_capital: InPattern::new(client.clone(), _m(&acc, "invested_capital_in")), invested_capital: InPattern2::new(client.clone(), _m(&acc, "invested_capital_in")),
loss: CentsNegativeToUsdPattern2::new(client.clone(), _m(&acc, "unrealized_loss")), loss: CentsNegativeToUsdPattern2::new(client.clone(), _m(&acc, "unrealized_loss")),
net_pnl: CentsToUsdPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl")), net_pnl: CentsToUsdPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl")),
nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")), nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")),
@@ -1960,7 +1960,7 @@ impl ActivityOutputsRealizedSupplyUnrealizedPattern2 {
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct BlockChangeCumulativeDeltaSumPattern { pub struct BlockChangeCumulativeDeltaSumPattern {
pub block: CentsUsdPattern4, pub block: CentsUsdPattern4,
pub change_1m: ToPattern, pub change_1m: ToPattern2,
pub cumulative: CentsUsdPattern, pub cumulative: CentsUsdPattern,
pub delta: AbsoluteRatePattern2, pub delta: AbsoluteRatePattern2,
pub sum: _1m1w1y24hPattern5, pub sum: _1m1w1y24hPattern5,
@@ -1971,7 +1971,7 @@ impl BlockChangeCumulativeDeltaSumPattern {
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
block: CentsUsdPattern4::new(client.clone(), _m(&acc, "realized_pnl")), block: CentsUsdPattern4::new(client.clone(), _m(&acc, "realized_pnl")),
change_1m: ToPattern::new(client.clone(), _m(&acc, "pnl_change_1m_to")), change_1m: ToPattern2::new(client.clone(), _m(&acc, "pnl_change_1m_to")),
cumulative: CentsUsdPattern::new(client.clone(), _m(&acc, "realized_pnl_cumulative")), cumulative: CentsUsdPattern::new(client.clone(), _m(&acc, "realized_pnl_cumulative")),
delta: AbsoluteRatePattern2::new(client.clone(), _m(&acc, "realized_pnl_delta")), delta: AbsoluteRatePattern2::new(client.clone(), _m(&acc, "realized_pnl_delta")),
sum: _1m1w1y24hPattern5::new(client.clone(), _m(&acc, "realized_pnl_sum")), sum: _1m1w1y24hPattern5::new(client.clone(), _m(&acc, "realized_pnl_sum")),
@@ -2966,6 +2966,22 @@ impl AbsoluteRatePattern2 {
} }
} }
/// Pattern struct for repeated tree structure.
pub struct AddrUtxoPattern {
pub addr: BtcCentsSatsUsdPattern,
pub utxo: BtcCentsSatsUsdPattern,
}
impl AddrUtxoPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
addr: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "addr_amount")),
utxo: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "utxo_amount")),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct AllSthPattern2 { pub struct AllSthPattern2 {
pub all: BtcCentsDeltaSatsUsdPattern, pub all: BtcCentsDeltaSatsUsdPattern,
@@ -3192,32 +3208,48 @@ impl DeltaTotalPattern {
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct FundedTotalPattern { pub struct FundedTotalPattern {
pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3, pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3, pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
} }
impl FundedTotalPattern { impl FundedTotalPattern {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), acc.clone()), funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), acc.clone()),
total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), _p("total", &acc)), total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), _p("total", &acc)),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct InPattern2 {
pub in_loss: CentsUsdPattern3,
pub in_profit: CentsUsdPattern3,
}
impl InPattern2 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
in_loss: CentsUsdPattern3::new(client.clone(), _m(&acc, "loss")),
in_profit: CentsUsdPattern3::new(client.clone(), _m(&acc, "profit")),
} }
} }
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct InPattern { pub struct InPattern {
pub in_loss: CentsUsdPattern3, pub in_loss: ToPattern,
pub in_profit: CentsUsdPattern3, pub in_profit: ToPattern,
} }
impl InPattern { impl InPattern {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
in_loss: CentsUsdPattern3::new(client.clone(), _m(&acc, "loss")), in_loss: ToPattern::new(client.clone(), _m(&acc, "loss_to_own")),
in_profit: CentsUsdPattern3::new(client.clone(), _m(&acc, "profit")), in_profit: ToPattern::new(client.clone(), _m(&acc, "profit_to_own")),
} }
} }
} }
@@ -3277,12 +3309,12 @@ pub struct SdSmaPattern {
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct ToPattern { pub struct ToPattern2 {
pub to_mcap: BpsPercentRatioPattern, pub to_mcap: BpsPercentRatioPattern,
pub to_rcap: BpsPercentRatioPattern, pub to_rcap: BpsPercentRatioPattern,
} }
impl ToPattern { impl ToPattern2 {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
@@ -3334,6 +3366,20 @@ impl PricePattern {
} }
} }
/// Pattern struct for repeated tree structure.
pub struct ToPattern {
pub to_own: BpsPercentRatioPattern2,
}
impl ToPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
to_own: BpsPercentRatioPattern2::new(client.clone(), acc.clone()),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct TransferPattern { pub struct TransferPattern {
pub transfer_volume: AverageBlockCumulativeSumPattern3, pub transfer_volume: AverageBlockCumulativeSumPattern3,
@@ -4197,14 +4243,15 @@ pub struct SeriesTree_Addrs {
pub raw: SeriesTree_Addrs_Raw, pub raw: SeriesTree_Addrs_Raw,
pub indexes: SeriesTree_Addrs_Indexes, pub indexes: SeriesTree_Addrs_Indexes,
pub data: SeriesTree_Addrs_Data, pub data: SeriesTree_Addrs_Data,
pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3, pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3, pub empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub activity: SeriesTree_Addrs_Activity, pub activity: SeriesTree_Addrs_Activity,
pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3, pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5, pub new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub reused: SeriesTree_Addrs_Reused, pub reused: SeriesTree_Addrs_Reused,
pub exposed: SeriesTree_Addrs_Exposed, pub exposed: SeriesTree_Addrs_Exposed,
pub delta: SeriesTree_Addrs_Delta, pub delta: SeriesTree_Addrs_Delta,
pub avg_amount: SeriesTree_Addrs_AvgAmount,
} }
impl SeriesTree_Addrs { impl SeriesTree_Addrs {
@@ -4213,14 +4260,15 @@ impl SeriesTree_Addrs {
raw: SeriesTree_Addrs_Raw::new(client.clone(), format!("{base_path}_raw")), raw: SeriesTree_Addrs_Raw::new(client.clone(), format!("{base_path}_raw")),
indexes: SeriesTree_Addrs_Indexes::new(client.clone(), format!("{base_path}_indexes")), indexes: SeriesTree_Addrs_Indexes::new(client.clone(), format!("{base_path}_indexes")),
data: SeriesTree_Addrs_Data::new(client.clone(), format!("{base_path}_data")), data: SeriesTree_Addrs_Data::new(client.clone(), format!("{base_path}_data")),
funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), "addr_count".to_string()), funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), "addr_count".to_string()),
empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), "empty_addr_count".to_string()), empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), "empty_addr_count".to_string()),
activity: SeriesTree_Addrs_Activity::new(client.clone(), format!("{base_path}_activity")), activity: SeriesTree_Addrs_Activity::new(client.clone(), format!("{base_path}_activity")),
total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), "total_addr_count".to_string()), total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), "total_addr_count".to_string()),
new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5::new(client.clone(), "new_addr_count".to_string()), new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "new_addr_count".to_string()),
reused: SeriesTree_Addrs_Reused::new(client.clone(), format!("{base_path}_reused")), reused: SeriesTree_Addrs_Reused::new(client.clone(), format!("{base_path}_reused")),
exposed: SeriesTree_Addrs_Exposed::new(client.clone(), format!("{base_path}_exposed")), exposed: SeriesTree_Addrs_Exposed::new(client.clone(), format!("{base_path}_exposed")),
delta: SeriesTree_Addrs_Delta::new(client.clone(), format!("{base_path}_delta")), delta: SeriesTree_Addrs_Delta::new(client.clone(), format!("{base_path}_delta")),
avg_amount: SeriesTree_Addrs_AvgAmount::new(client.clone(), format!("{base_path}_avg_amount")),
} }
} }
} }
@@ -4485,11 +4533,11 @@ impl SeriesTree_Addrs_Reused {
/// Series tree node. /// Series tree node.
pub struct SeriesTree_Addrs_Reused_Events { pub struct SeriesTree_Addrs_Reused_Events {
pub output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5, pub output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6, pub output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7,
pub spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern, pub spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern,
pub input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5, pub input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6, pub input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7,
pub active_reused_addr_count: _1m1w1y24hBlockPattern, pub active_reused_addr_count: _1m1w1y24hBlockPattern,
pub active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare, pub active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare,
} }
@@ -4497,11 +4545,11 @@ pub struct SeriesTree_Addrs_Reused_Events {
impl SeriesTree_Addrs_Reused_Events { impl SeriesTree_Addrs_Reused_Events {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5::new(client.clone(), "output_to_reused_addr_count".to_string()), output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "output_to_reused_addr_count".to_string()),
output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "output_to_reused_addr_share".to_string()), output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7::new(client.clone(), "output_to_reused_addr_share".to_string()),
spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern::new(client.clone(), "spendable_output_to_reused_addr_share".to_string()), spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern::new(client.clone(), "spendable_output_to_reused_addr_share".to_string()),
input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5::new(client.clone(), "input_from_reused_addr_count".to_string()), input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "input_from_reused_addr_count".to_string()),
input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "input_from_reused_addr_share".to_string()), input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7::new(client.clone(), "input_from_reused_addr_share".to_string()),
active_reused_addr_count: _1m1w1y24hBlockPattern::new(client.clone(), "active_reused_addr_count".to_string()), active_reused_addr_count: _1m1w1y24hBlockPattern::new(client.clone(), "active_reused_addr_count".to_string()),
active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare::new(client.clone(), format!("{base_path}_active_reused_addr_share")), active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare::new(client.clone(), format!("{base_path}_active_reused_addr_share")),
} }
@@ -4633,6 +4681,35 @@ impl SeriesTree_Addrs_Delta {
} }
} }
/// Series tree node.
pub struct SeriesTree_Addrs_AvgAmount {
pub all: AddrUtxoPattern,
pub p2pk65: AddrUtxoPattern,
pub p2pk33: AddrUtxoPattern,
pub p2pkh: AddrUtxoPattern,
pub p2sh: AddrUtxoPattern,
pub p2wpkh: AddrUtxoPattern,
pub p2wsh: AddrUtxoPattern,
pub p2tr: AddrUtxoPattern,
pub p2a: AddrUtxoPattern,
}
impl SeriesTree_Addrs_AvgAmount {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self {
all: AddrUtxoPattern::new(client.clone(), "avg".to_string()),
p2pk65: AddrUtxoPattern::new(client.clone(), "p2pk65_avg".to_string()),
p2pk33: AddrUtxoPattern::new(client.clone(), "p2pk33_avg".to_string()),
p2pkh: AddrUtxoPattern::new(client.clone(), "p2pkh_avg".to_string()),
p2sh: AddrUtxoPattern::new(client.clone(), "p2sh_avg".to_string()),
p2wpkh: AddrUtxoPattern::new(client.clone(), "p2wpkh_avg".to_string()),
p2wsh: AddrUtxoPattern::new(client.clone(), "p2wsh_avg".to_string()),
p2tr: AddrUtxoPattern::new(client.clone(), "p2tr_avg".to_string()),
p2a: AddrUtxoPattern::new(client.clone(), "p2a_avg".to_string()),
}
}
}
/// Series tree node. /// Series tree node.
pub struct SeriesTree_Scripts { pub struct SeriesTree_Scripts {
pub raw: SeriesTree_Scripts_Raw, pub raw: SeriesTree_Scripts_Raw,
@@ -6975,6 +7052,7 @@ pub struct SeriesTree_Cohorts_Utxo_All {
pub realized: SeriesTree_Cohorts_Utxo_All_Realized, pub realized: SeriesTree_Cohorts_Utxo_All_Realized,
pub cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis, pub cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis,
pub unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized, pub unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized,
pub invested_capital: InPattern,
} }
impl SeriesTree_Cohorts_Utxo_All { impl SeriesTree_Cohorts_Utxo_All {
@@ -6986,6 +7064,7 @@ impl SeriesTree_Cohorts_Utxo_All {
realized: SeriesTree_Cohorts_Utxo_All_Realized::new(client.clone(), format!("{base_path}_realized")), realized: SeriesTree_Cohorts_Utxo_All_Realized::new(client.clone(), format!("{base_path}_realized")),
cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")), cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized::new(client.clone(), format!("{base_path}_unrealized")), unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized::new(client.clone(), format!("{base_path}_unrealized")),
invested_capital: InPattern::new(client.clone(), "invested_capital_in".to_string()),
} }
} }
} }
@@ -7358,7 +7437,7 @@ pub struct SeriesTree_Cohorts_Utxo_All_Unrealized {
pub loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss, pub loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss,
pub net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl, pub net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl,
pub gross_pnl: CentsUsdPattern3, pub gross_pnl: CentsUsdPattern3,
pub invested_capital: InPattern, pub invested_capital: InPattern2,
pub capitalized_cap_in_profit_raw: SeriesPattern18<CentsSquaredSats>, pub capitalized_cap_in_profit_raw: SeriesPattern18<CentsSquaredSats>,
pub capitalized_cap_in_loss_raw: SeriesPattern18<CentsSquaredSats>, pub capitalized_cap_in_loss_raw: SeriesPattern18<CentsSquaredSats>,
pub sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment, pub sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment,
@@ -7372,7 +7451,7 @@ impl SeriesTree_Cohorts_Utxo_All_Unrealized {
loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss::new(client.clone(), format!("{base_path}_loss")), loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss::new(client.clone(), format!("{base_path}_loss")),
net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl::new(client.clone(), format!("{base_path}_net_pnl")), net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl::new(client.clone(), format!("{base_path}_net_pnl")),
gross_pnl: CentsUsdPattern3::new(client.clone(), "unrealized_gross_pnl".to_string()), gross_pnl: CentsUsdPattern3::new(client.clone(), "unrealized_gross_pnl".to_string()),
invested_capital: InPattern::new(client.clone(), "invested_capital_in".to_string()), invested_capital: InPattern2::new(client.clone(), "invested_capital_in".to_string()),
capitalized_cap_in_profit_raw: SeriesPattern18::new(client.clone(), "capitalized_cap_in_profit_raw".to_string()), capitalized_cap_in_profit_raw: SeriesPattern18::new(client.clone(), "capitalized_cap_in_profit_raw".to_string()),
capitalized_cap_in_loss_raw: SeriesPattern18::new(client.clone(), "capitalized_cap_in_loss_raw".to_string()), capitalized_cap_in_loss_raw: SeriesPattern18::new(client.clone(), "capitalized_cap_in_loss_raw".to_string()),
sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")), sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")),
@@ -7462,6 +7541,7 @@ pub struct SeriesTree_Cohorts_Utxo_Sth {
pub realized: SeriesTree_Cohorts_Utxo_Sth_Realized, pub realized: SeriesTree_Cohorts_Utxo_Sth_Realized,
pub cost_basis: InMaxMinPerSupplyPattern, pub cost_basis: InMaxMinPerSupplyPattern,
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2, pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
pub invested_capital: InPattern,
} }
impl SeriesTree_Cohorts_Utxo_Sth { impl SeriesTree_Cohorts_Utxo_Sth {
@@ -7473,6 +7553,7 @@ impl SeriesTree_Cohorts_Utxo_Sth {
realized: SeriesTree_Cohorts_Utxo_Sth_Realized::new(client.clone(), format!("{base_path}_realized")), realized: SeriesTree_Cohorts_Utxo_Sth_Realized::new(client.clone(), format!("{base_path}_realized")),
cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "sth".to_string()), cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "sth".to_string()),
unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "sth".to_string()), unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "sth".to_string()),
invested_capital: InPattern::new(client.clone(), "sth_invested_capital_in".to_string()),
} }
} }
} }
@@ -7730,6 +7811,7 @@ pub struct SeriesTree_Cohorts_Utxo_Lth {
pub realized: SeriesTree_Cohorts_Utxo_Lth_Realized, pub realized: SeriesTree_Cohorts_Utxo_Lth_Realized,
pub cost_basis: InMaxMinPerSupplyPattern, pub cost_basis: InMaxMinPerSupplyPattern,
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2, pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
pub invested_capital: InPattern,
} }
impl SeriesTree_Cohorts_Utxo_Lth { impl SeriesTree_Cohorts_Utxo_Lth {
@@ -7741,6 +7823,7 @@ impl SeriesTree_Cohorts_Utxo_Lth {
realized: SeriesTree_Cohorts_Utxo_Lth_Realized::new(client.clone(), format!("{base_path}_realized")), realized: SeriesTree_Cohorts_Utxo_Lth_Realized::new(client.clone(), format!("{base_path}_realized")),
cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "lth".to_string()), cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "lth".to_string()),
unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "lth".to_string()), unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "lth".to_string()),
invested_capital: InPattern::new(client.clone(), "lth_invested_capital_in".to_string()),
} }
} }
} }

View File

@@ -67,14 +67,14 @@ pub(crate) fn process_funded_addrs(
// Pure pushes - no holes remain // Pure pushes - no holes remain
addrs_data.funded.reserve_pushed(pushes_iter.len()); addrs_data.funded.reserve_pushed(pushes_iter.len());
let mut next_index = addrs_data.funded.len(); for (next_index, (addr_type, type_index, data)) in
for (addr_type, type_index, data) in pushes_iter { (addrs_data.funded.len()..).zip(pushes_iter)
{
addrs_data.funded.push(data); addrs_data.funded.push(data);
result.get_mut(addr_type).unwrap().insert( result.get_mut(addr_type).unwrap().insert(
type_index, type_index,
AnyAddrIndex::from(FundedAddrIndex::from(next_index)), AnyAddrIndex::from(FundedAddrIndex::from(next_index)),
); );
next_index += 1;
} }
Ok(result) Ok(result)
@@ -138,14 +138,14 @@ pub(crate) fn process_empty_addrs(
// Pure pushes - no holes remain // Pure pushes - no holes remain
addrs_data.empty.reserve_pushed(pushes_iter.len()); addrs_data.empty.reserve_pushed(pushes_iter.len());
let mut next_index = addrs_data.empty.len(); for (next_index, (addr_type, type_index, data)) in
for (addr_type, type_index, data) in pushes_iter { (addrs_data.empty.len()..).zip(pushes_iter)
{
addrs_data.empty.push(data); addrs_data.empty.push(data);
result.get_mut(addr_type).unwrap().insert( result.get_mut(addr_type).unwrap().insert(
type_index, type_index,
AnyAddrIndex::from(EmptyAddrIndex::from(next_index)), AnyAddrIndex::from(EmptyAddrIndex::from(next_index)),
); );
next_index += 1;
} }
Ok(result) Ok(result)

View File

@@ -542,17 +542,14 @@ impl UTXOCohorts<Rw> {
} }
/// Second phase of post-processing: compute relative metrics. /// Second phase of post-processing: compute relative metrics.
pub(crate) fn compute_rest_part2<HM>( pub(crate) fn compute_rest_part2(
&mut self, &mut self,
blocks: &blocks::Vecs, blocks: &blocks::Vecs,
prices: &prices::Vecs, prices: &prices::Vecs,
starting_indexes: &Indexes, starting_indexes: &Indexes,
height_to_market_cap: &HM, height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit, exit: &Exit,
) -> Result<()> ) -> Result<()> {
where
HM: ReadableVec<Height, Dollars> + Sync,
{
// Get under_1h value sources for adjusted computation (cloned to avoid borrow conflicts). // Get under_1h value sources for adjusted computation (cloned to avoid borrow conflicts).
let under_1h_value_created = self let under_1h_value_created = self
.age_range .age_range

View File

@@ -258,6 +258,7 @@ pub(crate) fn process_blocks(
.chain(vecs.addrs.activity.par_iter_height_mut()) .chain(vecs.addrs.activity.par_iter_height_mut())
.chain(vecs.addrs.reused.par_iter_height_mut()) .chain(vecs.addrs.reused.par_iter_height_mut())
.chain(vecs.addrs.exposed.par_iter_height_mut()) .chain(vecs.addrs.exposed.par_iter_height_mut())
.chain(vecs.addrs.avg_amount.par_iter_height_mut())
.chain(rayon::iter::once( .chain(rayon::iter::once(
&mut vecs.coinblocks_destroyed.block as &mut dyn AnyStoredVec, &mut vecs.coinblocks_destroyed.block as &mut dyn AnyStoredVec,
)) ))

View File

@@ -156,6 +156,7 @@ impl AllCohortMetrics {
starting_indexes.height, starting_indexes.height,
&self.supply, &self.supply,
&self.unrealized, &self.unrealized,
&self.realized,
height_to_market_cap, height_to_market_cap,
exit, exit,
)?; )?;

View File

@@ -132,6 +132,7 @@ impl ExtendedCohortMetrics {
starting_indexes.height, starting_indexes.height,
&self.supply, &self.supply,
&self.unrealized, &self.unrealized,
&self.realized,
height_to_market_cap, height_to_market_cap,
all_supply_sats, all_supply_sats,
&self.supply.total.usd.height, &self.supply.total.usd.height,

View File

@@ -133,7 +133,7 @@ pub use realized::{
AdjustedSopr, RealizedCore, RealizedFull, RealizedFullAccum, RealizedLike, RealizedMinimal, AdjustedSopr, RealizedCore, RealizedFull, RealizedFullAccum, RealizedLike, RealizedMinimal,
}; };
pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended}; pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended};
pub use supply::{SupplyBase, SupplyCore}; pub use supply::{AvgAmountMetrics, SupplyBase, SupplyCore};
pub use unrealized::{ pub use unrealized::{
UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedMinimal, UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedMinimal,
}; };

View File

@@ -118,11 +118,11 @@ impl RealizedMinimal {
|(i, cap_cents, supply, ..)| { |(i, cap_cents, supply, ..)| {
let cap = cap_cents.as_u128(); let cap = cap_cents.as_u128();
let supply_sats = Sats::from(supply).as_u128(); let supply_sats = Sats::from(supply).as_u128();
if supply_sats == 0 { let cents = (cap * Sats::ONE_BTC_U128)
(i, Cents::ZERO) .checked_div(supply_sats)
} else { .map(Cents::from)
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats)) .unwrap_or(Cents::ZERO);
} (i, cents)
}, },
exit, exit,
)?) )?)

View File

@@ -4,9 +4,9 @@ use brk_types::{Dollars, Height};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull}; use crate::distribution::metrics::{ImportConfig, RealizedFull, SupplyCore, UnrealizedFull};
use super::{RelativeExtendedOwnPnl, RelativeFull}; use super::{RelativeExtendedOwnPnl, RelativeFull, RelativeInvestedCapital};
/// Relative metrics for the "all" cohort (base + own_pnl, NO rel_to_all). /// Relative metrics for the "all" cohort (base + own_pnl, NO rel_to_all).
#[derive(Deref, DerefMut, Traversable)] #[derive(Deref, DerefMut, Traversable)]
@@ -17,6 +17,8 @@ pub struct RelativeForAll<M: StorageMode = Rw> {
pub base: RelativeFull<M>, pub base: RelativeFull<M>,
#[traversable(flatten)] #[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl<M>, pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
#[traversable(flatten)]
pub invested_capital: RelativeInvestedCapital<M>,
} }
impl RelativeForAll { impl RelativeForAll {
@@ -24,6 +26,7 @@ impl RelativeForAll {
Ok(Self { Ok(Self {
base: RelativeFull::forced_import(cfg)?, base: RelativeFull::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?, extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
invested_capital: RelativeInvestedCapital::forced_import(cfg)?,
}) })
} }
@@ -32,6 +35,7 @@ impl RelativeForAll {
max_from: Height, max_from: Height,
supply: &SupplyCore, supply: &SupplyCore,
unrealized: &UnrealizedFull, unrealized: &UnrealizedFull,
realized: &RealizedFull,
market_cap: &impl ReadableVec<Height, Dollars>, market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
@@ -43,6 +47,8 @@ impl RelativeForAll {
&unrealized.gross_pnl.usd.height, &unrealized.gross_pnl.usd.height,
exit, exit,
)?; )?;
self.invested_capital
.compute(max_from, unrealized, realized, exit)?;
Ok(()) Ok(())
} }
} }

View File

@@ -0,0 +1,53 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Cents, Height, Version};
use vecdb::{Exit, Rw, StorageMode};
use crate::internal::{PercentPerBlock, RatioCentsBp16};
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
/// Shares of invested capital in profit / in loss relative to own realized cap.
/// Present for cohorts with `UnrealizedFull` (all, sth, lth).
#[derive(Traversable)]
pub struct RelativeInvestedCapital<M: StorageMode = Rw> {
#[traversable(wrap = "invested_capital/in_profit", rename = "to_own")]
pub in_profit_to_own: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "invested_capital/in_loss", rename = "to_own")]
pub in_loss_to_own: PercentPerBlock<BasisPoints16, M>,
}
impl RelativeInvestedCapital {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
Ok(Self {
in_profit_to_own: cfg.import("invested_capital_in_profit_to_own", v0)?,
in_loss_to_own: cfg.import("invested_capital_in_loss_to_own", v0)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
exit: &Exit,
) -> Result<()> {
let realized_cap = &realized.core.minimal.cap.cents.height;
self.in_profit_to_own
.compute_binary::<Cents, Cents, RatioCentsBp16>(
max_from,
&unrealized.invested_capital.in_profit.cents.height,
realized_cap,
exit,
)?;
self.in_loss_to_own
.compute_binary::<Cents, Cents, RatioCentsBp16>(
max_from,
&unrealized.invested_capital.in_loss.cents.height,
realized_cap,
exit,
)?;
Ok(())
}
}

View File

@@ -2,6 +2,7 @@ mod extended_own_market_cap;
mod extended_own_pnl; mod extended_own_pnl;
mod for_all; mod for_all;
mod full; mod full;
mod invested_capital;
mod to_all; mod to_all;
mod with_extended; mod with_extended;
@@ -9,5 +10,6 @@ pub use extended_own_market_cap::RelativeExtendedOwnMarketCap;
pub use extended_own_pnl::RelativeExtendedOwnPnl; pub use extended_own_pnl::RelativeExtendedOwnPnl;
pub use for_all::RelativeForAll; pub use for_all::RelativeForAll;
pub use full::RelativeFull; pub use full::RelativeFull;
pub use invested_capital::RelativeInvestedCapital;
pub use to_all::RelativeToAll; pub use to_all::RelativeToAll;
pub use with_extended::RelativeWithExtended; pub use with_extended::RelativeWithExtended;

View File

@@ -4,9 +4,12 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull}; use crate::distribution::metrics::{ImportConfig, RealizedFull, SupplyCore, UnrealizedFull};
use super::{RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeFull, RelativeToAll}; use super::{
RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeFull, RelativeInvestedCapital,
RelativeToAll,
};
/// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl). /// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl).
/// Used by: sth, lth cohorts. /// Used by: sth, lth cohorts.
@@ -22,6 +25,8 @@ pub struct RelativeWithExtended<M: StorageMode = Rw> {
pub extended_own_market_cap: RelativeExtendedOwnMarketCap<M>, pub extended_own_market_cap: RelativeExtendedOwnMarketCap<M>,
#[traversable(flatten)] #[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl<M>, pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
#[traversable(flatten)]
pub invested_capital: RelativeInvestedCapital<M>,
} }
impl RelativeWithExtended { impl RelativeWithExtended {
@@ -31,6 +36,7 @@ impl RelativeWithExtended {
rel_to_all: RelativeToAll::forced_import(cfg)?, rel_to_all: RelativeToAll::forced_import(cfg)?,
extended_own_market_cap: RelativeExtendedOwnMarketCap::forced_import(cfg)?, extended_own_market_cap: RelativeExtendedOwnMarketCap::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?, extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
invested_capital: RelativeInvestedCapital::forced_import(cfg)?,
}) })
} }
@@ -40,6 +46,7 @@ impl RelativeWithExtended {
max_from: Height, max_from: Height,
supply: &SupplyCore, supply: &SupplyCore,
unrealized: &UnrealizedFull, unrealized: &UnrealizedFull,
realized: &RealizedFull,
market_cap: &impl ReadableVec<Height, Dollars>, market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>, all_supply_sats: &impl ReadableVec<Height, Sats>,
own_market_cap: &impl ReadableVec<Height, Dollars>, own_market_cap: &impl ReadableVec<Height, Dollars>,
@@ -57,6 +64,8 @@ impl RelativeWithExtended {
&unrealized.gross_pnl.usd.height, &unrealized.gross_pnl.usd.height,
exit, exit,
)?; )?;
self.invested_capital
.compute(max_from, unrealized, realized, exit)?;
Ok(()) Ok(())
} }
} }

View File

@@ -0,0 +1,77 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Sats, StoredU64, Version};
use vecdb::{AnyStoredVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{indexes, internal::AmountPerBlock, prices};
/// Average amount held per UTXO and per funded address.
///
/// `utxo = supply / utxo_count`, `addr = supply / funded_addr_count`.
#[derive(Traversable)]
pub struct AvgAmountMetrics<M: StorageMode = Rw> {
pub utxo: AmountPerBlock<M>,
pub addr: AmountPerBlock<M>,
}
impl AvgAmountMetrics {
pub(crate) fn forced_import(
db: &Database,
prefix: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let name = |suffix: &str| {
if prefix.is_empty() {
suffix.to_string()
} else {
format!("{prefix}_{suffix}")
}
};
Ok(Self {
utxo: AmountPerBlock::forced_import(db, &name("avg_utxo_amount"), version, indexes)?,
addr: AmountPerBlock::forced_import(db, &name("avg_addr_amount"), version, indexes)?,
})
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.utxo.sats.height as &mut dyn AnyStoredVec,
&mut self.utxo.cents.height,
&mut self.addr.sats.height,
&mut self.addr.cents.height,
]
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.utxo.sats.height.reset()?;
self.utxo.cents.height.reset()?;
self.addr.sats.height.reset()?;
self.addr.cents.height.reset()?;
Ok(())
}
pub(crate) fn compute(
&mut self,
prices: &prices::Vecs,
supply_sats: &impl ReadableVec<Height, Sats>,
utxo_count: &impl ReadableVec<Height, StoredU64>,
funded_addr_count: &impl ReadableVec<Height, StoredU64>,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.utxo
.sats
.height
.compute_divide(max_from, supply_sats, utxo_count, exit)?;
self.utxo.compute(prices, max_from, exit)?;
self.addr
.sats
.height
.compute_divide(max_from, supply_sats, funded_addr_count, exit)?;
self.addr.compute(prices, max_from, exit)?;
Ok(())
}
}

View File

@@ -49,7 +49,7 @@ impl SupplyBase {
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![ vec![
&mut self.total.sats.height as &mut dyn AnyStoredVec, &mut self.total.sats.height as &mut dyn AnyStoredVec,
&mut self.total.cents.height as &mut dyn AnyStoredVec, &mut self.total.cents.height,
] ]
} }

View File

@@ -1,5 +1,7 @@
mod avg_amount;
mod base; mod base;
mod core; mod core;
pub use avg_amount::AvgAmountMetrics;
pub use self::core::SupplyCore; pub use self::core::SupplyCore;
pub use base::SupplyBase; pub use base::SupplyBase;

View File

@@ -25,7 +25,7 @@ use crate::{
}, },
indexes, inputs, indexes, inputs,
internal::{ internal::{
PerBlockCumulativeRolling, WindowStartVec, Windows, PerBlockCumulativeRolling, WindowStartVec, Windows, WithAddrTypes,
db_utils::{finalize_db, open_db}, db_utils::{finalize_db, open_db},
}, },
outputs, prices, transactions, outputs, prices, transactions,
@@ -37,6 +37,7 @@ use super::{
AddrActivityVecs, AddrCountsVecs, DeltaVecs, ExposedAddrVecs, NewAddrCountVecs, AddrActivityVecs, AddrCountsVecs, DeltaVecs, ExposedAddrVecs, NewAddrCountVecs,
ReusedAddrVecs, TotalAddrCountVecs, ReusedAddrVecs, TotalAddrCountVecs,
}, },
metrics::AvgAmountMetrics,
}; };
const VERSION: Version = Version::new(23); const VERSION: Version = Version::new(23);
@@ -51,6 +52,7 @@ pub struct AddrMetricsVecs<M: StorageMode = Rw> {
pub reused: ReusedAddrVecs<M>, pub reused: ReusedAddrVecs<M>,
pub exposed: ExposedAddrVecs<M>, pub exposed: ExposedAddrVecs<M>,
pub delta: DeltaVecs, pub delta: DeltaVecs,
pub avg_amount: WithAddrTypes<AvgAmountMetrics<M>>,
#[traversable(wrap = "indexes", rename = "funded")] #[traversable(wrap = "indexes", rename = "funded")]
pub funded_index: pub funded_index:
LazyVecFrom1<FundedAddrIndex, FundedAddrIndex, FundedAddrIndex, FundedAddrData>, LazyVecFrom1<FundedAddrIndex, FundedAddrIndex, FundedAddrIndex, FundedAddrData>,
@@ -170,6 +172,9 @@ impl Vecs {
// Growth rate: delta change + rate (global + per-type) // Growth rate: delta change + rate (global + per-type)
let delta = DeltaVecs::new(version, &addr_count, cached_starts, indexes); let delta = DeltaVecs::new(version, &addr_count, cached_starts, indexes);
// Average amount (supply / utxo_count, supply / funded_addr_count) for `all` and per addr type.
let avg_amount = WithAddrTypes::<AvgAmountMetrics>::forced_import(&db, version, indexes)?;
let this = Self { let this = Self {
supply_state: BytesVec::forced_import_with( supply_state: BytesVec::forced_import_with(
vecdb::ImportOptions::new(&db, "supply_state", version) vecdb::ImportOptions::new(&db, "supply_state", version)
@@ -185,6 +190,7 @@ impl Vecs {
reused: reused_addr_count, reused: reused_addr_count,
exposed: exposed_addr_vecs, exposed: exposed_addr_vecs,
delta, delta,
avg_amount,
funded_index: funded_addr_index, funded_index: funded_addr_index,
empty_index: empty_addr_index, empty_index: empty_addr_index,
}, },
@@ -302,6 +308,7 @@ impl Vecs {
self.addrs.activity.reset_height()?; self.addrs.activity.reset_height()?;
self.addrs.reused.reset_height()?; self.addrs.reused.reset_height()?;
self.addrs.exposed.reset_height()?; self.addrs.exposed.reset_height()?;
self.addrs.avg_amount.reset_height()?;
reset_state( reset_state(
&mut self.any_addr_indexes, &mut self.any_addr_indexes,
&mut self.addrs_data, &mut self.addrs_data,
@@ -490,6 +497,34 @@ impl Vecs {
exit, exit,
)?; )?;
// Average amount (supply / utxo_count, supply / funded_addr_count) for `all` and per addr type.
let all_m = &self.utxo_cohorts.all.metrics;
self.addrs.avg_amount.all.compute(
prices,
&all_m.supply.total.sats.height,
&all_m.outputs.unspent_count.height,
&self.addrs.funded.all.height,
starting_indexes.height,
exit,
)?;
for ((ot, avg), (_, funded)) in self
.addrs
.avg_amount
.by_addr_type
.iter_mut()
.zip(self.addrs.funded.by_addr_type.iter())
{
let type_m = &t.get(ot).metrics;
avg.compute(
prices,
&type_m.supply.total.sats.height,
&type_m.outputs.unspent_count.height,
&funded.height,
starting_indexes.height,
exit,
)?;
}
// 6c. Compute total_addr_count = addr_count + empty_addr_count // 6c. Compute total_addr_count = addr_count + empty_addr_count
self.addrs.total.compute( self.addrs.total.compute(
starting_indexes.height, starting_indexes.height,

View File

@@ -267,7 +267,7 @@ impl<T: NumericValue + JsonSchema> PerBlockDistribution<T> {
vec.push(zero); vec.push(zero);
} }
} else { } else {
weighted.sort_unstable_by(|a, b| a.0.cmp(&b.0)); weighted.sort_unstable_by_key(|a| a.0);
max.push(weighted.last().unwrap().0); max.push(weighted.last().unwrap().0);
pct90.push(get_weighted_percentile(&weighted, 0.90)); pct90.push(get_weighted_percentile(&weighted, 0.90));

View File

@@ -24,9 +24,9 @@ pub use derived::{
RatioCents64, TimesSqrt, RatioCents64, TimesSqrt,
}; };
pub use ratio::{ pub use ratio::{
RatioCentsBp32, RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RatioDiffCentsBps32, RatioCentsBp16, RatioCentsBp32, RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32,
RatioDiffDollarsBps32, RatioDiffF32Bps32, RatioDollarsBp16, RatioDollarsBp32, RatioDiffCentsBps32, RatioDiffDollarsBps32, RatioDiffF32Bps32, RatioDollarsBp16,
RatioDollarsBps32, RatioSatsBp16, RatioU64Bp16, RatioU64F32, RatioDollarsBp32, RatioDollarsBps32, RatioSatsBp16, RatioU64Bp16, RatioU64F32,
}; };
pub use specialized::{ pub use specialized::{
BlockCountTarget1m, BlockCountTarget1w, BlockCountTarget1y, BlockCountTarget24h, BlockCountTarget1m, BlockCountTarget1w, BlockCountTarget1y, BlockCountTarget24h,

View File

@@ -43,6 +43,19 @@ impl BinaryTransform<Cents, Cents, BasisPoints32> for RatioCentsBp32 {
} }
} }
pub struct RatioCentsBp16;
impl BinaryTransform<Cents, Cents, BasisPoints16> for RatioCentsBp16 {
#[inline(always)]
fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 {
if denominator == Cents::ZERO {
BasisPoints16::ZERO
} else {
BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64)
}
}
}
pub struct RatioDollarsBp16; pub struct RatioDollarsBp16;
impl BinaryTransform<Dollars, Dollars, BasisPoints16> for RatioDollarsBp16 { impl BinaryTransform<Dollars, Dollars, BasisPoints16> for RatioDollarsBp16 {

View File

@@ -17,6 +17,8 @@ use super::{
WindowStartVec, Windows, WindowStartVec, Windows,
}; };
use crate::distribution::metrics::AvgAmountMetrics;
/// `all` aggregate plus per-`AddrType` breakdown. /// `all` aggregate plus per-`AddrType` breakdown.
#[derive(Clone, Traversable)] #[derive(Clone, Traversable)]
pub struct WithAddrTypes<T> { pub struct WithAddrTypes<T> {
@@ -246,6 +248,42 @@ impl WithAddrTypes<AmountPerBlock> {
} }
} }
impl WithAddrTypes<AvgAmountMetrics> {
pub(crate) fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let all = AvgAmountMetrics::forced_import(db, "", version, indexes)?;
let by_addr_type = ByAddrType::new_with_name(|type_name| {
AvgAmountMetrics::forced_import(db, type_name, version, indexes)
})?;
Ok(Self { all, by_addr_type })
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.all.collect_vecs_mut();
for v in self.by_addr_type.values_mut() {
vecs.extend(v.collect_vecs_mut());
}
vecs
}
pub(crate) fn par_iter_height_mut(
&mut self,
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
self.collect_vecs_mut().into_par_iter()
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.all.reset_height()?;
for v in self.by_addr_type.values_mut() {
v.reset_height()?;
}
Ok(())
}
}
impl<B: BpsType> WithAddrTypes<PercentPerBlock<B>> { impl<B: BpsType> WithAddrTypes<PercentPerBlock<B>> {
pub(crate) fn forced_import( pub(crate) fn forced_import(
db: &Database, db: &Database,

View File

@@ -1,3 +1,5 @@
use std::cmp::Reverse;
use super::{BLOCK_VSIZE, package::Package}; use super::{BLOCK_VSIZE, package::Package};
use crate::types::SelectedTx; use crate::types::SelectedTx;
@@ -13,7 +15,7 @@ pub fn partition_into_blocks(
mut packages: Vec<Package>, mut packages: Vec<Package>,
num_blocks: usize, num_blocks: usize,
) -> Vec<Vec<SelectedTx>> { ) -> Vec<Vec<SelectedTx>> {
packages.sort_unstable_by(|a, b| b.fee_rate.cmp(&a.fee_rate)); packages.sort_unstable_by_key(|p| Reverse(p.fee_rate));
let mut blocks: Vec<Vec<SelectedTx>> = Vec::with_capacity(num_blocks); let mut blocks: Vec<Vec<SelectedTx>> = Vec::with_capacity(num_blocks);
let mut current_block: Vec<SelectedTx> = Vec::new(); let mut current_block: Vec<SelectedTx> = Vec::new();

View File

@@ -375,11 +375,7 @@ impl Query {
slug: pool_slug, slug: pool_slug,
miner_names, miner_names,
}, },
avg_fee: Sats::from(if non_coinbase > 0 { avg_fee: Sats::from(total_fees_u64.checked_div(non_coinbase).unwrap_or(0)),
total_fees_u64 / non_coinbase
} else {
0
}),
avg_fee_rate: FeeRate::from((total_fees, VSize::from(vsize))), avg_fee_rate: FeeRate::from((total_fees, VSize::from(vsize))),
coinbase_raw, coinbase_raw,
coinbase_address, coinbase_address,

View File

@@ -80,7 +80,7 @@ impl BlockWindow {
.prices .prices
.spot.cents.height .spot.cents.height
.collect_range_at(self.start, self.end); .collect_range_at(self.start, self.end);
let read_start = self.start.saturating_sub(1).max(0); let read_start = self.start.saturating_sub(1);
let all_cum = cumulative.collect_range_at(read_start, self.end); let all_cum = cumulative.collect_range_at(read_start, self.end);
let offset = if self.start > 0 { 1 } else { 0 }; let offset = if self.start > 0 { 1 } else { 0 };
@@ -91,7 +91,6 @@ impl BlockWindow {
while pos < total { while pos < total {
let window_end = (pos + self.window).min(total); let window_end = (pos + self.window).min(total);
let block_count = (window_end - pos) as u64; let block_count = (window_end - pos) as u64;
if block_count > 0 {
let mid = (pos + window_end) / 2; let mid = (pos + window_end) / 2;
let cum_end = all_cum[window_end - 1 + offset]; let cum_end = all_cum[window_end - 1 + offset];
let cum_start = if pos + offset > 0 { let cum_start = if pos + offset > 0 {
@@ -100,10 +99,11 @@ impl BlockWindow {
Sats::ZERO Sats::ZERO
}; };
let total_sats = cum_end - cum_start; let total_sats = cum_end - cum_start;
if let Some(avg) = (*total_sats).checked_div(block_count) {
results.push(WindowAvg { results.push(WindowAvg {
avg_height: Height::from(self.start + mid), avg_height: Height::from(self.start + mid),
timestamp: all_ts[mid], timestamp: all_ts[mid],
avg_value: Sats::from(*total_sats / block_count), avg_value: Sats::from(avg),
usd: Dollars::from(all_prices[mid]), usd: Dollars::from(all_prices[mid]),
}); });
} }

View File

@@ -1,3 +1,5 @@
use std::cmp::Reverse;
use brk_error::{Error, Result}; use brk_error::{Error, Result};
use brk_types::{ use brk_types::{
BlockInfoV1, Day1, Height, Pool, PoolBlockCounts, PoolBlockShares, PoolDetail, PoolDetailInfo, BlockInfoV1, Day1, Height, Pool, PoolBlockCounts, PoolBlockShares, PoolDetail, PoolDetailInfo,
@@ -89,7 +91,7 @@ impl Query {
} }
// Sort by block count descending // Sort by block count descending
pool_data.sort_by(|a, b| b.1.cmp(&a.1)); pool_data.sort_by_key(|p| Reverse(p.1));
let total_blocks: u64 = pool_data.iter().map(|(_, count)| count).sum(); let total_blocks: u64 = pool_data.iter().map(|(_, count)| count).sum();

View File

@@ -3,6 +3,7 @@
//! Run with: //! Run with:
//! cargo run -p brk_rpc --example compare_backends --features corepc //! cargo run -p brk_rpc --example compare_backends --features corepc
#[cfg(all(feature = "bitcoincore-rpc", feature = "corepc"))]
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
#[cfg(not(all(feature = "bitcoincore-rpc", feature = "corepc")))] #[cfg(not(all(feature = "bitcoincore-rpc", feature = "corepc")))]
@@ -260,6 +261,7 @@ fn main() {
println!("=== All checks passed ==="); println!("=== All checks passed ===");
} }
#[cfg(all(feature = "bitcoincore-rpc", feature = "corepc"))]
fn timed<T>(f: impl FnOnce() -> T) -> (Duration, T) { fn timed<T>(f: impl FnOnce() -> T) -> (Duration, T) {
let start = Instant::now(); let start = Instant::now();
let result = f(); let result = f();

View File

@@ -1,3 +1,5 @@
#![allow(unreachable_patterns, reason = "P2PK65 and P2PK33 both serialize as 'p2pk'")]
use bitcoin::{AddressType, ScriptBuf, opcodes::all::OP_PUSHBYTES_2}; use bitcoin::{AddressType, ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
use brk_error::Error; use brk_error::Error;
use schemars::JsonSchema; use schemars::JsonSchema;

View File

@@ -9,7 +9,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco, SaturatingAdd}; use vecdb::{CheckedSub, Formattable, Pco, SaturatingAdd};
use crate::StoredF64; use crate::{StoredF64, StoredU64};
use super::{Bitcoin, Cents, Dollars, Height}; use super::{Bitcoin, Cents, Dollars, Height};
@@ -204,36 +204,35 @@ impl Sum for Sats {
impl Div<Dollars> for Sats { impl Div<Dollars> for Sats {
type Output = Self; type Output = Self;
#[allow(clippy::suspicious_arithmetic_impl, reason = "cents-precision upscale before division")]
fn div(self, rhs: Dollars) -> Self::Output { fn div(self, rhs: Dollars) -> Self::Output {
let raw_cents = u64::from(Cents::from(rhs)); let raw_cents = u64::from(Cents::from(rhs));
if raw_cents != 0 { (self.0 * 100)
Self(self.0 * 100 / raw_cents) .checked_div(raw_cents)
} else { .map(Self)
Self::MAX .unwrap_or(Self::MAX)
}
} }
} }
impl Div<Sats> for Sats { impl Div<Sats> for Sats {
type Output = Self; type Output = Self;
fn div(self, rhs: Sats) -> Self::Output { fn div(self, rhs: Sats) -> Self::Output {
if rhs.0 == 0 { Self(self.0.checked_div(rhs.0).unwrap_or(0))
Self(0)
} else {
Self(self.0 / rhs.0)
}
} }
} }
impl Div<usize> for Sats { impl Div<usize> for Sats {
type Output = Self; type Output = Self;
fn div(self, rhs: usize) -> Self::Output { fn div(self, rhs: usize) -> Self::Output {
if rhs == 0 { Self(self.0.checked_div(rhs as u64).unwrap_or(0))
Self::ZERO
} else {
Self(self.0 / rhs as u64)
} }
} }
impl Div<StoredU64> for Sats {
type Output = Self;
fn div(self, rhs: StoredU64) -> Self::Output {
Self(self.0.checked_div(u64::from(rhs)).unwrap_or(0))
}
} }
impl From<u8> for Sats { impl From<u8> for Sats {

View File

@@ -99,11 +99,9 @@ fn sanitize(dirty: impl Iterator<Item = String>) -> Vec<String> {
let mut current = String::new(); let mut current = String::new();
for c in s.to_lowercase().chars() { for c in s.to_lowercase().chars() {
match c { match c {
' ' | ',' | '+' => { ' ' | ',' | '+' if !current.is_empty() => {
if !current.is_empty() {
clean.push(mem::take(&mut current)); clean.push(mem::take(&mut current));
} }
}
'-' => current.push('_'), '-' => current.push('_'),
c if c.is_alphanumeric() || c == '_' => current.push(c), c if c.is_alphanumeric() || c == '_' => current.push(c),
_ => {} _ => {}

View File

@@ -2301,7 +2301,7 @@ function createIndexPct0Pct1Pct2Pct5Pct95Pct98Pct99ScorePattern(client, acc) {
} }
/** /**
* @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 * @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6
* @property {AverageBlockCumulativeSumPattern<StoredU64>} all * @property {AverageBlockCumulativeSumPattern<StoredU64>} all
* @property {AverageBlockCumulativeSumPattern<StoredU64>} p2a * @property {AverageBlockCumulativeSumPattern<StoredU64>} p2a
* @property {AverageBlockCumulativeSumPattern<StoredU64>} p2pk33 * @property {AverageBlockCumulativeSumPattern<StoredU64>} p2pk33
@@ -2314,12 +2314,12 @@ function createIndexPct0Pct1Pct2Pct5Pct95Pct98Pct99ScorePattern(client, acc) {
*/ */
/** /**
* Create a AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 pattern node * Create a AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated series name * @param {string} acc - Accumulated series name
* @returns {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5} * @returns {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6}
*/ */
function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(client, acc) { function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, acc) {
return { return {
all: createAverageBlockCumulativeSumPattern(client, acc), all: createAverageBlockCumulativeSumPattern(client, acc),
p2a: createAverageBlockCumulativeSumPattern(client, _p('p2a', acc)), p2a: createAverageBlockCumulativeSumPattern(client, _p('p2a', acc)),
@@ -2334,7 +2334,7 @@ function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(client, acc) {
} }
/** /**
* @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 * @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4
* @property {SeriesPattern1<StoredU64>} all * @property {SeriesPattern1<StoredU64>} all
* @property {SeriesPattern1<StoredU64>} p2a * @property {SeriesPattern1<StoredU64>} p2a
* @property {SeriesPattern1<StoredU64>} p2pk33 * @property {SeriesPattern1<StoredU64>} p2pk33
@@ -2347,12 +2347,12 @@ function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(client, acc) {
*/ */
/** /**
* Create a AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 pattern node * Create a AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated series name * @param {string} acc - Accumulated series name
* @returns {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} * @returns {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4}
*/ */
function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, acc) { function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, acc) {
return { return {
all: createSeriesPattern1(client, acc), all: createSeriesPattern1(client, acc),
p2a: createSeriesPattern1(client, _p('p2a', acc)), p2a: createSeriesPattern1(client, _p('p2a', acc)),
@@ -2367,7 +2367,7 @@ function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, acc) {
} }
/** /**
* @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 * @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7
* @property {_1m1w1y24hBpsPercentRatioPattern} all * @property {_1m1w1y24hBpsPercentRatioPattern} all
* @property {_1m1w1y24hBpsPercentRatioPattern} p2a * @property {_1m1w1y24hBpsPercentRatioPattern} p2a
* @property {_1m1w1y24hBpsPercentRatioPattern} p2pk33 * @property {_1m1w1y24hBpsPercentRatioPattern} p2pk33
@@ -2380,12 +2380,12 @@ function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, acc) {
*/ */
/** /**
* Create a AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 pattern node * Create a AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated series name * @param {string} acc - Accumulated series name
* @returns {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6} * @returns {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7}
*/ */
function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, acc) { function createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7(client, acc) {
return { return {
all: create_1m1w1y24hBpsPercentRatioPattern(client, acc), all: create_1m1w1y24hBpsPercentRatioPattern(client, acc),
p2a: create_1m1w1y24hBpsPercentRatioPattern(client, _p('p2a', acc)), p2a: create_1m1w1y24hBpsPercentRatioPattern(client, _p('p2a', acc)),
@@ -2437,7 +2437,7 @@ function createAverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc) {
* @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInLossRaw * @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInLossRaw
* @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInProfitRaw * @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInProfitRaw
* @property {CentsUsdPattern3} grossPnl * @property {CentsUsdPattern3} grossPnl
* @property {InPattern} investedCapital * @property {InPattern2} investedCapital
* @property {CentsNegativeToUsdPattern2} loss * @property {CentsNegativeToUsdPattern2} loss
* @property {CentsToUsdPattern3} netPnl * @property {CentsToUsdPattern3} netPnl
* @property {BpsRatioPattern} nupl * @property {BpsRatioPattern} nupl
@@ -2456,7 +2456,7 @@ function createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client
capitalizedCapInLossRaw: createSeriesPattern18(client, _m(acc, 'capitalized_cap_in_loss_raw')), capitalizedCapInLossRaw: createSeriesPattern18(client, _m(acc, 'capitalized_cap_in_loss_raw')),
capitalizedCapInProfitRaw: createSeriesPattern18(client, _m(acc, 'capitalized_cap_in_profit_raw')), capitalizedCapInProfitRaw: createSeriesPattern18(client, _m(acc, 'capitalized_cap_in_profit_raw')),
grossPnl: createCentsUsdPattern3(client, _m(acc, 'unrealized_gross_pnl')), grossPnl: createCentsUsdPattern3(client, _m(acc, 'unrealized_gross_pnl')),
investedCapital: createInPattern(client, _m(acc, 'invested_capital_in')), investedCapital: createInPattern2(client, _m(acc, 'invested_capital_in')),
loss: createCentsNegativeToUsdPattern2(client, _m(acc, 'unrealized_loss')), loss: createCentsNegativeToUsdPattern2(client, _m(acc, 'unrealized_loss')),
netPnl: createCentsToUsdPattern3(client, _m(acc, 'net_unrealized_pnl')), netPnl: createCentsToUsdPattern3(client, _m(acc, 'net_unrealized_pnl')),
nupl: createBpsRatioPattern(client, _m(acc, 'nupl')), nupl: createBpsRatioPattern(client, _m(acc, 'nupl')),
@@ -3028,7 +3028,7 @@ function createActivityOutputsRealizedSupplyUnrealizedPattern2(client, acc) {
/** /**
* @typedef {Object} BlockChangeCumulativeDeltaSumPattern * @typedef {Object} BlockChangeCumulativeDeltaSumPattern
* @property {CentsUsdPattern4} block * @property {CentsUsdPattern4} block
* @property {ToPattern} change1m * @property {ToPattern2} change1m
* @property {CentsUsdPattern} cumulative * @property {CentsUsdPattern} cumulative
* @property {AbsoluteRatePattern2} delta * @property {AbsoluteRatePattern2} delta
* @property {_1m1w1y24hPattern5} sum * @property {_1m1w1y24hPattern5} sum
@@ -3043,7 +3043,7 @@ function createActivityOutputsRealizedSupplyUnrealizedPattern2(client, acc) {
function createBlockChangeCumulativeDeltaSumPattern(client, acc) { function createBlockChangeCumulativeDeltaSumPattern(client, acc) {
return { return {
block: createCentsUsdPattern4(client, _m(acc, 'realized_pnl')), block: createCentsUsdPattern4(client, _m(acc, 'realized_pnl')),
change1m: createToPattern(client, _m(acc, 'pnl_change_1m_to')), change1m: createToPattern2(client, _m(acc, 'pnl_change_1m_to')),
cumulative: createCentsUsdPattern(client, _m(acc, 'realized_pnl_cumulative')), cumulative: createCentsUsdPattern(client, _m(acc, 'realized_pnl_cumulative')),
delta: createAbsoluteRatePattern2(client, _m(acc, 'realized_pnl_delta')), delta: createAbsoluteRatePattern2(client, _m(acc, 'realized_pnl_delta')),
sum: create_1m1w1y24hPattern5(client, _m(acc, 'realized_pnl_sum')), sum: create_1m1w1y24hPattern5(client, _m(acc, 'realized_pnl_sum')),
@@ -4195,6 +4195,25 @@ function createAbsoluteRatePattern2(client, acc) {
}; };
} }
/**
* @typedef {Object} AddrUtxoPattern
* @property {BtcCentsSatsUsdPattern} addr
* @property {BtcCentsSatsUsdPattern} utxo
*/
/**
* Create a AddrUtxoPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {AddrUtxoPattern}
*/
function createAddrUtxoPattern(client, acc) {
return {
addr: createBtcCentsSatsUsdPattern(client, _m(acc, 'addr_amount')),
utxo: createBtcCentsSatsUsdPattern(client, _m(acc, 'utxo_amount')),
};
}
/** /**
* @typedef {Object} AllSthPattern2 * @typedef {Object} AllSthPattern2
* @property {BtcCentsDeltaSatsUsdPattern} all * @property {BtcCentsDeltaSatsUsdPattern} all
@@ -4464,8 +4483,8 @@ function createDeltaTotalPattern(client, acc) {
/** /**
* @typedef {Object} FundedTotalPattern * @typedef {Object} FundedTotalPattern
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} funded * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4} funded
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} total * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4} total
*/ */
/** /**
@@ -4476,15 +4495,34 @@ function createDeltaTotalPattern(client, acc) {
*/ */
function createFundedTotalPattern(client, acc) { function createFundedTotalPattern(client, acc) {
return { return {
funded: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, acc), funded: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, acc),
total: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, _p('total', acc)), total: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, _p('total', acc)),
};
}
/**
* @typedef {Object} InPattern2
* @property {CentsUsdPattern3} inLoss
* @property {CentsUsdPattern3} inProfit
*/
/**
* Create a InPattern2 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {InPattern2}
*/
function createInPattern2(client, acc) {
return {
inLoss: createCentsUsdPattern3(client, _m(acc, 'loss')),
inProfit: createCentsUsdPattern3(client, _m(acc, 'profit')),
}; };
} }
/** /**
* @typedef {Object} InPattern * @typedef {Object} InPattern
* @property {CentsUsdPattern3} inLoss * @property {ToPattern} inLoss
* @property {CentsUsdPattern3} inProfit * @property {ToPattern} inProfit
*/ */
/** /**
@@ -4495,8 +4533,8 @@ function createFundedTotalPattern(client, acc) {
*/ */
function createInPattern(client, acc) { function createInPattern(client, acc) {
return { return {
inLoss: createCentsUsdPattern3(client, _m(acc, 'loss')), inLoss: createToPattern(client, _m(acc, 'loss_to_own')),
inProfit: createCentsUsdPattern3(client, _m(acc, 'profit')), inProfit: createToPattern(client, _m(acc, 'profit_to_own')),
}; };
} }
@@ -4565,18 +4603,18 @@ function createRatioValuePattern(client, acc) {
*/ */
/** /**
* @typedef {Object} ToPattern * @typedef {Object} ToPattern2
* @property {BpsPercentRatioPattern} toMcap * @property {BpsPercentRatioPattern} toMcap
* @property {BpsPercentRatioPattern} toRcap * @property {BpsPercentRatioPattern} toRcap
*/ */
/** /**
* Create a ToPattern pattern node * Create a ToPattern2 pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated series name * @param {string} acc - Accumulated series name
* @returns {ToPattern} * @returns {ToPattern2}
*/ */
function createToPattern(client, acc) { function createToPattern2(client, acc) {
return { return {
toMcap: createBpsPercentRatioPattern(client, _m(acc, 'mcap')), toMcap: createBpsPercentRatioPattern(client, _m(acc, 'mcap')),
toRcap: createBpsPercentRatioPattern(client, _m(acc, 'rcap')), toRcap: createBpsPercentRatioPattern(client, _m(acc, 'rcap')),
@@ -4634,6 +4672,23 @@ function createPricePattern(client, acc) {
}; };
} }
/**
* @typedef {Object} ToPattern
* @property {BpsPercentRatioPattern2} toOwn
*/
/**
* Create a ToPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {ToPattern}
*/
function createToPattern(client, acc) {
return {
toOwn: createBpsPercentRatioPattern2(client, acc),
};
}
/** /**
* @typedef {Object} TransferPattern * @typedef {Object} TransferPattern
* @property {AverageBlockCumulativeSumPattern3} transferVolume * @property {AverageBlockCumulativeSumPattern3} transferVolume
@@ -5028,14 +5083,15 @@ function createTransferPattern(client, acc) {
* @property {SeriesTree_Addrs_Raw} raw * @property {SeriesTree_Addrs_Raw} raw
* @property {SeriesTree_Addrs_Indexes} indexes * @property {SeriesTree_Addrs_Indexes} indexes
* @property {SeriesTree_Addrs_Data} data * @property {SeriesTree_Addrs_Data} data
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} funded * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4} funded
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} empty * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4} empty
* @property {SeriesTree_Addrs_Activity} activity * @property {SeriesTree_Addrs_Activity} activity
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} total * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4} total
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5} new * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6} new
* @property {SeriesTree_Addrs_Reused} reused * @property {SeriesTree_Addrs_Reused} reused
* @property {SeriesTree_Addrs_Exposed} exposed * @property {SeriesTree_Addrs_Exposed} exposed
* @property {SeriesTree_Addrs_Delta} delta * @property {SeriesTree_Addrs_Delta} delta
* @property {SeriesTree_Addrs_AvgAmount} avgAmount
*/ */
/** /**
@@ -5148,11 +5204,11 @@ function createTransferPattern(client, acc) {
/** /**
* @typedef {Object} SeriesTree_Addrs_Reused_Events * @typedef {Object} SeriesTree_Addrs_Reused_Events
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5} outputToReusedAddrCount * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6} outputToReusedAddrCount
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6} outputToReusedAddrShare * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7} outputToReusedAddrShare
* @property {_1m1w1y24hBpsPercentRatioPattern} spendableOutputToReusedAddrShare * @property {_1m1w1y24hBpsPercentRatioPattern} spendableOutputToReusedAddrShare
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5} inputFromReusedAddrCount * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6} inputFromReusedAddrCount
* @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6} inputFromReusedAddrShare * @property {AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7} inputFromReusedAddrShare
* @property {_1m1w1y24hBlockPattern} activeReusedAddrCount * @property {_1m1w1y24hBlockPattern} activeReusedAddrCount
* @property {SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare} activeReusedAddrShare * @property {SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare} activeReusedAddrShare
*/ */
@@ -5212,6 +5268,19 @@ function createTransferPattern(client, acc) {
* @property {AbsoluteRatePattern} p2a * @property {AbsoluteRatePattern} p2a
*/ */
/**
* @typedef {Object} SeriesTree_Addrs_AvgAmount
* @property {AddrUtxoPattern} all
* @property {AddrUtxoPattern} p2pk65
* @property {AddrUtxoPattern} p2pk33
* @property {AddrUtxoPattern} p2pkh
* @property {AddrUtxoPattern} p2sh
* @property {AddrUtxoPattern} p2wpkh
* @property {AddrUtxoPattern} p2wsh
* @property {AddrUtxoPattern} p2tr
* @property {AddrUtxoPattern} p2a
*/
/** /**
* @typedef {Object} SeriesTree_Scripts * @typedef {Object} SeriesTree_Scripts
* @property {SeriesTree_Scripts_Raw} raw * @property {SeriesTree_Scripts_Raw} raw
@@ -6237,6 +6306,7 @@ function createTransferPattern(client, acc) {
* @property {SeriesTree_Cohorts_Utxo_All_Realized} realized * @property {SeriesTree_Cohorts_Utxo_All_Realized} realized
* @property {SeriesTree_Cohorts_Utxo_All_CostBasis} costBasis * @property {SeriesTree_Cohorts_Utxo_All_CostBasis} costBasis
* @property {SeriesTree_Cohorts_Utxo_All_Unrealized} unrealized * @property {SeriesTree_Cohorts_Utxo_All_Unrealized} unrealized
* @property {InPattern} investedCapital
*/ */
/** /**
@@ -6407,7 +6477,7 @@ function createTransferPattern(client, acc) {
* @property {SeriesTree_Cohorts_Utxo_All_Unrealized_Loss} loss * @property {SeriesTree_Cohorts_Utxo_All_Unrealized_Loss} loss
* @property {SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl} netPnl * @property {SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl} netPnl
* @property {CentsUsdPattern3} grossPnl * @property {CentsUsdPattern3} grossPnl
* @property {InPattern} investedCapital * @property {InPattern2} investedCapital
* @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInProfitRaw * @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInProfitRaw
* @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInLossRaw * @property {SeriesPattern18<CentsSquaredSats>} capitalizedCapInLossRaw
* @property {SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment} sentiment * @property {SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment} sentiment
@@ -6452,6 +6522,7 @@ function createTransferPattern(client, acc) {
* @property {SeriesTree_Cohorts_Utxo_Sth_Realized} realized * @property {SeriesTree_Cohorts_Utxo_Sth_Realized} realized
* @property {InMaxMinPerSupplyPattern} costBasis * @property {InMaxMinPerSupplyPattern} costBasis
* @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized * @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized
* @property {InPattern} investedCapital
*/ */
/** /**
@@ -6574,6 +6645,7 @@ function createTransferPattern(client, acc) {
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized} realized * @property {SeriesTree_Cohorts_Utxo_Lth_Realized} realized
* @property {InMaxMinPerSupplyPattern} costBasis * @property {InMaxMinPerSupplyPattern} costBasis
* @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized * @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized
* @property {InPattern} investedCapital
*/ */
/** /**
@@ -8515,8 +8587,8 @@ class BrkClient extends BrkClientBase {
funded: createSeriesPattern34(this, 'funded_addr_data'), funded: createSeriesPattern34(this, 'funded_addr_data'),
empty: createSeriesPattern35(this, 'empty_addr_data'), empty: createSeriesPattern35(this, 'empty_addr_data'),
}, },
funded: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(this, 'addr_count'), funded: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(this, 'addr_count'),
empty: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(this, 'empty_addr_count'), empty: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(this, 'empty_addr_count'),
activity: { activity: {
all: { all: {
reactivated: create_1m1w1y24hBlockPattern(this, 'reactivated_addrs'), reactivated: create_1m1w1y24hBlockPattern(this, 'reactivated_addrs'),
@@ -8534,16 +8606,16 @@ class BrkClient extends BrkClientBase {
p2tr: createActiveBidirectionalReactivatedReceivingSendingPattern(this, 'p2tr'), p2tr: createActiveBidirectionalReactivatedReceivingSendingPattern(this, 'p2tr'),
p2a: createActiveBidirectionalReactivatedReceivingSendingPattern(this, 'p2a'), p2a: createActiveBidirectionalReactivatedReceivingSendingPattern(this, 'p2a'),
}, },
total: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(this, 'total_addr_count'), total: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(this, 'total_addr_count'),
new: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(this, 'new_addr_count'), new: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(this, 'new_addr_count'),
reused: { reused: {
count: createFundedTotalPattern(this, 'reused_addr_count'), count: createFundedTotalPattern(this, 'reused_addr_count'),
events: { events: {
outputToReusedAddrCount: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(this, 'output_to_reused_addr_count'), outputToReusedAddrCount: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(this, 'output_to_reused_addr_count'),
outputToReusedAddrShare: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(this, 'output_to_reused_addr_share'), outputToReusedAddrShare: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7(this, 'output_to_reused_addr_share'),
spendableOutputToReusedAddrShare: create_1m1w1y24hBpsPercentRatioPattern(this, 'spendable_output_to_reused_addr_share'), spendableOutputToReusedAddrShare: create_1m1w1y24hBpsPercentRatioPattern(this, 'spendable_output_to_reused_addr_share'),
inputFromReusedAddrCount: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(this, 'input_from_reused_addr_count'), inputFromReusedAddrCount: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(this, 'input_from_reused_addr_count'),
inputFromReusedAddrShare: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(this, 'input_from_reused_addr_share'), inputFromReusedAddrShare: createAllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7(this, 'input_from_reused_addr_share'),
activeReusedAddrCount: create_1m1w1y24hBlockPattern(this, 'active_reused_addr_count'), activeReusedAddrCount: create_1m1w1y24hBlockPattern(this, 'active_reused_addr_count'),
activeReusedAddrShare: { activeReusedAddrShare: {
block: createSeriesPattern18(this, 'active_reused_addr_share'), block: createSeriesPattern18(this, 'active_reused_addr_share'),
@@ -8590,6 +8662,17 @@ class BrkClient extends BrkClientBase {
p2tr: createAbsoluteRatePattern(this, 'p2tr_addr_count'), p2tr: createAbsoluteRatePattern(this, 'p2tr_addr_count'),
p2a: createAbsoluteRatePattern(this, 'p2a_addr_count'), p2a: createAbsoluteRatePattern(this, 'p2a_addr_count'),
}, },
avgAmount: {
all: createAddrUtxoPattern(this, 'avg'),
p2pk65: createAddrUtxoPattern(this, 'p2pk65_avg'),
p2pk33: createAddrUtxoPattern(this, 'p2pk33_avg'),
p2pkh: createAddrUtxoPattern(this, 'p2pkh_avg'),
p2sh: createAddrUtxoPattern(this, 'p2sh_avg'),
p2wpkh: createAddrUtxoPattern(this, 'p2wpkh_avg'),
p2wsh: createAddrUtxoPattern(this, 'p2wsh_avg'),
p2tr: createAddrUtxoPattern(this, 'p2tr_avg'),
p2a: createAddrUtxoPattern(this, 'p2a_avg'),
},
}, },
scripts: { scripts: {
raw: { raw: {
@@ -9452,7 +9535,7 @@ class BrkClient extends BrkClientBase {
toOwnGrossPnl: createBpsPercentRatioPattern(this, 'net_unrealized_pnl_to_own_gross_pnl'), toOwnGrossPnl: createBpsPercentRatioPattern(this, 'net_unrealized_pnl_to_own_gross_pnl'),
}, },
grossPnl: createCentsUsdPattern3(this, 'unrealized_gross_pnl'), grossPnl: createCentsUsdPattern3(this, 'unrealized_gross_pnl'),
investedCapital: createInPattern(this, 'invested_capital_in'), investedCapital: createInPattern2(this, 'invested_capital_in'),
capitalizedCapInProfitRaw: createSeriesPattern18(this, 'capitalized_cap_in_profit_raw'), capitalizedCapInProfitRaw: createSeriesPattern18(this, 'capitalized_cap_in_profit_raw'),
capitalizedCapInLossRaw: createSeriesPattern18(this, 'capitalized_cap_in_loss_raw'), capitalizedCapInLossRaw: createSeriesPattern18(this, 'capitalized_cap_in_loss_raw'),
sentiment: { sentiment: {
@@ -9461,6 +9544,7 @@ class BrkClient extends BrkClientBase {
net: createCentsUsdPattern(this, 'net_sentiment'), net: createCentsUsdPattern(this, 'net_sentiment'),
}, },
}, },
investedCapital: createInPattern(this, 'invested_capital_in'),
}, },
sth: { sth: {
supply: createDeltaHalfInToTotalPattern2(this, 'sth_supply'), supply: createDeltaHalfInToTotalPattern2(this, 'sth_supply'),
@@ -9560,6 +9644,7 @@ class BrkClient extends BrkClientBase {
}, },
costBasis: createInMaxMinPerSupplyPattern(this, 'sth'), costBasis: createInMaxMinPerSupplyPattern(this, 'sth'),
unrealized: createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(this, 'sth'), unrealized: createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(this, 'sth'),
investedCapital: createInPattern(this, 'sth_invested_capital_in'),
}, },
lth: { lth: {
supply: createDeltaHalfInToTotalPattern2(this, 'lth_supply'), supply: createDeltaHalfInToTotalPattern2(this, 'lth_supply'),
@@ -9662,6 +9747,7 @@ class BrkClient extends BrkClientBase {
}, },
costBasis: createInMaxMinPerSupplyPattern(this, 'lth'), costBasis: createInMaxMinPerSupplyPattern(this, 'lth'),
unrealized: createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(this, 'lth'), unrealized: createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(this, 'lth'),
investedCapital: createInPattern(this, 'lth_invested_capital_in'),
}, },
ageRange: { ageRange: {
under1h: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'utxos_under_1h_old'), under1h: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'utxos_under_1h_old'),

View File

@@ -2738,7 +2738,7 @@ class IndexPct0Pct1Pct2Pct5Pct95Pct98Pct99ScorePattern:
self.pct99_5: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'pct99_5')) self.pct99_5: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'pct99_5'))
self.score: SeriesPattern1[StoredI8] = SeriesPattern1(client, _m(acc, 'score')) self.score: SeriesPattern1[StoredI8] = SeriesPattern1(client, _m(acc, 'score'))
class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5: class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -2753,7 +2753,7 @@ class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5:
self.p2wpkh: AverageBlockCumulativeSumPattern[StoredU64] = AverageBlockCumulativeSumPattern(client, _p('p2wpkh', acc)) self.p2wpkh: AverageBlockCumulativeSumPattern[StoredU64] = AverageBlockCumulativeSumPattern(client, _p('p2wpkh', acc))
self.p2wsh: AverageBlockCumulativeSumPattern[StoredU64] = AverageBlockCumulativeSumPattern(client, _p('p2wsh', acc)) self.p2wsh: AverageBlockCumulativeSumPattern[StoredU64] = AverageBlockCumulativeSumPattern(client, _p('p2wsh', acc))
class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3: class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -2768,7 +2768,7 @@ class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3:
self.p2wpkh: SeriesPattern1[StoredU64] = SeriesPattern1(client, _p('p2wpkh', acc)) self.p2wpkh: SeriesPattern1[StoredU64] = SeriesPattern1(client, _p('p2wpkh', acc))
self.p2wsh: SeriesPattern1[StoredU64] = SeriesPattern1(client, _p('p2wsh', acc)) self.p2wsh: SeriesPattern1[StoredU64] = SeriesPattern1(client, _p('p2wsh', acc))
class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6: class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -2806,7 +2806,7 @@ class CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2:
self.capitalized_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, _m(acc, 'capitalized_cap_in_loss_raw')) self.capitalized_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, _m(acc, 'capitalized_cap_in_loss_raw'))
self.capitalized_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, _m(acc, 'capitalized_cap_in_profit_raw')) self.capitalized_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, _m(acc, 'capitalized_cap_in_profit_raw'))
self.gross_pnl: CentsUsdPattern3 = CentsUsdPattern3(client, _m(acc, 'unrealized_gross_pnl')) self.gross_pnl: CentsUsdPattern3 = CentsUsdPattern3(client, _m(acc, 'unrealized_gross_pnl'))
self.invested_capital: InPattern = InPattern(client, _m(acc, 'invested_capital_in')) self.invested_capital: InPattern2 = InPattern2(client, _m(acc, 'invested_capital_in'))
self.loss: CentsNegativeToUsdPattern2 = CentsNegativeToUsdPattern2(client, _m(acc, 'unrealized_loss')) self.loss: CentsNegativeToUsdPattern2 = CentsNegativeToUsdPattern2(client, _m(acc, 'unrealized_loss'))
self.net_pnl: CentsToUsdPattern3 = CentsToUsdPattern3(client, _m(acc, 'net_unrealized_pnl')) self.net_pnl: CentsToUsdPattern3 = CentsToUsdPattern3(client, _m(acc, 'net_unrealized_pnl'))
self.nupl: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'nupl')) self.nupl: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'nupl'))
@@ -3066,7 +3066,7 @@ class BlockChangeCumulativeDeltaSumPattern:
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.block: CentsUsdPattern4 = CentsUsdPattern4(client, _m(acc, 'realized_pnl')) self.block: CentsUsdPattern4 = CentsUsdPattern4(client, _m(acc, 'realized_pnl'))
self.change_1m: ToPattern = ToPattern(client, _m(acc, 'pnl_change_1m_to')) self.change_1m: ToPattern2 = ToPattern2(client, _m(acc, 'pnl_change_1m_to'))
self.cumulative: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_pnl_cumulative')) self.cumulative: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_pnl_cumulative'))
self.delta: AbsoluteRatePattern2 = AbsoluteRatePattern2(client, _m(acc, 'realized_pnl_delta')) self.delta: AbsoluteRatePattern2 = AbsoluteRatePattern2(client, _m(acc, 'realized_pnl_delta'))
self.sum: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, _m(acc, 'realized_pnl_sum')) self.sum: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, _m(acc, 'realized_pnl_sum'))
@@ -3564,6 +3564,14 @@ class AbsoluteRatePattern2:
self.absolute: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, acc) self.absolute: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, acc)
self.rate: _1m1w1y24hPattern2 = _1m1w1y24hPattern2(client, acc) self.rate: _1m1w1y24hPattern2 = _1m1w1y24hPattern2(client, acc)
class AddrUtxoPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.addr: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'addr_amount'))
self.utxo: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'utxo_amount'))
class AllSthPattern2: class AllSthPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -3681,10 +3689,10 @@ class FundedTotalPattern:
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, acc) self.funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, acc)
self.total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, _p('total', acc)) self.total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, _p('total', acc))
class InPattern: class InPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -3692,6 +3700,14 @@ class InPattern:
self.in_loss: CentsUsdPattern3 = CentsUsdPattern3(client, _m(acc, 'loss')) self.in_loss: CentsUsdPattern3 = CentsUsdPattern3(client, _m(acc, 'loss'))
self.in_profit: CentsUsdPattern3 = CentsUsdPattern3(client, _m(acc, 'profit')) self.in_profit: CentsUsdPattern3 = CentsUsdPattern3(client, _m(acc, 'profit'))
class InPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.in_loss: ToPattern = ToPattern(client, _m(acc, 'loss_to_own'))
self.in_profit: ToPattern = ToPattern(client, _m(acc, 'profit_to_own'))
class PerPattern: class PerPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -3720,7 +3736,7 @@ class SdSmaPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
pass pass
class ToPattern: class ToPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -3749,6 +3765,13 @@ class PricePattern:
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.price: BpsCentsPercentilesRatioSatsUsdPattern = BpsCentsPercentilesRatioSatsUsdPattern(client, acc) self.price: BpsCentsPercentilesRatioSatsUsdPattern = BpsCentsPercentilesRatioSatsUsdPattern(client, acc)
class ToPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.to_own: BpsPercentRatioPattern2 = BpsPercentRatioPattern2(client, acc)
class TransferPattern: class TransferPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -4269,11 +4292,11 @@ class SeriesTree_Addrs_Reused_Events:
"""Series tree node.""" """Series tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(client, 'output_to_reused_addr_count') self.output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, 'output_to_reused_addr_count')
self.output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, 'output_to_reused_addr_share') self.output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7(client, 'output_to_reused_addr_share')
self.spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern = _1m1w1y24hBpsPercentRatioPattern(client, 'spendable_output_to_reused_addr_share') self.spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern = _1m1w1y24hBpsPercentRatioPattern(client, 'spendable_output_to_reused_addr_share')
self.input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(client, 'input_from_reused_addr_count') self.input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, 'input_from_reused_addr_count')
self.input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, 'input_from_reused_addr_share') self.input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7(client, 'input_from_reused_addr_share')
self.active_reused_addr_count: _1m1w1y24hBlockPattern = _1m1w1y24hBlockPattern(client, 'active_reused_addr_count') self.active_reused_addr_count: _1m1w1y24hBlockPattern = _1m1w1y24hBlockPattern(client, 'active_reused_addr_count')
self.active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare = SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare(client) self.active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare = SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare(client)
@@ -4334,6 +4357,20 @@ class SeriesTree_Addrs_Delta:
self.p2tr: AbsoluteRatePattern = AbsoluteRatePattern(client, 'p2tr_addr_count') self.p2tr: AbsoluteRatePattern = AbsoluteRatePattern(client, 'p2tr_addr_count')
self.p2a: AbsoluteRatePattern = AbsoluteRatePattern(client, 'p2a_addr_count') self.p2a: AbsoluteRatePattern = AbsoluteRatePattern(client, 'p2a_addr_count')
class SeriesTree_Addrs_AvgAmount:
"""Series tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self.all: AddrUtxoPattern = AddrUtxoPattern(client, 'avg')
self.p2pk65: AddrUtxoPattern = AddrUtxoPattern(client, 'p2pk65_avg')
self.p2pk33: AddrUtxoPattern = AddrUtxoPattern(client, 'p2pk33_avg')
self.p2pkh: AddrUtxoPattern = AddrUtxoPattern(client, 'p2pkh_avg')
self.p2sh: AddrUtxoPattern = AddrUtxoPattern(client, 'p2sh_avg')
self.p2wpkh: AddrUtxoPattern = AddrUtxoPattern(client, 'p2wpkh_avg')
self.p2wsh: AddrUtxoPattern = AddrUtxoPattern(client, 'p2wsh_avg')
self.p2tr: AddrUtxoPattern = AddrUtxoPattern(client, 'p2tr_avg')
self.p2a: AddrUtxoPattern = AddrUtxoPattern(client, 'p2a_avg')
class SeriesTree_Addrs: class SeriesTree_Addrs:
"""Series tree node.""" """Series tree node."""
@@ -4341,14 +4378,15 @@ class SeriesTree_Addrs:
self.raw: SeriesTree_Addrs_Raw = SeriesTree_Addrs_Raw(client) self.raw: SeriesTree_Addrs_Raw = SeriesTree_Addrs_Raw(client)
self.indexes: SeriesTree_Addrs_Indexes = SeriesTree_Addrs_Indexes(client) self.indexes: SeriesTree_Addrs_Indexes = SeriesTree_Addrs_Indexes(client)
self.data: SeriesTree_Addrs_Data = SeriesTree_Addrs_Data(client) self.data: SeriesTree_Addrs_Data = SeriesTree_Addrs_Data(client)
self.funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, 'addr_count') self.funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, 'addr_count')
self.empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, 'empty_addr_count') self.empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, 'empty_addr_count')
self.activity: SeriesTree_Addrs_Activity = SeriesTree_Addrs_Activity(client) self.activity: SeriesTree_Addrs_Activity = SeriesTree_Addrs_Activity(client)
self.total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3(client, 'total_addr_count') self.total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4(client, 'total_addr_count')
self.new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5(client, 'new_addr_count') self.new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 = AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6(client, 'new_addr_count')
self.reused: SeriesTree_Addrs_Reused = SeriesTree_Addrs_Reused(client) self.reused: SeriesTree_Addrs_Reused = SeriesTree_Addrs_Reused(client)
self.exposed: SeriesTree_Addrs_Exposed = SeriesTree_Addrs_Exposed(client) self.exposed: SeriesTree_Addrs_Exposed = SeriesTree_Addrs_Exposed(client)
self.delta: SeriesTree_Addrs_Delta = SeriesTree_Addrs_Delta(client) self.delta: SeriesTree_Addrs_Delta = SeriesTree_Addrs_Delta(client)
self.avg_amount: SeriesTree_Addrs_AvgAmount = SeriesTree_Addrs_AvgAmount(client)
class SeriesTree_Scripts_Raw_Empty: class SeriesTree_Scripts_Raw_Empty:
"""Series tree node.""" """Series tree node."""
@@ -5659,7 +5697,7 @@ class SeriesTree_Cohorts_Utxo_All_Unrealized:
self.loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss = SeriesTree_Cohorts_Utxo_All_Unrealized_Loss(client) self.loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss = SeriesTree_Cohorts_Utxo_All_Unrealized_Loss(client)
self.net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl = SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl(client) self.net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl = SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl(client)
self.gross_pnl: CentsUsdPattern3 = CentsUsdPattern3(client, 'unrealized_gross_pnl') self.gross_pnl: CentsUsdPattern3 = CentsUsdPattern3(client, 'unrealized_gross_pnl')
self.invested_capital: InPattern = InPattern(client, 'invested_capital_in') self.invested_capital: InPattern2 = InPattern2(client, 'invested_capital_in')
self.capitalized_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'capitalized_cap_in_profit_raw') self.capitalized_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'capitalized_cap_in_profit_raw')
self.capitalized_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'capitalized_cap_in_loss_raw') self.capitalized_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'capitalized_cap_in_loss_raw')
self.sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment(client) self.sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment(client)
@@ -5674,6 +5712,7 @@ class SeriesTree_Cohorts_Utxo_All:
self.realized: SeriesTree_Cohorts_Utxo_All_Realized = SeriesTree_Cohorts_Utxo_All_Realized(client) self.realized: SeriesTree_Cohorts_Utxo_All_Realized = SeriesTree_Cohorts_Utxo_All_Realized(client)
self.cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis = SeriesTree_Cohorts_Utxo_All_CostBasis(client) self.cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis = SeriesTree_Cohorts_Utxo_All_CostBasis(client)
self.unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized = SeriesTree_Cohorts_Utxo_All_Unrealized(client) self.unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized = SeriesTree_Cohorts_Utxo_All_Unrealized(client)
self.invested_capital: InPattern = InPattern(client, 'invested_capital_in')
class SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev_All: class SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev_All:
"""Series tree node.""" """Series tree node."""
@@ -5804,6 +5843,7 @@ class SeriesTree_Cohorts_Utxo_Sth:
self.realized: SeriesTree_Cohorts_Utxo_Sth_Realized = SeriesTree_Cohorts_Utxo_Sth_Realized(client) self.realized: SeriesTree_Cohorts_Utxo_Sth_Realized = SeriesTree_Cohorts_Utxo_Sth_Realized(client)
self.cost_basis: InMaxMinPerSupplyPattern = InMaxMinPerSupplyPattern(client, 'sth') self.cost_basis: InMaxMinPerSupplyPattern = InMaxMinPerSupplyPattern(client, 'sth')
self.unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 = CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client, 'sth') self.unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 = CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client, 'sth')
self.invested_capital: InPattern = InPattern(client, 'sth_invested_capital_in')
class SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev_All: class SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev_All:
"""Series tree node.""" """Series tree node."""
@@ -5941,6 +5981,7 @@ class SeriesTree_Cohorts_Utxo_Lth:
self.realized: SeriesTree_Cohorts_Utxo_Lth_Realized = SeriesTree_Cohorts_Utxo_Lth_Realized(client) self.realized: SeriesTree_Cohorts_Utxo_Lth_Realized = SeriesTree_Cohorts_Utxo_Lth_Realized(client)
self.cost_basis: InMaxMinPerSupplyPattern = InMaxMinPerSupplyPattern(client, 'lth') self.cost_basis: InMaxMinPerSupplyPattern = InMaxMinPerSupplyPattern(client, 'lth')
self.unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 = CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client, 'lth') self.unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 = CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client, 'lth')
self.invested_capital: InPattern = InPattern(client, 'lth_invested_capital_in')
class SeriesTree_Cohorts_Utxo_AgeRange: class SeriesTree_Cohorts_Utxo_AgeRange:
"""Series tree node.""" """Series tree node."""

View File

@@ -0,0 +1,276 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>bitview logo (svg)</title>
<style>
/* Website's Lilex (the site's --font-mono). */
@font-face {
font-family: Lilex;
src: url("../fonts/Lilex[wght]-v2_620.woff2") format("woff2");
font-style: normal;
font-weight: 100 700;
font-display: block;
}
@font-face {
font-family: Lilex;
src: url("../fonts/Lilex-Italic[wght]-v2_620.woff2.woff2") format("woff2");
font-style: italic;
font-weight: 100 700;
font-display: block;
}
:root {
color-scheme: light dark;
--cube: 4.5rem;
--orange: oklch(67.64% 0.191 44.41);
--white: oklch(95% 0 0);
--black: oklch(15% 0 0);
--light-gray: oklch(90% 0 0);
--dark-gray: oklch(20% 0 0);
--border-color: light-dark(var(--light-gray), var(--dark-gray));
--background-color: light-dark(var(--white), var(--black));
--fill: 0.5;
--empty-alpha: 0.3;
--face-step: 0.033;
--iso-scale: 0.866;
--blur-stddev: 3;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
}
/* ---- page chrome ---- */
html, body { margin: 0; padding: 0; }
body {
font: 14px/1.4 -apple-system, system-ui, sans-serif;
color: #111;
background: #f7f8fa;
}
.wrap { max-width: 1440px; margin: 0 auto; padding: 40px 24px 80px; }
section { margin: 0 0 12px; }
.row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
}
.controls {
display: flex;
gap: 16px;
align-items: center;
margin: 0 0 24px;
font-size: 13px;
color: #444;
}
.controls select { font-size: 13px; padding: 2px 6px; }
.tile {
position: relative;
aspect-ratio: 1;
border-radius: 14px;
display: grid; place-items: center;
overflow: hidden;
box-shadow: 0 0 0 1px rgba(0,0,0,0.08);
}
.tile .label {
position: absolute; left: 10px; bottom: 8px;
font: 11px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
color: rgba(0,0,0,0.55);
background: rgba(255,255,255,0.7); padding: 2px 6px; border-radius: 4px;
backdrop-filter: blur(6px);
}
.tile.scheme-light { color-scheme: light; }
.tile.scheme-dark { color-scheme: dark; color: #e8e8ea; }
.tile.scheme-dark .label { color: rgba(255,255,255,0.75); background: rgba(0,0,0,0.4); }
.bg-auto { background: var(--background-color); }
.bg-paper { background: light-dark(#f0ece3, #2a2823); }
.bg-gradient { background: linear-gradient(135deg, oklch(70% 0.16 260), oklch(72% 0.19 330)); }
.bg-image-1 { background: url('https://picsum.photos/seed/brk1/440/440') center/cover; }
.bg-image-2 { background: url('https://picsum.photos/seed/brk2/440/440') center/cover; }
/* ---- cube slot: just holds the svg ---- */
.logo-slot {
position: relative;
width: 160px; height: 160px;
display: grid; place-items: center;
}
.logo-slot svg {
/* Iso cube silhouette is 2·iso × 2 (taller than wide, aspect
sqrt(3)/2 : 1). The viewBox is square 0 0 200 200 for clean
polygon coordinates; preserveAspectRatio="none" stretches it
into the right aspect at render time. */
width: calc(var(--cube) * var(--iso-scale) * 2);
height: calc(var(--cube) * 2);
/* Frost: backdrop-filter on the non-transformed <svg> (Safari
honours it) clipped to the hex silhouette so the blur only
shows where the cube's translucent faces show through. */
clip-path: polygon(
50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%
);
backdrop-filter: blur(3px);
-webkit-backdrop-filter: blur(3px);
}
/* ---- cube face colors (derived from --face-color, same logic
as website/styles/panes/explorer.css) ---- */
svg.cube {
--face-color: var(--orange);
--face-right: light-dark(
oklch(from var(--face-color) calc(l - var(--face-step) * 2) c h),
var(--face-color)
);
--face-left: light-dark(
oklch(from var(--face-color) calc(l - var(--face-step)) c h),
oklch(from var(--face-color) calc(l + var(--face-step)) c h)
);
--face-top: light-dark(
var(--face-color),
oklch(from var(--face-color) calc(l + var(--face-step) * 2) c h)
);
--face-bottom: oklch(from var(--face-color) calc(l - var(--face-step) * 3) c h);
color: light-dark(var(--black), var(--white));
}
/* Glass fills — translucent (--empty-alpha).
Front faces (visible in iso): top, right, left.
Rear faces (hidden in iso but visible through the translucent
fronts as "interior depth"): bottom (y-), rear-left (x-),
rear-right (z-). Colors mirror the HTML demo:
rear bottom → face-bottom
rear-left (x-) → face-top
rear-right (z-) → face-left
Liquid polygons are opaque, drawn between rear and front. */
svg.cube .glass-top { fill: var(--face-top); fill-opacity: var(--empty-alpha); }
svg.cube .glass-right { fill: var(--face-right); fill-opacity: var(--empty-alpha); }
svg.cube .glass-left { fill: var(--face-left); fill-opacity: var(--empty-alpha); }
svg.cube .glass-bottom { fill: var(--face-bottom); fill-opacity: var(--empty-alpha); }
svg.cube .glass-rear-left { fill: var(--face-top); fill-opacity: var(--empty-alpha); }
svg.cube .glass-rear-right { fill: var(--face-left); fill-opacity: var(--empty-alpha); }
svg.cube .liquid-top { fill: var(--face-top); }
svg.cube .liquid-right { fill: var(--face-right); }
svg.cube .liquid-left { fill: var(--face-left); }
</style>
</head>
<body>
<div class="wrap">
<div class="controls">
<span>SVG cube — blur via SVG <code>feGaussianBlur</code> with <code>BackgroundImage</code>.</span>
</div>
<!-- Cube template.
viewBox 0 0 200 200, hex center = (100, 100), iso half-width = 86.6.
Points: V_top=(100,0) VR_upper=(187,50) VR_lower=(187,150)
V_bottom=(100,200) VL_lower=(13,150) VL_upper=(13,50)
V_center=(100,100)
Face polygons (3 visible):
top = V_upper_left, V_top, V_upper_right, V_center
right = V_upper_right, V_lower_right, V_bottom, V_center
left = V_upper_left, V_lower_left, V_bottom, V_center
Liquid surface at fill f in [0,1] — 4 corners:
(13, 150 - 100f) (187, 150 - 100f) (100, 100 - 100f) (100, 200 - 100f)
JS computes liquid sub-polygons per tile based on --fill. -->
<template id="logo-template">
<div class="logo-slot">
<svg class="cube" viewBox="0 0 200 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<!-- Rear glass (hidden 3D faces at their iso positions).
Drawn first so translucent front faces composite over
them for a "depth" look. -->
<g class="glass-rear">
<polygon class="glass-bottom" points="100,100 200,150 100,200 0,150"/>
<polygon class="glass-rear-left" points="100,100 0,150 0,50 100,0"/>
<polygon class="glass-rear-right" points="100,100 200,150 200,50 100,0"/>
</g>
<!-- Liquid (opaque): JS injects polygons sized from --fill. -->
<g class="liquid"></g>
<!-- Front glass (visible 3D faces). -->
<g class="glass-front">
<polygon class="glass-top" points="0,50 100,0 200,50 100,100"/>
<polygon class="glass-right" points="200,50 200,150 100,200 100,100"/>
<polygon class="glass-left" points="0,50 0,150 100,200 100,100"/>
</g>
</svg>
</div>
</template>
<section>
<div class="row" id="row"></div>
</section>
<section>
<div class="row" id="fills"></div>
</section>
</div>
<script>
// Liquid surface at fill f in [0,1]: horizontal cross-section of
// the cube at y=f, projected to viewBox (hex fills 200×200).
const surface = (f) => ({
tl: [0, 150 - 100 * f], // left side at surface
tr: [200, 150 - 100 * f], // right side at surface
back: [100, 100 - 100 * f], // back vertex (upper)
front: [100, 200 - 100 * f], // front vertex (lower)
});
// Liquid = 3 sub-polygons of the 3 visible faces, clipped at the
// surface line. The surface rhombus has 4 corners:
// back — back vertex of the cross-section
// tr/tl — right/left side vertices of the cross-section (shared
// with the right/left visible faces)
// front — front vertex of the cross-section (shared with both
// side faces' front edge)
// Each side face's upper edge at the surface runs from its side
// corner (tr or tl) to the shared front corner.
const liquidPolygons = (f) => {
if (f <= 0) return [];
const s = surface(f);
return [
{ cls: 'liquid-top', pts: [s.back, s.tr, s.front, s.tl] },
{ cls: 'liquid-right', pts: [s.tr, [200, 150], [100, 200], s.front] },
{ cls: 'liquid-left', pts: [s.tl, [0, 150], [100, 200], s.front] },
];
};
const template = document.getElementById('logo-template');
const SVGNS = 'http://www.w3.org/2000/svg';
const makeLogo = ({ fill = 0.5, faceColor, cubeScheme } = {}) => {
const slot = template.content.cloneNode(true).firstElementChild;
const svg = slot.querySelector('svg');
svg.style.setProperty('--fill', String(fill));
if (faceColor) svg.style.setProperty('--face-color', faceColor);
svg.style.setProperty('color-scheme', cubeScheme ?? 'light');
const liquid = svg.querySelector('.liquid');
for (const { cls, pts } of liquidPolygons(fill)) {
const poly = document.createElementNS(SVGNS, 'polygon');
poly.setAttribute('class', cls);
poly.setAttribute('points', pts.map(p => p.join(',')).join(' '));
liquid.appendChild(poly);
}
return slot;
};
const makeTile = (cls, label, content) => {
const tile = document.createElement('div');
tile.className = `tile ${cls}`;
tile.appendChild(content);
const lbl = document.createElement('span');
lbl.className = 'label';
lbl.textContent = label;
tile.appendChild(lbl);
return tile;
};
// Row 1: cube on each background.
const row = document.getElementById('row');
row.appendChild(makeTile('bg-auto scheme-light', 'light', makeLogo()));
row.appendChild(makeTile('bg-auto scheme-dark', 'dark', makeLogo()));
row.appendChild(makeTile('bg-paper scheme-light', 'paper', makeLogo()));
row.appendChild(makeTile('bg-gradient scheme-light', 'gradient', makeLogo()));
row.appendChild(makeTile('bg-image-1 scheme-light', 'img 1', makeLogo()));
row.appendChild(makeTile('bg-image-2 scheme-light', 'img 2', makeLogo()));
// Row 2: fill levels.
const fills = document.getElementById('fills');
for (const f of [0, 0.1, 0.25, 0.5, 0.75, 1])
fills.appendChild(makeTile('bg-auto scheme-light', `fill ${f}`, makeLogo({ fill: f })));
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -128,6 +128,9 @@
* *
* Address count pattern (base + delta with absolute + rate) * Address count pattern (base + delta with absolute + rate)
* @typedef {Brk.BaseDeltaPattern} AddrCountPattern * @typedef {Brk.BaseDeltaPattern} AddrCountPattern
* @typedef {Brk.AddrUtxoPattern} AvgAmountPattern
* @typedef {Brk.SeriesTree_Addrs_Exposed} ExposedTree
* @typedef {Brk.SeriesTree_Addrs_Reused} ReusedTree
*/ */
/** /**

View File

@@ -273,6 +273,15 @@ function createBlockCube(block) {
function createCube() { function createCube() {
const cubeElement = document.createElement("div"); const cubeElement = document.createElement("div");
cubeElement.classList.add("cube"); cubeElement.classList.add("cube");
const bottomElement = document.createElement("div");
bottomElement.classList.add("face", "bottom");
cubeElement.append(bottomElement);
const rearRightElement = document.createElement("div");
rearRightElement.classList.add("face", "rear-right");
cubeElement.append(rearRightElement);
const rearLeftElement = document.createElement("div");
rearLeftElement.classList.add("face", "rear-left");
cubeElement.append(rearLeftElement);
const innerTopElement = document.createElement("div"); const innerTopElement = document.createElement("div");
innerTopElement.classList.add("face", "inner-top"); innerTopElement.classList.add("face", "inner-top");
cubeElement.append(innerTopElement); cubeElement.append(innerTopElement);

View File

@@ -47,6 +47,7 @@ export function buildCohortData() {
base: addrs.funded.all, base: addrs.funded.all,
delta: addrs.delta.all, delta: addrs.delta.all,
}, },
avgAmount: addrs.avgAmount.all,
}; };
const shortNames = TERM_NAMES.short; const shortNames = TERM_NAMES.short;
@@ -174,6 +175,9 @@ export function buildCohortData() {
base: addrs.funded[key], base: addrs.funded[key],
delta: addrs.delta[key], delta: addrs.delta[key],
}, },
avgAmount: addrs.avgAmount[key],
exposed: addrs.exposed,
reused: addrs.reused,
}; };
}); });

View File

@@ -28,7 +28,7 @@ import {
groupedWindowsCumulativeWithAll, groupedWindowsCumulativeWithAll,
} from "../shared.js"; } from "../shared.js";
import { colors } from "../../utils/colors.js"; import { colors } from "../../utils/colors.js";
import { priceLines } from "../constants.js"; import { priceLine } from "../constants.js";
/** /**
* Simple supply series (total + half only, no profit/loss) * Simple supply series (total + half only, no profit/loss)
@@ -165,41 +165,44 @@ function groupedDeltaItems(list, all, getDelta, unit, title, name) {
// ============================================================================ // ============================================================================
/** /**
* Profitability chart (in profit + in loss supply) * Amount chart: total + halved + in profit + in loss in sats/btc/usd.
* @param {{ total: AnyValuePattern, half: AnyValuePattern, inProfit: AnyValuePattern, inLoss: AnyValuePattern }} supply * @param {{ total: AnyValuePattern, half: AnyValuePattern, inProfit: AnyValuePattern, inLoss: AnyValuePattern }} supply
* @param {(name: string) => string} title * @param {(name: string) => string} title
* @returns {PartialChartOption} * @returns {PartialChartOption}
*/ */
function profitabilityChart(supply, title) { function profitabilityAmountChart(supply, title) {
return { return {
name: "Profitability", name: "Amount",
title: title("Supply Profitability"), title: title("Supply Profitability"),
bottom: [ bottom: [
...satsBtcUsd({ ...satsBtcUsd({ pattern: supply.total, name: "Total", color: colors.default }),
pattern: supply.total, ...satsBtcUsd({ pattern: supply.inProfit, name: "In Profit", color: colors.profit }),
name: "Total", ...satsBtcUsd({ pattern: supply.inLoss, name: "In Loss", color: colors.loss }),
color: colors.default, ...satsBtcUsd({ pattern: supply.half, name: "Halved", color: colors.gray, style: 4 }),
}),
...satsBtcUsd({
pattern: supply.inProfit,
name: "In Profit",
color: colors.profit,
}),
...satsBtcUsd({
pattern: supply.inLoss,
name: "In Loss",
color: colors.loss,
}),
...satsBtcUsd({
pattern: supply.half,
name: "Halved",
color: colors.gray,
style: 4,
}),
], ],
}; };
} }
/**
* Share chart: in profit / in loss as % of own supply.
* @param {{ inProfit: { toOwn: { percent: AnySeriesPattern, ratio: AnySeriesPattern } }, inLoss: { toOwn: { percent: AnySeriesPattern, ratio: AnySeriesPattern } } }} supply
* @param {(name: string) => string} title
* @returns {PartialChartOption}
*/
function profitabilityShareChart(supply, title) {
return {
name: "Share",
title: title("Supply Profitability"),
bottom: [
...percentRatio({ pattern: supply.inProfit.toOwn, name: "In Profit", color: colors.profit }),
...percentRatio({ pattern: supply.inLoss.toOwn, name: "In Loss", color: colors.loss }),
priceLine({ number: 100, color: colors.default, style: 0, unit: Unit.percentage }),
priceLine({ number: 50, unit: Unit.percentage }),
],
};
}
/** /**
* @param {{ toCirculating: PercentRatioPattern, inProfit: { toCirculating: PercentRatioPattern }, inLoss: { toCirculating: PercentRatioPattern } }} supply * @param {{ toCirculating: PercentRatioPattern, inProfit: { toCirculating: PercentRatioPattern }, inLoss: { toCirculating: PercentRatioPattern } }} supply
* @param {(name: string) => string} title * @param {(name: string) => string} title
@@ -207,8 +210,8 @@ function profitabilityChart(supply, title) {
*/ */
function circulatingChart(supply, title) { function circulatingChart(supply, title) {
return { return {
name: "% of Circulating", name: "Dominance",
title: title("Supply (% of Circulating)"), title: title("Supply Dominance"),
bottom: [ bottom: [
...percentRatio({ pattern: supply.toCirculating, name: "Total", color: colors.default }), ...percentRatio({ pattern: supply.toCirculating, name: "Total", color: colors.default }),
...percentRatio({ pattern: supply.inProfit.toCirculating, name: "In Profit", color: colors.profit }), ...percentRatio({ pattern: supply.inProfit.toCirculating, name: "In Profit", color: colors.profit }),
@@ -217,23 +220,6 @@ function circulatingChart(supply, title) {
}; };
} }
/**
* @param {{ inProfit: { toOwn: { percent: AnySeriesPattern, ratio: AnySeriesPattern } }, inLoss: { toOwn: { percent: AnySeriesPattern, ratio: AnySeriesPattern } } }} supply
* @param {(name: string) => string} title
* @returns {PartialChartOption}
*/
function ownSupplyChart(supply, title) {
return {
name: "% of Own Supply",
title: title("Supply (% of Own)"),
bottom: [
...percentRatio({ pattern: supply.inProfit.toOwn, name: "In Profit", color: colors.profit }),
...percentRatio({ pattern: supply.inLoss.toOwn, name: "In Loss", color: colors.loss }),
...priceLines({ numbers: [100, 50, 0], unit: Unit.percentage }),
],
};
}
/** /**
* @param {OutputsPattern} outputs * @param {OutputsPattern} outputs
* @param {Color} color * @param {Color} color
@@ -330,8 +316,13 @@ export function createHoldingsSectionAll({ cohort, title }) {
title: title("Supply"), title: title("Supply"),
bottom: simpleSupplySeries(supply), bottom: simpleSupplySeries(supply),
}, },
profitabilityChart(supply, title), {
ownSupplyChart(supply, title), name: "Profitability",
tree: [
profitabilityAmountChart(supply, title),
profitabilityShareChart(supply, title),
],
},
...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"), ...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"),
], ],
}, },
@@ -355,9 +346,14 @@ export function createHoldingsSectionWithRelative({ cohort, title }) {
title: title("Supply"), title: title("Supply"),
bottom: simpleSupplySeries(supply), bottom: simpleSupplySeries(supply),
}, },
profitabilityChart(supply, title), {
name: "Profitability",
tree: [
profitabilityAmountChart(supply, title),
profitabilityShareChart(supply, title),
circulatingChart(supply, title), circulatingChart(supply, title),
ownSupplyChart(supply, title), ],
},
...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"), ...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"),
], ],
}, },
@@ -380,8 +376,13 @@ export function createHoldingsSectionWithOwnSupply({ cohort, title }) {
title: title("Supply"), title: title("Supply"),
bottom: simpleSupplySeries(supply), bottom: simpleSupplySeries(supply),
}, },
profitabilityChart(supply, title), {
name: "Profitability",
tree: [
profitabilityAmountChart(supply, title),
circulatingChart(supply, title), circulatingChart(supply, title),
],
},
...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"), ...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"),
], ],
}, },
@@ -404,7 +405,10 @@ export function createHoldingsSectionWithProfitLoss({ cohort, title }) {
title: title("Supply"), title: title("Supply"),
bottom: simpleSupplySeries(supply), bottom: simpleSupplySeries(supply),
}, },
profitabilityChart(supply, title), {
name: "Profitability",
tree: [profitabilityAmountChart(supply, title)],
},
...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"), ...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"),
], ],
}, },
@@ -427,7 +431,10 @@ export function createHoldingsSectionAddress({ cohort, title }) {
title: title("Supply"), title: title("Supply"),
bottom: simpleSupplySeries(supply), bottom: simpleSupplySeries(supply),
}, },
profitabilityChart(supply, title), {
name: "Profitability",
tree: [profitabilityAmountChart(supply, title)],
},
...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"), ...singleDeltaItems(supply.delta, Unit.sats, title, "Supply"),
], ],
}, },
@@ -502,7 +509,10 @@ export function createGroupedHoldingsSectionAddress({ list, all, title }) {
name: "Supply", name: "Supply",
tree: [ tree: [
groupedSupplyTotal(list, all, title), groupedSupplyTotal(list, all, title),
...groupedSupplyProfitLoss(list, all, title), {
name: "Profitability",
tree: groupedSupplyProfitLoss(list, all, title),
},
...groupedDeltaItems(list, all, (c) => c.tree.supply.delta, Unit.sats, title, "Supply"), ...groupedDeltaItems(list, all, (c) => c.tree.supply.delta, Unit.sats, title, "Supply"),
], ],
}, },
@@ -520,6 +530,25 @@ export function createGroupedHoldingsSectionAddress({ list, all, title }) {
...groupedDeltaItems(list, all, (c) => c.addressCount.delta, Unit.count, title, "Address Count"), ...groupedDeltaItems(list, all, (c) => c.addressCount.delta, Unit.count, title, "Address Count"),
], ],
}, },
{
name: "Average Holdings",
tree: [
{
name: "Per UTXO",
title: title("Average Holdings per UTXO"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, avgAmount }) =>
satsBtcUsd({ pattern: avgAmount.utxo, name, color }),
),
},
{
name: "Per Address",
title: title("Average Holdings per Funded Address"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, avgAmount }) =>
satsBtcUsd({ pattern: avgAmount.addr, name, color }),
),
},
],
},
]; ];
} }

View File

@@ -14,6 +14,9 @@ import {
formatCohortTitle, formatCohortTitle,
satsBtcUsd, satsBtcUsd,
satsBtcUsdFullTree, satsBtcUsdFullTree,
avgHoldingsSubtree,
exposedSubtree,
reusedSubtree,
} from "../shared.js"; } from "../shared.js";
import { import {
ROLLING_WINDOWS, ROLLING_WINDOWS,
@@ -103,6 +106,7 @@ export function createCohortFolderAll(cohort) {
createCostBasisSectionWithPercentiles({ cohort, title }), createCostBasisSectionWithPercentiles({ cohort, title }),
createProfitabilitySectionAll({ cohort, title }), createProfitabilitySectionAll({ cohort, title }),
createActivitySectionWithAdjusted({ cohort, title }), createActivitySectionWithAdjusted({ cohort, title }),
avgHoldingsSubtree(cohort.avgAmount, title),
], ],
}; };
} }
@@ -259,6 +263,9 @@ export function createCohortFolderAddress(cohort) {
createPricesSectionBasic({ cohort, title }), createPricesSectionBasic({ cohort, title }),
createProfitabilitySectionWithProfitLoss({ cohort, title }), createProfitabilitySectionWithProfitLoss({ cohort, title }),
createActivitySectionMinimal({ cohort, title }), createActivitySectionMinimal({ cohort, title }),
avgHoldingsSubtree(cohort.avgAmount, title),
reusedSubtree(cohort.reused, cohort.key, title),
exposedSubtree(cohort.exposed, cohort.key, title),
], ],
}; };
} }

View File

@@ -6,6 +6,7 @@ import { Unit } from "../../utils/units.js";
import { colors } from "../../utils/colors.js"; import { colors } from "../../utils/colors.js";
import { ROLLING_WINDOWS, line, baseline, mapWindows, sumsTreeBaseline, rollingPercentRatioTree, percentRatio, percentRatioBaseline } from "../series.js"; import { ROLLING_WINDOWS, line, baseline, mapWindows, sumsTreeBaseline, rollingPercentRatioTree, percentRatio, percentRatioBaseline } from "../series.js";
import { ratioBottomSeries, mapCohortsWithAll, flatMapCohortsWithAll } from "../shared.js"; import { ratioBottomSeries, mapCohortsWithAll, flatMapCohortsWithAll } from "../shared.js";
import { priceLine } from "../constants.js";
// ============================================================================ // ============================================================================
// Shared building blocks // Shared building blocks
@@ -80,6 +81,9 @@ export function createValuationSectionFull({ cohort, title }) {
{ name: "Total", title: title("Realized Cap"), bottom: [line({ series: tree.realized.cap.usd, name: "Realized Cap", color, unit: Unit.usd })] }, { name: "Total", title: title("Realized Cap"), bottom: [line({ series: tree.realized.cap.usd, name: "Realized Cap", color, unit: Unit.usd })] },
{ {
name: "Profitability", name: "Profitability",
tree: [
{
name: "Amount",
title: title("Invested Capital"), title: title("Invested Capital"),
bottom: [ bottom: [
line({ series: tree.realized.cap.usd, name: "Total", color: colors.default, unit: Unit.usd }), line({ series: tree.realized.cap.usd, name: "Total", color: colors.default, unit: Unit.usd }),
@@ -87,6 +91,18 @@ export function createValuationSectionFull({ cohort, title }) {
line({ series: tree.unrealized.investedCapital.inLoss.usd, name: "In Loss", color: colors.loss, unit: Unit.usd }), line({ series: tree.unrealized.investedCapital.inLoss.usd, name: "In Loss", color: colors.loss, unit: Unit.usd }),
], ],
}, },
{
name: "Share",
title: title("Invested Capital Profitability"),
bottom: [
...percentRatio({ pattern: tree.investedCapital.inProfit.toOwn, name: "In Profit", color: colors.profit }),
...percentRatio({ pattern: tree.investedCapital.inLoss.toOwn, name: "In Loss", color: colors.loss }),
priceLine({ number: 100, color: colors.default, style: 0, unit: Unit.percentage }),
priceLine({ number: 50, unit: Unit.percentage }),
],
},
],
},
{ name: "MVRV", title: title("MVRV"), bottom: ratioBottomSeries(tree.realized.price) }, { name: "MVRV", title: title("MVRV"), bottom: ratioBottomSeries(tree.realized.price) },
...singleDeltaItems(tree, title), ...singleDeltaItems(tree, title),
{ name: "% of Own Market Cap", title: title("Realized Cap (% of Own Market Cap)"), bottom: percentRatioBaseline({ pattern: tree.realized.cap.toOwnMcap, name: "% of Own Market Cap", color }) }, { name: "% of Own Market Cap", title: title("Realized Cap (% of Own Market Cap)"), bottom: percentRatioBaseline({ pattern: tree.realized.cap.toOwnMcap, name: "% of Own Market Cap", color }) },

View File

@@ -21,6 +21,7 @@ import {
ROLLING_WINDOWS, ROLLING_WINDOWS,
chartsFromBlockAnd6b, chartsFromBlockAnd6b,
multiSeriesTree, multiSeriesTree,
percentRatio,
percentRatioDots, percentRatioDots,
} from "./series.js"; } from "./series.js";
import { import {
@@ -29,6 +30,9 @@ import {
satsBtcUsdFullTree, satsBtcUsdFullTree,
formatCohortTitle, formatCohortTitle,
groupedWindowsCumulative, groupedWindowsCumulative,
avgHoldingsSubtree,
exposedSubtree,
reusedSubtree,
} from "./shared.js"; } from "./shared.js";
/** /**
@@ -210,34 +214,6 @@ export function createNetworkSection() {
], ],
}); });
const reusedOutputsSubtreeForType =
/**
* @param {AddressableType} key
* @param {(name: string) => string} title
*/
(key, title) => ({
name: "Outputs",
tree: [
{
name: "Count",
tree: chartsFromCount({
pattern: addrs.reused.events.outputToReusedAddrCount[key],
title,
metric: "Transaction Outputs to Reused Addresses",
unit: Unit.count,
}),
},
{
name: "Share",
tree: chartsFromPercentCumulative({
pattern: addrs.reused.events.outputToReusedAddrShare[key],
title,
metric: "Share of Transaction Outputs to Reused Addresses",
}),
},
],
});
const reusedActiveSubtreeForAll = const reusedActiveSubtreeForAll =
/** @param {(name: string) => string} title */ /** @param {(name: string) => string} title */
(title) => ({ (title) => ({
@@ -276,19 +252,6 @@ export function createNetworkSection() {
], ],
}); });
const reusedSubtreeForType =
/**
* @param {AddressableType} key
* @param {(name: string) => string} title
*/
(key, title) => ({
name: "Reused",
tree: [
...reusedSetEntries(key, title),
reusedOutputsSubtreeForType(key, title),
reusedInputsSubtree(key, title),
],
});
const countSubtree = const countSubtree =
/** /**
@@ -324,64 +287,6 @@ export function createNetworkSection() {
], ],
}); });
const exposedSubtree =
/**
* @param {AddressableType | "all"} key
* @param {(name: string) => string} title
*/
(key, title) => ({
name: "Exposed",
tree: [
{
name: "Compare",
title: title("Exposed Address Count"),
bottom: [
line({
series: addrs.exposed.count.funded[key],
name: "Funded",
unit: Unit.count,
}),
line({
series: addrs.exposed.count.total[key],
name: "Total",
color: colors.gray,
unit: Unit.count,
}),
],
},
{
name: "Funded",
title: title("Funded Exposed Address Count"),
bottom: [
line({
series: addrs.exposed.count.funded[key],
name: "Funded Exposed",
unit: Unit.count,
}),
],
},
{
name: "Total",
title: title("Total Exposed Address Count"),
bottom: [
line({
series: addrs.exposed.count.total[key],
name: "Total Exposed",
color: colors.gray,
unit: Unit.count,
}),
],
},
{
name: "Supply",
title: title("Supply in Exposed Addresses"),
bottom: satsBtcUsd({
pattern: addrs.exposed.supply[key],
name: "Supply",
}),
},
],
});
const activityPerTypeEntries = const activityPerTypeEntries =
/** /**
@@ -478,7 +383,8 @@ export function createNetworkSection() {
}), }),
activitySubtreeForAll(title), activitySubtreeForAll(title),
reusedSubtreeForAll(title), reusedSubtreeForAll(title),
exposedSubtree("all", title), exposedSubtree(addrs.exposed, "all", title),
avgHoldingsSubtree(addrs.avgAmount.all, title),
]; ];
}; };
@@ -507,8 +413,9 @@ export function createNetworkSection() {
unit: Unit.count, unit: Unit.count,
}), }),
activitySubtreeForType(addrType, title), activitySubtreeForType(addrType, title),
reusedSubtreeForType(addrType, title), reusedSubtree(addrs.reused, addrType, title),
exposedSubtree(addrType, title), exposedSubtree(addrs.exposed, addrType, title),
avgHoldingsSubtree(addrs.avgAmount[addrType], title),
]; ];
}; };
@@ -761,6 +668,49 @@ export function createNetworkSection() {
}), }),
), ),
}, },
{
name: "Share",
title: "Share of Supply in Exposed Addresses by Type",
bottom: addressTypes.flatMap((t) =>
percentRatio({
pattern: addrs.exposed.supply.share[t.key],
name: t.name,
color: t.color,
defaultActive: t.defaultActive,
}),
),
},
],
},
// Average Holdings
{
name: "Average Holdings",
tree: [
{
name: "Per UTXO",
title: "Average Holdings per UTXO by Type",
bottom: addressTypes.flatMap((t) =>
satsBtcUsd({
pattern: addrs.avgAmount[t.key].utxo,
name: t.name,
color: t.color,
defaultActive: t.defaultActive,
}),
),
},
{
name: "Per Address",
title: "Average Holdings per Funded Address by Type",
bottom: addressTypes.flatMap((t) =>
satsBtcUsd({
pattern: addrs.avgAmount[t.key].addr,
name: t.name,
color: t.color,
defaultActive: t.defaultActive,
}),
),
},
], ],
}, },
], ],

View File

@@ -6,6 +6,9 @@ import {
line, line,
baseline, baseline,
price, price,
percentRatio,
chartsFromCount,
chartsFromPercentCumulative,
sumsAndAveragesCumulativeWith, sumsAndAveragesCumulativeWith,
} from "./series.js"; } from "./series.js";
import { priceLine, priceLines } from "./constants.js"; import { priceLine, priceLines } from "./constants.js";
@@ -243,6 +246,198 @@ export function satsBtcUsdFullTree({ pattern, title, metric, color }) {
}); });
} }
/**
* "Exposed" subtree (quantum-risk / revealed-pubkey addresses).
* Shape: Compare (funded + total) / Funded / Total / Supply / Share.
* Shared between Network and Distribution (per-type cohort view).
* @param {ExposedTree} exposed
* @param {AddressableType | "all"} key
* @param {(name: string) => string} title
* @returns {PartialOptionsGroup}
*/
export function exposedSubtree(exposed, key, title) {
return {
name: "Exposed",
tree: [
{
name: "Compare",
title: title("Exposed Address Count"),
bottom: [
line({ series: exposed.count.funded[key], name: "Funded", unit: Unit.count }),
line({
series: exposed.count.total[key],
name: "Total",
color: colors.gray,
unit: Unit.count,
}),
],
},
{
name: "Funded",
title: title("Funded Exposed Address Count"),
bottom: [
line({ series: exposed.count.funded[key], name: "Funded Exposed", unit: Unit.count }),
],
},
{
name: "Total",
title: title("Total Exposed Address Count"),
bottom: [
line({
series: exposed.count.total[key],
name: "Total Exposed",
color: colors.gray,
unit: Unit.count,
}),
],
},
{
name: "Supply",
title: title("Supply in Exposed Addresses"),
bottom: satsBtcUsd({ pattern: exposed.supply[key], name: "Supply" }),
},
{
name: "Share",
title: title("Share of Supply in Exposed Addresses"),
bottom: percentRatio({ pattern: exposed.supply.share[key], name: "Supply" }),
},
],
};
}
/**
* "Reused" subtree (per-type / per-cohort — no "Active" window, since that
* data is only tracked globally). Shape:
* Compare (funded + total) / Funded / Total / Outputs / Inputs.
* @param {ReusedTree} reused
* @param {AddressableType | "all"} key
* @param {(name: string) => string} title
* @returns {PartialOptionsGroup}
*/
export function reusedSubtree(reused, key, title) {
return {
name: "Reused",
tree: [
{
name: "Compare",
title: title("Reused Address Count"),
bottom: [
line({ series: reused.count.funded[key], name: "Funded", unit: Unit.count }),
line({
series: reused.count.total[key],
name: "Total",
color: colors.gray,
unit: Unit.count,
}),
],
},
{
name: "Funded",
title: title("Funded Reused Addresses"),
bottom: [
line({ series: reused.count.funded[key], name: "Funded Reused", unit: Unit.count }),
],
},
{
name: "Total",
title: title("Total Reused Addresses"),
bottom: [
line({
series: reused.count.total[key],
name: "Total Reused",
color: colors.gray,
unit: Unit.count,
}),
],
},
{
name: "Outputs",
tree: [
{
name: "Count",
tree: chartsFromCount({
pattern: reused.events.outputToReusedAddrCount[key],
title,
metric: "Transaction Outputs to Reused Addresses",
unit: Unit.count,
}),
},
{
name: "Share",
tree: chartsFromPercentCumulative({
pattern: reused.events.outputToReusedAddrShare[key],
title,
metric: "Share of Transaction Outputs to Reused Addresses",
}),
},
],
},
{
name: "Inputs",
tree: [
{
name: "Count",
tree: chartsFromCount({
pattern: reused.events.inputFromReusedAddrCount[key],
title,
metric: "Transaction Inputs from Reused Addresses",
unit: Unit.count,
}),
},
{
name: "Share",
tree: chartsFromPercentCumulative({
pattern: reused.events.inputFromReusedAddrShare[key],
title,
metric: "Share of Transaction Inputs from Reused Addresses",
}),
},
],
},
],
};
}
/**
* "Average Holdings" subtree: Compare (both) + Per UTXO + Per Funded Address.
* Shared between Network and Distribution.
* @param {AvgAmountPattern} pattern
* @param {(name: string) => string} title
* @returns {PartialOptionsGroup}
*/
export function avgHoldingsSubtree(pattern, title) {
return {
name: "Average Holdings",
tree: [
{
name: "Compare",
title: title("Average Holdings"),
bottom: [
...satsBtcUsd({ pattern: pattern.utxo, name: "Per UTXO" }),
...satsBtcUsd({
pattern: pattern.addr,
name: "Per Funded Address",
color: colors.gray,
}),
],
},
{
name: "Per UTXO",
title: title("Average Holdings per UTXO"),
bottom: satsBtcUsd({ pattern: pattern.utxo, name: "Per UTXO" }),
},
{
name: "Per Address",
title: title("Average Holdings per Funded Address"),
bottom: satsBtcUsd({
pattern: pattern.addr,
name: "Per Funded Address",
}),
},
],
};
}
/** /**
* Create Price + Ratio charts from a simple price pattern (BpsCentsRatioSatsUsdPattern) * Create Price + Ratio charts from a simple price pattern (BpsCentsRatioSatsUsdPattern)
* @param {Object} args * @param {Object} args

View File

@@ -183,6 +183,7 @@
* @property {Color} color * @property {Color} color
* @property {PatternAll} tree * @property {PatternAll} tree
* @property {AddrCountPattern} addressCount * @property {AddrCountPattern} addressCount
* @property {AvgAmountPattern} avgAmount
* *
* Full cohort: adjustedSopr + percentiles + RelToMarketCap (term.short) * Full cohort: adjustedSopr + percentiles + RelToMarketCap (term.short)
* @typedef {Object} CohortFull * @typedef {Object} CohortFull
@@ -251,7 +252,7 @@
* ============================================================================ * ============================================================================
* *
* Addressable cohort with address count (for "type" cohorts - uses OutputsRealizedSupplyUnrealizedPattern2) * Addressable cohort with address count (for "type" cohorts - uses OutputsRealizedSupplyUnrealizedPattern2)
* @typedef {{ name: string, title: string, color: Color, tree: EmptyPattern, addressCount: AddrCountPattern }} CohortAddr * @typedef {{ name: string, key: AddressableType, title: string, color: Color, tree: EmptyPattern, addressCount: AddrCountPattern, avgAmount: AvgAmountPattern, exposed: ExposedTree, reused: ReusedTree }} CohortAddr
* *
* ============================================================================ * ============================================================================
* Cohort Group Types (by capability) * Cohort Group Types (by capability)

View File

@@ -29,7 +29,8 @@ nav {
} }
a:visited { a:visited {
color: transparent; font-style: italic;
/*color: var(--orange);*/
} }
ul { ul {

View File

@@ -72,7 +72,11 @@
--block-gap: calc( --block-gap: calc(
var(--min-gap) + var(--t) * (var(--max-gap) - var(--min-gap)) var(--min-gap) + var(--t) * (var(--max-gap) - var(--min-gap))
); );
--empty-alpha: 0.5; --empty-alpha: 0.3;
--iso-scale: 0.866;
--ox: 0.3;
--oy: 0.6;
--fill-pct: calc(var(--fill, 1) * 100%);
--face-step: 0.033; --face-step: 0.033;
--face-right-color: light-dark( --face-right-color: light-dark(
oklch(from var(--face-color) calc(l - var(--face-step) * 2) c h), oklch(from var(--face-color) calc(l - var(--face-step) * 2) c h),
@@ -86,7 +90,6 @@
var(--face-color), var(--face-color),
oklch(from var(--face-color) calc(l + var(--face-step) * 2) c h) oklch(from var(--face-color) calc(l + var(--face-step) * 2) c h)
); );
/*margin-top: -0.375rem;*/
margin-left: calc(var(--cube) * -0.25); margin-left: calc(var(--cube) * -0.25);
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
@@ -97,29 +100,9 @@
line-height: var(--line-height-sm); line-height: var(--line-height-sm);
--face-color: var(--border-color); --face-color: var(--border-color);
color: var(--color); color: var(--color);
transition: transition-property: color, background-color;
color,
background-color,
border-color,
outline-color,
text-decoration-color,
fill,
stroke,
opacity,
box-shadow,
transform,
translate,
scale,
rotate,
filter,
-webkit-backdrop-filter,
backdrop-filter,
display,
content-visibility,
overlay,
pointer-events;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 50ms; transition-duration: 50ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
user-select: none; user-select: none;
pointer-events: none; pointer-events: none;
@@ -143,33 +126,74 @@
position: absolute; position: absolute;
width: var(--cube); width: var(--cube);
height: var(--cube); height: var(--cube);
}
.right,
.left,
.top {
padding: 0.1rem; padding: 0.1rem;
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
} }
.inner-top { .right,
backdrop-filter: none; .left,
background-color: var(--face-top-color); .rear-right,
/*-webkit-mask-image: linear-gradient(transparent, black 0.5rem, black calc(100% - 0.5rem), transparent); .rear-left {
mask-image: linear-gradient(transparent, black 0.5rem, black calc(100% - 0.5rem), transparent);*/ background: linear-gradient(
to top,
var(--fc) var(--fill-pct),
oklch(from var(--fc) l c h / var(--empty-alpha)) var(--fill-pct)
);
}
.bottom {
background-color: var(--face-color);
transform: rotate(30deg) skew(-30deg) transform: rotate(30deg) skew(-30deg)
translate( translate(
calc(var(--cube) * (1.99 - var(--fill, 1))), calc(var(--cube) * (var(--ox) + 1 + var(--oy) / var(--iso-scale))),
calc(var(--cube) * (0.599 - 0.864 * var(--fill, 1))) calc(var(--cube) * var(--oy))
) )
scaleY(0.864); scaleY(var(--iso-scale));
}
.rear-right {
--fc: var(--face-left-color);
transform: rotate(30deg) skewX(30deg)
translate(
calc(var(--cube) * (var(--ox) + 1)),
calc(var(--cube) * (var(--oy) - var(--iso-scale)))
)
scaleY(var(--iso-scale));
}
.rear-left {
--fc: var(--face-top-color);
transform: rotate(-30deg) skewX(-30deg)
translate(
calc(var(--cube) * (var(--ox) + 1)),
calc(var(--cube) * (var(--ox) * var(--iso-scale) + var(--oy)))
)
scale(-1, var(--iso-scale));
}
.inner-top {
background-color: var(--face-top-color);
transform: rotate(30deg) skew(-30deg)
translate(
calc(var(--cube) * (var(--ox) + 1 + var(--oy) / var(--iso-scale) - var(--fill, 1))),
calc(var(--cube) * (var(--oy) - var(--iso-scale) * var(--fill, 1)))
)
scaleY(var(--iso-scale));
} }
.right { .right {
background: linear-gradient( --fc: var(--face-right-color);
to top,
var(--face-right-color) calc(var(--fill, 1) * 100%),
oklch(from var(--face-right-color) l c h / var(--empty-alpha))
calc(var(--fill, 1) * 100%)
);
transform: rotate(-30deg) skewX(-30deg) transform: rotate(-30deg) skewX(-30deg)
translate(calc(var(--cube) * 1.3), calc(var(--cube) * 1.725)) translate(
scaleY(0.864); calc(var(--cube) * (var(--ox) + 1)),
calc(var(--cube) * ((var(--ox) + 1) * var(--iso-scale) + var(--oy)))
)
scaleY(var(--iso-scale));
} }
.top { .top {
@@ -179,8 +203,11 @@
calc(var(--empty-alpha) + var(--is-full) * (1 - var(--empty-alpha))) calc(var(--empty-alpha) + var(--is-full) * (1 - var(--empty-alpha)))
); );
transform: rotate(30deg) skew(-30deg) transform: rotate(30deg) skew(-30deg)
translate(calc(var(--cube) * 0.99), calc(var(--cube) * -0.265)) translate(
scaleY(0.864); calc(var(--cube) * (var(--ox) + var(--oy) / var(--iso-scale))),
calc(var(--cube) * (var(--oy) - var(--iso-scale)))
)
scaleY(var(--iso-scale));
justify-content: center; justify-content: center;
align-items: center; align-items: center;
text-align: center; text-align: center;
@@ -192,17 +219,15 @@
} }
.left { .left {
--fc: var(--face-left-color);
font-size: var(--font-size-xs); font-size: var(--font-size-xs);
line-height: var(--line-height-xs); line-height: var(--line-height-xs);
background: linear-gradient(
to top,
var(--face-left-color) calc(var(--fill, 1) * 100%),
oklch(from var(--face-left-color) l c h / var(--empty-alpha))
calc(var(--fill, 1) * 100%)
);
transform: rotate(30deg) skewX(30deg) transform: rotate(30deg) skewX(30deg)
translate(calc(var(--cube) * 0.3), calc(var(--cube) * 0.6)) translate(
scaleY(0.864); calc(var(--cube) * var(--ox)),
calc(var(--cube) * var(--oy))
)
scaleY(var(--iso-scale));
} }
&.skeleton { &.skeleton {