diff --git a/crates/brk_bindgen/src/generators/python/client.rs b/crates/brk_bindgen/src/generators/python/client.rs index 30352c162..ef72cf225 100644 --- a/crates/brk_bindgen/src/generators/python/client.rs +++ b/crates/brk_bindgen/src/generators/python/client.rs @@ -131,7 +131,8 @@ def _p(prefix: str, acc: str) -> str: pub fn generate_endpoint_class(output: &mut String) { writeln!( output, - r#"class MetricData(TypedDict, Generic[T]): + r#"@dataclass +class MetricData(Generic[T]): """Metric data with range information.""" version: int total: int @@ -176,8 +177,9 @@ class _EndpointConfig: p = self.path() return f"{{p}}?{{query}}" if query else p - def get_json(self) -> Any: - return self.client.get_json(self._build_path()) + def get_json(self) -> MetricData: + data = self.client.get_json(self._build_path()) + return MetricData(**data) def get_csv(self) -> str: return self.client.get_text(self._build_path(format='csv')) @@ -376,7 +378,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern // Generate helper function writeln!( output, - r#"def _ep(c: BrkClientBase, n: str, i: Index) -> MetricEndpointBuilder: + r#"def _ep(c: BrkClientBase, n: str, i: Index) -> MetricEndpointBuilder[Any]: return MetricEndpointBuilder(c, n, i) "# ) @@ -409,6 +411,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern // Generate the main accessor class writeln!(output, "class {}(Generic[T]):", pattern.name).unwrap(); + writeln!(output, " by: {}[T]", by_class_name).unwrap(); writeln!( output, " def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, {}(c, n)", diff --git a/crates/brk_bindgen/src/generators/python/mod.rs b/crates/brk_bindgen/src/generators/python/mod.rs index b75e5da0e..44c3538cc 100644 --- a/crates/brk_bindgen/src/generators/python/mod.rs +++ b/crates/brk_bindgen/src/generators/python/mod.rs @@ -24,12 +24,18 @@ pub fn generate_python_client( writeln!(output, "# Auto-generated BRK Python client").unwrap(); writeln!(output, "# Do not edit manually\n").unwrap(); + writeln!(output, "from __future__ import annotations").unwrap(); + writeln!(output, "from dataclasses import dataclass").unwrap(); writeln!( output, "from typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol, overload" ) .unwrap(); - writeln!(output, "from http.client import HTTPSConnection, HTTPConnection").unwrap(); + writeln!( + output, + "from http.client import HTTPSConnection, HTTPConnection" + ) + .unwrap(); writeln!(output, "from urllib.parse import urlparse").unwrap(); writeln!(output, "import json\n").unwrap(); writeln!(output, "T = TypeVar('T')\n").unwrap(); diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 09ebab658..2261c2f96 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -1427,6 +1427,7 @@ pub struct AaopoolPattern { pub _24h_blocks_mined: MetricPattern1, pub _24h_dominance: MetricPattern1, pub blocks_mined: BlockCountPattern, + pub blocks_since_block: MetricPattern1, pub coinbase: CoinbasePattern2, pub days_since_block: MetricPattern4, pub dominance: MetricPattern1, @@ -1447,6 +1448,7 @@ impl AaopoolPattern { _24h_blocks_mined: MetricPattern1::new(client.clone(), _m(&acc, "24h_blocks_mined")), _24h_dominance: MetricPattern1::new(client.clone(), _m(&acc, "24h_dominance")), blocks_mined: BlockCountPattern::new(client.clone(), _m(&acc, "blocks_mined")), + blocks_since_block: MetricPattern1::new(client.clone(), _m(&acc, "blocks_since_block")), coinbase: CoinbasePattern2::new(client.clone(), _m(&acc, "coinbase")), days_since_block: MetricPattern4::new(client.clone(), _m(&acc, "days_since_block")), dominance: MetricPattern1::new(client.clone(), _m(&acc, "dominance")), @@ -1456,6 +1458,44 @@ impl AaopoolPattern { } } +/// Pattern struct for repeated tree structure. +pub struct RelativePattern2 { + pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1, + pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1, + pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub supply_in_loss_rel_to_circulating_supply: MetricPattern1, + pub supply_in_loss_rel_to_own_supply: MetricPattern1, + pub supply_in_profit_rel_to_circulating_supply: MetricPattern1, + pub supply_in_profit_rel_to_own_supply: MetricPattern1, + pub supply_rel_to_circulating_supply: MetricPattern4, + pub unrealized_loss_rel_to_own_market_cap: MetricPattern1, + pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub unrealized_profit_rel_to_own_market_cap: MetricPattern1, + pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1, +} + +impl RelativePattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), + neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), + net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), + net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), + supply_in_loss_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), + supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), + supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), + unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), + unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), + unrealized_profit_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), + unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct LookbackPattern { pub _10y: MetricPattern4, @@ -1530,6 +1570,42 @@ impl PeriodLumpSumStackPattern { } } +/// Pattern struct for repeated tree structure. +pub struct ClassAveragePricePattern { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, + pub _2026: MetricPattern4, +} + +impl ClassAveragePricePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_average_price")), + _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_average_price")), + _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_average_price")), + _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_average_price")), + _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_average_price")), + _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_average_price")), + _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_average_price")), + _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_average_price")), + _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_average_price")), + _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_average_price")), + _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_average_price")), + _2026: MetricPattern4::new(client.clone(), _m(&acc, "2026_average_price")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct PeriodAveragePricePattern { pub _10y: MetricPattern4, @@ -1566,42 +1642,6 @@ impl PeriodAveragePricePattern { } } -/// Pattern struct for repeated tree structure. -pub struct ClassAveragePricePattern { - pub _2015: MetricPattern4, - pub _2016: MetricPattern4, - pub _2017: MetricPattern4, - pub _2018: MetricPattern4, - pub _2019: MetricPattern4, - pub _2020: MetricPattern4, - pub _2021: MetricPattern4, - pub _2022: MetricPattern4, - pub _2023: MetricPattern4, - pub _2024: MetricPattern4, - pub _2025: MetricPattern4, - pub _2026: MetricPattern4, -} - -impl ClassAveragePricePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_returns")), - _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_returns")), - _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_returns")), - _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_returns")), - _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_returns")), - _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_returns")), - _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_returns")), - _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_returns")), - _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_returns")), - _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_returns")), - _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_returns")), - _2026: MetricPattern4::new(client.clone(), _m(&acc, "2026_returns")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct BitcoinPattern { pub average: MetricPattern2, @@ -1702,38 +1742,6 @@ impl RelativePattern { } } -/// Pattern struct for repeated tree structure. -pub struct RelativePattern2 { - pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1, - pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, - pub net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1, - pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1, - pub supply_in_loss_rel_to_own_supply: MetricPattern1, - pub supply_in_profit_rel_to_own_supply: MetricPattern1, - pub unrealized_loss_rel_to_own_market_cap: MetricPattern1, - pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, - pub unrealized_profit_rel_to_own_market_cap: MetricPattern1, - pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1, -} - -impl RelativePattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), - neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), - net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), - net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), - supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), - unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), - unrealized_profit_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), - unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct CountPattern2 { pub average: MetricPattern1, @@ -1796,36 +1804,6 @@ impl AddrCountPattern { } } -/// Pattern struct for repeated tree structure. -pub struct FullnessPattern { - pub average: MetricPattern2, - pub base: MetricPattern11, - pub max: MetricPattern2, - pub median: MetricPattern6, - pub min: MetricPattern2, - pub pct10: MetricPattern6, - pub pct25: MetricPattern6, - pub pct75: MetricPattern6, - pub pct90: MetricPattern6, -} - -impl FullnessPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - average: MetricPattern2::new(client.clone(), _m(&acc, "average")), - base: MetricPattern11::new(client.clone(), acc.clone()), - max: MetricPattern2::new(client.clone(), _m(&acc, "max")), - median: MetricPattern6::new(client.clone(), _m(&acc, "median")), - min: MetricPattern2::new(client.clone(), _m(&acc, "min")), - pct10: MetricPattern6::new(client.clone(), _m(&acc, "pct10")), - pct25: MetricPattern6::new(client.clone(), _m(&acc, "pct25")), - pct75: MetricPattern6::new(client.clone(), _m(&acc, "pct75")), - pct90: MetricPattern6::new(client.clone(), _m(&acc, "pct90")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct FeeRatePattern { pub average: MetricPattern1, @@ -1856,6 +1834,36 @@ impl FeeRatePattern { } } +/// Pattern struct for repeated tree structure. +pub struct FullnessPattern { + pub average: MetricPattern2, + pub base: MetricPattern11, + pub max: MetricPattern2, + pub median: MetricPattern6, + pub min: MetricPattern2, + pub pct10: MetricPattern6, + pub pct25: MetricPattern6, + pub pct75: MetricPattern6, + pub pct90: MetricPattern6, +} + +impl FullnessPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + average: MetricPattern2::new(client.clone(), _m(&acc, "average")), + base: MetricPattern11::new(client.clone(), acc.clone()), + max: MetricPattern2::new(client.clone(), _m(&acc, "max")), + median: MetricPattern6::new(client.clone(), _m(&acc, "median")), + min: MetricPattern2::new(client.clone(), _m(&acc, "min")), + pct10: MetricPattern6::new(client.clone(), _m(&acc, "pct10")), + pct25: MetricPattern6::new(client.clone(), _m(&acc, "pct25")), + pct75: MetricPattern6::new(client.clone(), _m(&acc, "pct75")), + pct90: MetricPattern6::new(client.clone(), _m(&acc, "pct90")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _0satsPattern { pub activity: ActivityPattern2, @@ -1913,27 +1921,27 @@ impl PhaseDailyCentsPattern { } /// Pattern struct for repeated tree structure. -pub struct _10yTo12yPattern { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern2, - pub outputs: OutputsPattern, - pub realized: RealizedPattern2, - pub relative: RelativePattern2, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, +pub struct PeriodCagrPattern { + pub _10y: MetricPattern4, + pub _2y: MetricPattern4, + pub _3y: MetricPattern4, + pub _4y: MetricPattern4, + pub _5y: MetricPattern4, + pub _6y: MetricPattern4, + pub _8y: MetricPattern4, } -impl _10yTo12yPattern { +impl PeriodCagrPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern2::new(client.clone(), acc.clone()), - outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: RealizedPattern2::new(client.clone(), acc.clone()), - relative: RelativePattern2::new(client.clone(), acc.clone()), - supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + _10y: MetricPattern4::new(client.clone(), _p("10y", &acc)), + _2y: MetricPattern4::new(client.clone(), _p("2y", &acc)), + _3y: MetricPattern4::new(client.clone(), _p("3y", &acc)), + _4y: MetricPattern4::new(client.clone(), _p("4y", &acc)), + _5y: MetricPattern4::new(client.clone(), _p("5y", &acc)), + _6y: MetricPattern4::new(client.clone(), _p("6y", &acc)), + _8y: MetricPattern4::new(client.clone(), _p("8y", &acc)), } } } @@ -1983,7 +1991,7 @@ impl _0satsPattern2 { cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), realized: RealizedPattern::new(client.clone(), acc.clone()), - relative: RelativePattern4::new(client.clone(), _m(&acc, "supply_in")), + relative: RelativePattern4::new(client.clone(), _m(&acc, "supply")), supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), } @@ -1991,7 +1999,7 @@ impl _0satsPattern2 { } /// Pattern struct for repeated tree structure. -pub struct _100btcPattern { +pub struct _0Pattern { pub activity: ActivityPattern2, pub cost_basis: CostBasisPattern, pub outputs: OutputsPattern, @@ -2001,7 +2009,7 @@ pub struct _100btcPattern { pub unrealized: UnrealizedPattern, } -impl _100btcPattern { +impl _0Pattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -2016,32 +2024,6 @@ impl _100btcPattern { } } -/// Pattern struct for repeated tree structure. -pub struct PeriodCagrPattern { - pub _10y: MetricPattern4, - pub _2y: MetricPattern4, - pub _3y: MetricPattern4, - pub _4y: MetricPattern4, - pub _5y: MetricPattern4, - pub _6y: MetricPattern4, - pub _8y: MetricPattern4, -} - -impl PeriodCagrPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - _10y: MetricPattern4::new(client.clone(), _p("10y", &acc)), - _2y: MetricPattern4::new(client.clone(), _p("2y", &acc)), - _3y: MetricPattern4::new(client.clone(), _p("3y", &acc)), - _4y: MetricPattern4::new(client.clone(), _p("4y", &acc)), - _5y: MetricPattern4::new(client.clone(), _p("5y", &acc)), - _6y: MetricPattern4::new(client.clone(), _p("6y", &acc)), - _8y: MetricPattern4::new(client.clone(), _p("8y", &acc)), - } - } -} - /// Pattern struct for repeated tree structure. pub struct _10yPattern { pub activity: ActivityPattern2, @@ -2068,6 +2050,54 @@ impl _10yPattern { } } +/// Pattern struct for repeated tree structure. +pub struct _10yTo12yPattern { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern2, + pub outputs: OutputsPattern, + pub realized: RealizedPattern2, + pub relative: RelativePattern2, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, +} + +impl _10yTo12yPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern2::new(client.clone(), acc.clone()), + outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), + realized: RealizedPattern2::new(client.clone(), acc.clone()), + relative: RelativePattern2::new(client.clone(), acc.clone()), + supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct RelativePattern4 { + pub supply_in_loss_rel_to_circulating_supply: MetricPattern1, + pub supply_in_loss_rel_to_own_supply: MetricPattern1, + pub supply_in_profit_rel_to_circulating_supply: MetricPattern1, + pub supply_in_profit_rel_to_own_supply: MetricPattern1, + pub supply_rel_to_circulating_supply: MetricPattern4, +} + +impl RelativePattern4 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + supply_in_loss_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "in_loss_rel_to_circulating_supply")), + supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "in_profit_rel_to_circulating_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "in_profit_rel_to_own_supply")), + supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "rel_to_circulating_supply")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct ActivityPattern2 { pub coinblocks_destroyed: BlockCountPattern, @@ -2110,24 +2140,6 @@ impl SplitPattern2 { } } -/// Pattern struct for repeated tree structure. -pub struct SegwitAdoptionPattern { - pub base: MetricPattern11, - pub cumulative: MetricPattern2, - pub sum: MetricPattern2, -} - -impl SegwitAdoptionPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - base: MetricPattern11::new(client.clone(), acc.clone()), - cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), - sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct UnclaimedRewardsPattern { pub bitcoin: BitcoinPattern2, @@ -2146,78 +2158,6 @@ impl UnclaimedRewardsPattern { } } -/// Pattern struct for repeated tree structure. -pub struct ActiveSupplyPattern { - pub bitcoin: MetricPattern1, - pub dollars: MetricPattern1, - pub sats: MetricPattern1, -} - -impl ActiveSupplyPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: MetricPattern1::new(client.clone(), _m(&acc, "btc")), - dollars: MetricPattern1::new(client.clone(), _m(&acc, "usd")), - sats: MetricPattern1::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct CoinbasePattern2 { - pub bitcoin: BlockCountPattern, - pub dollars: BlockCountPattern, - pub sats: BlockCountPattern, -} - -impl CoinbasePattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), - dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), - sats: BlockCountPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct CostBasisPattern2 { - pub max: MetricPattern1, - pub min: MetricPattern1, - pub percentiles: PercentilesPattern, -} - -impl CostBasisPattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), - percentiles: PercentilesPattern::new(client.clone(), _m(&acc, "cost_basis")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct _2015Pattern { - pub bitcoin: MetricPattern4, - pub dollars: MetricPattern4, - pub sats: MetricPattern4, -} - -impl _2015Pattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")), - dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")), - sats: MetricPattern4::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct CoinbasePattern { pub bitcoin: BitcoinPattern, @@ -2237,49 +2177,91 @@ impl CoinbasePattern { } /// Pattern struct for repeated tree structure. -pub struct RelativePattern4 { - pub supply_in_loss_rel_to_own_supply: MetricPattern1, - pub supply_in_profit_rel_to_own_supply: MetricPattern1, -} - -impl RelativePattern4 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "profit_rel_to_own_supply")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct _1dReturns1mSdPattern { - pub sd: MetricPattern4, - pub sma: MetricPattern4, -} - -impl _1dReturns1mSdPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), - sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct CostBasisPattern { +pub struct CostBasisPattern2 { pub max: MetricPattern1, pub min: MetricPattern1, + pub percentiles: PercentilesPattern, } -impl CostBasisPattern { +impl CostBasisPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), + percentiles: PercentilesPattern::new(client.clone(), _m(&acc, "cost_basis")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct ActiveSupplyPattern { + pub bitcoin: MetricPattern1, + pub dollars: MetricPattern1, + pub sats: MetricPattern1, +} + +impl ActiveSupplyPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + bitcoin: MetricPattern1::new(client.clone(), _m(&acc, "btc")), + dollars: MetricPattern1::new(client.clone(), _m(&acc, "usd")), + sats: MetricPattern1::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _2015Pattern { + pub bitcoin: MetricPattern4, + pub dollars: MetricPattern4, + pub sats: MetricPattern4, +} + +impl _2015Pattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")), + dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")), + sats: MetricPattern4::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct SegwitAdoptionPattern { + pub base: MetricPattern11, + pub cumulative: MetricPattern2, + pub sum: MetricPattern2, +} + +impl SegwitAdoptionPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + base: MetricPattern11::new(client.clone(), acc.clone()), + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), + sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct CoinbasePattern2 { + pub bitcoin: BlockCountPattern, + pub dollars: BlockCountPattern, + pub sats: BlockCountPattern, +} + +impl CoinbasePattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), + dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), + sats: BlockCountPattern::new(client.clone(), acc.clone()), } } } @@ -2300,6 +2282,38 @@ impl SupplyPattern2 { } } +/// Pattern struct for repeated tree structure. +pub struct CostBasisPattern { + pub max: MetricPattern1, + pub min: MetricPattern1, +} + +impl CostBasisPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), + min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _1dReturns1mSdPattern { + pub sd: MetricPattern4, + pub sma: MetricPattern4, +} + +impl _1dReturns1mSdPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), + sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct SatsPattern { pub ohlc: MetricPattern1, @@ -2316,22 +2330,6 @@ impl SatsPattern { } } -/// Pattern struct for repeated tree structure. -pub struct BitcoinPattern2 { - pub cumulative: MetricPattern2, - pub sum: MetricPattern1, -} - -impl BitcoinPattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), - sum: MetricPattern1::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct BlockCountPattern { pub cumulative: MetricPattern1, @@ -2348,6 +2346,22 @@ impl BlockCountPattern { } } +/// Pattern struct for repeated tree structure. +pub struct BitcoinPattern2 { + pub cumulative: MetricPattern2, + pub sum: MetricPattern1, +} + +impl BitcoinPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), + sum: MetricPattern1::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct OutputsPattern { pub utxo_count: MetricPattern1, @@ -3307,95 +3321,95 @@ impl MetricsTree_Distribution_UtxoCohorts_AmountRange { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_Epoch { - pub _0: _0satsPattern2, - pub _1: _0satsPattern2, - pub _2: _0satsPattern2, - pub _3: _0satsPattern2, - pub _4: _0satsPattern2, + pub _0: _0Pattern, + pub _1: _0Pattern, + pub _2: _0Pattern, + pub _3: _0Pattern, + pub _4: _0Pattern, } impl MetricsTree_Distribution_UtxoCohorts_Epoch { pub fn new(client: Arc, base_path: String) -> Self { Self { - _0: _0satsPattern2::new(client.clone(), "epoch_0".to_string()), - _1: _0satsPattern2::new(client.clone(), "epoch_1".to_string()), - _2: _0satsPattern2::new(client.clone(), "epoch_2".to_string()), - _3: _0satsPattern2::new(client.clone(), "epoch_3".to_string()), - _4: _0satsPattern2::new(client.clone(), "epoch_4".to_string()), + _0: _0Pattern::new(client.clone(), "epoch_0".to_string()), + _1: _0Pattern::new(client.clone(), "epoch_1".to_string()), + _2: _0Pattern::new(client.clone(), "epoch_2".to_string()), + _3: _0Pattern::new(client.clone(), "epoch_3".to_string()), + _4: _0Pattern::new(client.clone(), "epoch_4".to_string()), } } } /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_GeAmount { - pub _100btc: _100btcPattern, - pub _100k_sats: _100btcPattern, - pub _100sats: _100btcPattern, - pub _10btc: _100btcPattern, - pub _10k_btc: _100btcPattern, - pub _10k_sats: _100btcPattern, - pub _10m_sats: _100btcPattern, - pub _10sats: _100btcPattern, - pub _1btc: _100btcPattern, - pub _1k_btc: _100btcPattern, - pub _1k_sats: _100btcPattern, - pub _1m_sats: _100btcPattern, - pub _1sat: _100btcPattern, + pub _100btc: _0Pattern, + pub _100k_sats: _0Pattern, + pub _100sats: _0Pattern, + pub _10btc: _0Pattern, + pub _10k_btc: _0Pattern, + pub _10k_sats: _0Pattern, + pub _10m_sats: _0Pattern, + pub _10sats: _0Pattern, + pub _1btc: _0Pattern, + pub _1k_btc: _0Pattern, + pub _1k_sats: _0Pattern, + pub _1m_sats: _0Pattern, + pub _1sat: _0Pattern, } impl MetricsTree_Distribution_UtxoCohorts_GeAmount { pub fn new(client: Arc, base_path: String) -> Self { Self { - _100btc: _100btcPattern::new(client.clone(), "utxos_above_100btc".to_string()), - _100k_sats: _100btcPattern::new(client.clone(), "utxos_above_100k_sats".to_string()), - _100sats: _100btcPattern::new(client.clone(), "utxos_above_100sats".to_string()), - _10btc: _100btcPattern::new(client.clone(), "utxos_above_10btc".to_string()), - _10k_btc: _100btcPattern::new(client.clone(), "utxos_above_10k_btc".to_string()), - _10k_sats: _100btcPattern::new(client.clone(), "utxos_above_10k_sats".to_string()), - _10m_sats: _100btcPattern::new(client.clone(), "utxos_above_10m_sats".to_string()), - _10sats: _100btcPattern::new(client.clone(), "utxos_above_10sats".to_string()), - _1btc: _100btcPattern::new(client.clone(), "utxos_above_1btc".to_string()), - _1k_btc: _100btcPattern::new(client.clone(), "utxos_above_1k_btc".to_string()), - _1k_sats: _100btcPattern::new(client.clone(), "utxos_above_1k_sats".to_string()), - _1m_sats: _100btcPattern::new(client.clone(), "utxos_above_1m_sats".to_string()), - _1sat: _100btcPattern::new(client.clone(), "utxos_above_1sat".to_string()), + _100btc: _0Pattern::new(client.clone(), "utxos_above_100btc".to_string()), + _100k_sats: _0Pattern::new(client.clone(), "utxos_above_100k_sats".to_string()), + _100sats: _0Pattern::new(client.clone(), "utxos_above_100sats".to_string()), + _10btc: _0Pattern::new(client.clone(), "utxos_above_10btc".to_string()), + _10k_btc: _0Pattern::new(client.clone(), "utxos_above_10k_btc".to_string()), + _10k_sats: _0Pattern::new(client.clone(), "utxos_above_10k_sats".to_string()), + _10m_sats: _0Pattern::new(client.clone(), "utxos_above_10m_sats".to_string()), + _10sats: _0Pattern::new(client.clone(), "utxos_above_10sats".to_string()), + _1btc: _0Pattern::new(client.clone(), "utxos_above_1btc".to_string()), + _1k_btc: _0Pattern::new(client.clone(), "utxos_above_1k_btc".to_string()), + _1k_sats: _0Pattern::new(client.clone(), "utxos_above_1k_sats".to_string()), + _1m_sats: _0Pattern::new(client.clone(), "utxos_above_1m_sats".to_string()), + _1sat: _0Pattern::new(client.clone(), "utxos_above_1sat".to_string()), } } } /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_LtAmount { - pub _100btc: _100btcPattern, - pub _100k_btc: _100btcPattern, - pub _100k_sats: _100btcPattern, - pub _100sats: _100btcPattern, - pub _10btc: _100btcPattern, - pub _10k_btc: _100btcPattern, - pub _10k_sats: _100btcPattern, - pub _10m_sats: _100btcPattern, - pub _10sats: _100btcPattern, - pub _1btc: _100btcPattern, - pub _1k_btc: _100btcPattern, - pub _1k_sats: _100btcPattern, - pub _1m_sats: _100btcPattern, + pub _100btc: _0Pattern, + pub _100k_btc: _0Pattern, + pub _100k_sats: _0Pattern, + pub _100sats: _0Pattern, + pub _10btc: _0Pattern, + pub _10k_btc: _0Pattern, + pub _10k_sats: _0Pattern, + pub _10m_sats: _0Pattern, + pub _10sats: _0Pattern, + pub _1btc: _0Pattern, + pub _1k_btc: _0Pattern, + pub _1k_sats: _0Pattern, + pub _1m_sats: _0Pattern, } impl MetricsTree_Distribution_UtxoCohorts_LtAmount { pub fn new(client: Arc, base_path: String) -> Self { Self { - _100btc: _100btcPattern::new(client.clone(), "utxos_under_100btc".to_string()), - _100k_btc: _100btcPattern::new(client.clone(), "utxos_under_100k_btc".to_string()), - _100k_sats: _100btcPattern::new(client.clone(), "utxos_under_100k_sats".to_string()), - _100sats: _100btcPattern::new(client.clone(), "utxos_under_100sats".to_string()), - _10btc: _100btcPattern::new(client.clone(), "utxos_under_10btc".to_string()), - _10k_btc: _100btcPattern::new(client.clone(), "utxos_under_10k_btc".to_string()), - _10k_sats: _100btcPattern::new(client.clone(), "utxos_under_10k_sats".to_string()), - _10m_sats: _100btcPattern::new(client.clone(), "utxos_under_10m_sats".to_string()), - _10sats: _100btcPattern::new(client.clone(), "utxos_under_10sats".to_string()), - _1btc: _100btcPattern::new(client.clone(), "utxos_under_1btc".to_string()), - _1k_btc: _100btcPattern::new(client.clone(), "utxos_under_1k_btc".to_string()), - _1k_sats: _100btcPattern::new(client.clone(), "utxos_under_1k_sats".to_string()), - _1m_sats: _100btcPattern::new(client.clone(), "utxos_under_1m_sats".to_string()), + _100btc: _0Pattern::new(client.clone(), "utxos_under_100btc".to_string()), + _100k_btc: _0Pattern::new(client.clone(), "utxos_under_100k_btc".to_string()), + _100k_sats: _0Pattern::new(client.clone(), "utxos_under_100k_sats".to_string()), + _100sats: _0Pattern::new(client.clone(), "utxos_under_100sats".to_string()), + _10btc: _0Pattern::new(client.clone(), "utxos_under_10btc".to_string()), + _10k_btc: _0Pattern::new(client.clone(), "utxos_under_10k_btc".to_string()), + _10k_sats: _0Pattern::new(client.clone(), "utxos_under_10k_sats".to_string()), + _10m_sats: _0Pattern::new(client.clone(), "utxos_under_10m_sats".to_string()), + _10sats: _0Pattern::new(client.clone(), "utxos_under_10sats".to_string()), + _1btc: _0Pattern::new(client.clone(), "utxos_under_1btc".to_string()), + _1k_btc: _0Pattern::new(client.clone(), "utxos_under_1k_btc".to_string()), + _1k_sats: _0Pattern::new(client.clone(), "utxos_under_1k_sats".to_string()), + _1m_sats: _0Pattern::new(client.clone(), "utxos_under_1m_sats".to_string()), } } } @@ -3449,47 +3463,47 @@ impl MetricsTree_Distribution_UtxoCohorts_MaxAge { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_MinAge { - pub _10y: _100btcPattern, - pub _12y: _100btcPattern, - pub _1d: _100btcPattern, - pub _1m: _100btcPattern, - pub _1w: _100btcPattern, - pub _1y: _100btcPattern, - pub _2m: _100btcPattern, - pub _2y: _100btcPattern, - pub _3m: _100btcPattern, - pub _3y: _100btcPattern, - pub _4m: _100btcPattern, - pub _4y: _100btcPattern, - pub _5m: _100btcPattern, - pub _5y: _100btcPattern, - pub _6m: _100btcPattern, - pub _6y: _100btcPattern, - pub _7y: _100btcPattern, - pub _8y: _100btcPattern, + pub _10y: _0Pattern, + pub _12y: _0Pattern, + pub _1d: _0Pattern, + pub _1m: _0Pattern, + pub _1w: _0Pattern, + pub _1y: _0Pattern, + pub _2m: _0Pattern, + pub _2y: _0Pattern, + pub _3m: _0Pattern, + pub _3y: _0Pattern, + pub _4m: _0Pattern, + pub _4y: _0Pattern, + pub _5m: _0Pattern, + pub _5y: _0Pattern, + pub _6m: _0Pattern, + pub _6y: _0Pattern, + pub _7y: _0Pattern, + pub _8y: _0Pattern, } impl MetricsTree_Distribution_UtxoCohorts_MinAge { pub fn new(client: Arc, base_path: String) -> Self { Self { - _10y: _100btcPattern::new(client.clone(), "utxos_at_least_10y_old".to_string()), - _12y: _100btcPattern::new(client.clone(), "utxos_at_least_12y_old".to_string()), - _1d: _100btcPattern::new(client.clone(), "utxos_at_least_1d_old".to_string()), - _1m: _100btcPattern::new(client.clone(), "utxos_at_least_1m_old".to_string()), - _1w: _100btcPattern::new(client.clone(), "utxos_at_least_1w_old".to_string()), - _1y: _100btcPattern::new(client.clone(), "utxos_at_least_1y_old".to_string()), - _2m: _100btcPattern::new(client.clone(), "utxos_at_least_2m_old".to_string()), - _2y: _100btcPattern::new(client.clone(), "utxos_at_least_2y_old".to_string()), - _3m: _100btcPattern::new(client.clone(), "utxos_at_least_3m_old".to_string()), - _3y: _100btcPattern::new(client.clone(), "utxos_at_least_3y_old".to_string()), - _4m: _100btcPattern::new(client.clone(), "utxos_at_least_4m_old".to_string()), - _4y: _100btcPattern::new(client.clone(), "utxos_at_least_4y_old".to_string()), - _5m: _100btcPattern::new(client.clone(), "utxos_at_least_5m_old".to_string()), - _5y: _100btcPattern::new(client.clone(), "utxos_at_least_5y_old".to_string()), - _6m: _100btcPattern::new(client.clone(), "utxos_at_least_6m_old".to_string()), - _6y: _100btcPattern::new(client.clone(), "utxos_at_least_6y_old".to_string()), - _7y: _100btcPattern::new(client.clone(), "utxos_at_least_7y_old".to_string()), - _8y: _100btcPattern::new(client.clone(), "utxos_at_least_8y_old".to_string()), + _10y: _0Pattern::new(client.clone(), "utxos_at_least_10y_old".to_string()), + _12y: _0Pattern::new(client.clone(), "utxos_at_least_12y_old".to_string()), + _1d: _0Pattern::new(client.clone(), "utxos_at_least_1d_old".to_string()), + _1m: _0Pattern::new(client.clone(), "utxos_at_least_1m_old".to_string()), + _1w: _0Pattern::new(client.clone(), "utxos_at_least_1w_old".to_string()), + _1y: _0Pattern::new(client.clone(), "utxos_at_least_1y_old".to_string()), + _2m: _0Pattern::new(client.clone(), "utxos_at_least_2m_old".to_string()), + _2y: _0Pattern::new(client.clone(), "utxos_at_least_2y_old".to_string()), + _3m: _0Pattern::new(client.clone(), "utxos_at_least_3m_old".to_string()), + _3y: _0Pattern::new(client.clone(), "utxos_at_least_3y_old".to_string()), + _4m: _0Pattern::new(client.clone(), "utxos_at_least_4m_old".to_string()), + _4y: _0Pattern::new(client.clone(), "utxos_at_least_4y_old".to_string()), + _5m: _0Pattern::new(client.clone(), "utxos_at_least_5m_old".to_string()), + _5y: _0Pattern::new(client.clone(), "utxos_at_least_5y_old".to_string()), + _6m: _0Pattern::new(client.clone(), "utxos_at_least_6m_old".to_string()), + _6y: _0Pattern::new(client.clone(), "utxos_at_least_6y_old".to_string()), + _7y: _0Pattern::new(client.clone(), "utxos_at_least_7y_old".to_string()), + _8y: _0Pattern::new(client.clone(), "utxos_at_least_8y_old".to_string()), } } } @@ -3561,80 +3575,80 @@ impl MetricsTree_Distribution_UtxoCohorts_Term_Short { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_Type { - pub empty: _0satsPattern2, - pub p2a: _0satsPattern2, - pub p2ms: _0satsPattern2, - pub p2pk33: _0satsPattern2, - pub p2pk65: _0satsPattern2, - pub p2pkh: _0satsPattern2, - pub p2sh: _0satsPattern2, - pub p2tr: _0satsPattern2, - pub p2wpkh: _0satsPattern2, - pub p2wsh: _0satsPattern2, - pub unknown: _0satsPattern2, + pub empty: _0Pattern, + pub p2a: _0Pattern, + pub p2ms: _0Pattern, + pub p2pk33: _0Pattern, + pub p2pk65: _0Pattern, + pub p2pkh: _0Pattern, + pub p2sh: _0Pattern, + pub p2tr: _0Pattern, + pub p2wpkh: _0Pattern, + pub p2wsh: _0Pattern, + pub unknown: _0Pattern, } impl MetricsTree_Distribution_UtxoCohorts_Type { pub fn new(client: Arc, base_path: String) -> Self { Self { - empty: _0satsPattern2::new(client.clone(), "empty_outputs".to_string()), - p2a: _0satsPattern2::new(client.clone(), "p2a".to_string()), - p2ms: _0satsPattern2::new(client.clone(), "p2ms".to_string()), - p2pk33: _0satsPattern2::new(client.clone(), "p2pk33".to_string()), - p2pk65: _0satsPattern2::new(client.clone(), "p2pk65".to_string()), - p2pkh: _0satsPattern2::new(client.clone(), "p2pkh".to_string()), - p2sh: _0satsPattern2::new(client.clone(), "p2sh".to_string()), - p2tr: _0satsPattern2::new(client.clone(), "p2tr".to_string()), - p2wpkh: _0satsPattern2::new(client.clone(), "p2wpkh".to_string()), - p2wsh: _0satsPattern2::new(client.clone(), "p2wsh".to_string()), - unknown: _0satsPattern2::new(client.clone(), "unknown_outputs".to_string()), + empty: _0Pattern::new(client.clone(), "empty_outputs".to_string()), + p2a: _0Pattern::new(client.clone(), "p2a".to_string()), + p2ms: _0Pattern::new(client.clone(), "p2ms".to_string()), + p2pk33: _0Pattern::new(client.clone(), "p2pk33".to_string()), + p2pk65: _0Pattern::new(client.clone(), "p2pk65".to_string()), + p2pkh: _0Pattern::new(client.clone(), "p2pkh".to_string()), + p2sh: _0Pattern::new(client.clone(), "p2sh".to_string()), + p2tr: _0Pattern::new(client.clone(), "p2tr".to_string()), + p2wpkh: _0Pattern::new(client.clone(), "p2wpkh".to_string()), + p2wsh: _0Pattern::new(client.clone(), "p2wsh".to_string()), + unknown: _0Pattern::new(client.clone(), "unknown_outputs".to_string()), } } } /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_Year { - pub _2009: _0satsPattern2, - pub _2010: _0satsPattern2, - pub _2011: _0satsPattern2, - pub _2012: _0satsPattern2, - pub _2013: _0satsPattern2, - pub _2014: _0satsPattern2, - pub _2015: _0satsPattern2, - pub _2016: _0satsPattern2, - pub _2017: _0satsPattern2, - pub _2018: _0satsPattern2, - pub _2019: _0satsPattern2, - pub _2020: _0satsPattern2, - pub _2021: _0satsPattern2, - pub _2022: _0satsPattern2, - pub _2023: _0satsPattern2, - pub _2024: _0satsPattern2, - pub _2025: _0satsPattern2, - pub _2026: _0satsPattern2, + pub _2009: _0Pattern, + pub _2010: _0Pattern, + pub _2011: _0Pattern, + pub _2012: _0Pattern, + pub _2013: _0Pattern, + pub _2014: _0Pattern, + pub _2015: _0Pattern, + pub _2016: _0Pattern, + pub _2017: _0Pattern, + pub _2018: _0Pattern, + pub _2019: _0Pattern, + pub _2020: _0Pattern, + pub _2021: _0Pattern, + pub _2022: _0Pattern, + pub _2023: _0Pattern, + pub _2024: _0Pattern, + pub _2025: _0Pattern, + pub _2026: _0Pattern, } impl MetricsTree_Distribution_UtxoCohorts_Year { pub fn new(client: Arc, base_path: String) -> Self { Self { - _2009: _0satsPattern2::new(client.clone(), "year_2009".to_string()), - _2010: _0satsPattern2::new(client.clone(), "year_2010".to_string()), - _2011: _0satsPattern2::new(client.clone(), "year_2011".to_string()), - _2012: _0satsPattern2::new(client.clone(), "year_2012".to_string()), - _2013: _0satsPattern2::new(client.clone(), "year_2013".to_string()), - _2014: _0satsPattern2::new(client.clone(), "year_2014".to_string()), - _2015: _0satsPattern2::new(client.clone(), "year_2015".to_string()), - _2016: _0satsPattern2::new(client.clone(), "year_2016".to_string()), - _2017: _0satsPattern2::new(client.clone(), "year_2017".to_string()), - _2018: _0satsPattern2::new(client.clone(), "year_2018".to_string()), - _2019: _0satsPattern2::new(client.clone(), "year_2019".to_string()), - _2020: _0satsPattern2::new(client.clone(), "year_2020".to_string()), - _2021: _0satsPattern2::new(client.clone(), "year_2021".to_string()), - _2022: _0satsPattern2::new(client.clone(), "year_2022".to_string()), - _2023: _0satsPattern2::new(client.clone(), "year_2023".to_string()), - _2024: _0satsPattern2::new(client.clone(), "year_2024".to_string()), - _2025: _0satsPattern2::new(client.clone(), "year_2025".to_string()), - _2026: _0satsPattern2::new(client.clone(), "year_2026".to_string()), + _2009: _0Pattern::new(client.clone(), "year_2009".to_string()), + _2010: _0Pattern::new(client.clone(), "year_2010".to_string()), + _2011: _0Pattern::new(client.clone(), "year_2011".to_string()), + _2012: _0Pattern::new(client.clone(), "year_2012".to_string()), + _2013: _0Pattern::new(client.clone(), "year_2013".to_string()), + _2014: _0Pattern::new(client.clone(), "year_2014".to_string()), + _2015: _0Pattern::new(client.clone(), "year_2015".to_string()), + _2016: _0Pattern::new(client.clone(), "year_2016".to_string()), + _2017: _0Pattern::new(client.clone(), "year_2017".to_string()), + _2018: _0Pattern::new(client.clone(), "year_2018".to_string()), + _2019: _0Pattern::new(client.clone(), "year_2019".to_string()), + _2020: _0Pattern::new(client.clone(), "year_2020".to_string()), + _2021: _0Pattern::new(client.clone(), "year_2021".to_string()), + _2022: _0Pattern::new(client.clone(), "year_2022".to_string()), + _2023: _0Pattern::new(client.clone(), "year_2023".to_string()), + _2024: _0Pattern::new(client.clone(), "year_2024".to_string()), + _2025: _0Pattern::new(client.clone(), "year_2025".to_string()), + _2026: _0Pattern::new(client.clone(), "year_2026".to_string()), } } } @@ -4202,8 +4216,8 @@ impl MetricsTree_Market_Ath { /// Metrics tree node. pub struct MetricsTree_Market_Dca { - pub class_average_price: MetricsTree_Market_Dca_ClassAveragePrice, - pub class_returns: ClassAveragePricePattern, + pub class_average_price: ClassAveragePricePattern, + pub class_returns: MetricsTree_Market_Dca_ClassReturns, pub class_stack: MetricsTree_Market_Dca_ClassStack, pub period_average_price: PeriodAveragePricePattern, pub period_cagr: PeriodCagrPattern, @@ -4215,8 +4229,8 @@ pub struct MetricsTree_Market_Dca { impl MetricsTree_Market_Dca { pub fn new(client: Arc, base_path: String) -> Self { Self { - class_average_price: MetricsTree_Market_Dca_ClassAveragePrice::new(client.clone(), format!("{base_path}_class_average_price")), - class_returns: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), + class_average_price: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), + class_returns: MetricsTree_Market_Dca_ClassReturns::new(client.clone(), format!("{base_path}_class_returns")), class_stack: MetricsTree_Market_Dca_ClassStack::new(client.clone(), format!("{base_path}_class_stack")), period_average_price: PeriodAveragePricePattern::new(client.clone(), "dca_average_price".to_string()), period_cagr: PeriodCagrPattern::new(client.clone(), "dca_cagr".to_string()), @@ -4228,36 +4242,36 @@ impl MetricsTree_Market_Dca { } /// Metrics tree node. -pub struct MetricsTree_Market_Dca_ClassAveragePrice { - pub _2015: MetricPattern4, - pub _2016: MetricPattern4, - pub _2017: MetricPattern4, - pub _2018: MetricPattern4, - pub _2019: MetricPattern4, - pub _2020: MetricPattern4, - pub _2021: MetricPattern4, - pub _2022: MetricPattern4, - pub _2023: MetricPattern4, - pub _2024: MetricPattern4, - pub _2025: MetricPattern4, - pub _2026: MetricPattern4, +pub struct MetricsTree_Market_Dca_ClassReturns { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, + pub _2026: MetricPattern4, } -impl MetricsTree_Market_Dca_ClassAveragePrice { +impl MetricsTree_Market_Dca_ClassReturns { pub fn new(client: Arc, base_path: String) -> Self { Self { - _2015: MetricPattern4::new(client.clone(), "dca_class_2015_average_price".to_string()), - _2016: MetricPattern4::new(client.clone(), "dca_class_2016_average_price".to_string()), - _2017: MetricPattern4::new(client.clone(), "dca_class_2017_average_price".to_string()), - _2018: MetricPattern4::new(client.clone(), "dca_class_2018_average_price".to_string()), - _2019: MetricPattern4::new(client.clone(), "dca_class_2019_average_price".to_string()), - _2020: MetricPattern4::new(client.clone(), "dca_class_2020_average_price".to_string()), - _2021: MetricPattern4::new(client.clone(), "dca_class_2021_average_price".to_string()), - _2022: MetricPattern4::new(client.clone(), "dca_class_2022_average_price".to_string()), - _2023: MetricPattern4::new(client.clone(), "dca_class_2023_average_price".to_string()), - _2024: MetricPattern4::new(client.clone(), "dca_class_2024_average_price".to_string()), - _2025: MetricPattern4::new(client.clone(), "dca_class_2025_average_price".to_string()), - _2026: MetricPattern4::new(client.clone(), "dca_class_2026_average_price".to_string()), + _2015: MetricPattern4::new(client.clone(), "dca_class_2015_returns".to_string()), + _2016: MetricPattern4::new(client.clone(), "dca_class_2016_returns".to_string()), + _2017: MetricPattern4::new(client.clone(), "dca_class_2017_returns".to_string()), + _2018: MetricPattern4::new(client.clone(), "dca_class_2018_returns".to_string()), + _2019: MetricPattern4::new(client.clone(), "dca_class_2019_returns".to_string()), + _2020: MetricPattern4::new(client.clone(), "dca_class_2020_returns".to_string()), + _2021: MetricPattern4::new(client.clone(), "dca_class_2021_returns".to_string()), + _2022: MetricPattern4::new(client.clone(), "dca_class_2022_returns".to_string()), + _2023: MetricPattern4::new(client.clone(), "dca_class_2023_returns".to_string()), + _2024: MetricPattern4::new(client.clone(), "dca_class_2024_returns".to_string()), + _2025: MetricPattern4::new(client.clone(), "dca_class_2025_returns".to_string()), + _2026: MetricPattern4::new(client.clone(), "dca_class_2026_returns".to_string()), } } } diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index 71bcf4e79..d9da8f188 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -38,8 +38,8 @@ impl UTXOCohorts { ) -> Result { let v = version + VERSION; - // Phase 1: Import base cohorts that don't need adjusted (age_range, amount_range, etc.) - // These are the source cohorts for overlapping computations. + // Phase 1: Import base cohorts for overlapping computations (age_range, amount_range). + // These are the source cohorts and must be imported before "all" to provide up_to_1h. let base = |f: Filter, name: &'static str| { UTXOCohortVecs::forced_import( db, @@ -57,9 +57,6 @@ impl UTXOCohorts { let age_range = ByAgeRange::try_new(&base)?; let amount_range = ByAmountRange::try_new(&base)?; - let epoch = ByEpoch::try_new(&base)?; - let year = ByYear::try_new(&base)?; - let type_ = BySpendableType::try_new(&base)?; // Get up_to_1h realized for adjusted computation (cohort - up_to_1h) let up_to_1h_realized = age_range.up_to_1h.metrics.realized.as_ref(); @@ -80,7 +77,27 @@ impl UTXOCohorts { let all_supply = Some(&all.metrics.supply); - // Phase 3: Import cohorts that need adjusted and/or all_supply + // Phase 3: Import cohorts that need all_supply but not adjusted (epoch, year, type) + let base_with_all_supply = |f: Filter, name: &'static str| { + UTXOCohortVecs::forced_import( + db, + f, + name, + v, + indexes, + price, + states_path, + StateLevel::Full, + all_supply, + None, + ) + }; + + let epoch = ByEpoch::try_new(&base_with_all_supply)?; + let year = ByYear::try_new(&base_with_all_supply)?; + let type_ = BySpendableType::try_new(&base_with_all_supply)?; + + // Phase 4: Import cohorts that need all_supply and up_to_1h for adjusted let price_only_adjusted = |f: Filter, name: &'static str| { UTXOCohortVecs::forced_import( db, @@ -115,7 +132,17 @@ impl UTXOCohorts { let max_age = ByMaxAge::try_new(&none_adjusted)?; - // Phase 4: Import remaining cohorts (no adjusted needed) + // Phase 5: Add rel_to_circulating metrics to base cohorts now that up_to_1h_realized is no longer borrowed + let mut age_range = age_range; + let mut amount_range = amount_range; + for (vecs, name) in age_range.iter_mut().zip(ByAgeRange::names().iter()) { + vecs.add_rel_to_circulating(name.id, v, all_supply.unwrap()); + } + for (vecs, name) in amount_range.iter_mut().zip(ByAmountRange::names().iter()) { + vecs.add_rel_to_circulating(name.id, v, all_supply.unwrap()); + } + + // Phase 6: Import remaining cohorts (no adjusted needed) let none = |f: Filter, name: &'static str| { UTXOCohortVecs::forced_import( db, diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs b/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs index ee84c6777..69d3445b7 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs @@ -80,6 +80,19 @@ impl UTXOCohortVecs { }) } + /// Add relative-to-circulating-supply metrics in a second step. + /// Called after the "all" cohort is available. + pub fn add_rel_to_circulating( + &mut self, + name: &str, + version: Version, + all_supply: &SupplyMetrics, + ) { + let full_name = CohortContext::Utxo.full_name(self.filter(), name); + self.metrics + .add_rel_to_circulating(&full_name, version, all_supply); + } + /// Get the starting height when state was imported. pub fn state_starting_height(&self) -> Option { self.state_starting_height diff --git a/crates/brk_computer/src/distribution/metrics/mod.rs b/crates/brk_computer/src/distribution/metrics/mod.rs index 0ce788c3f..e24cff2e4 100644 --- a/crates/brk_computer/src/distribution/metrics/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/mod.rs @@ -333,6 +333,28 @@ impl CohortMetrics { Ok(()) } + /// Add relative-to-circulating-supply metrics in a second step. + /// Called after the "all" cohort is available. + pub fn add_rel_to_circulating( + &mut self, + full_name: &str, + version: Version, + all_supply: &SupplyMetrics, + ) { + if let (Some(relative), Some(unrealized)) = + (self.relative.as_mut(), self.unrealized.as_ref()) + { + relative.add_rel_to_circulating( + &self.filter, + full_name, + version, + unrealized, + &self.supply, + all_supply, + ); + } + } + /// Second phase of computed metrics (ratios, relative values). #[allow(clippy::too_many_arguments)] pub fn compute_rest_part2( diff --git a/crates/brk_computer/src/distribution/metrics/relative.rs b/crates/brk_computer/src/distribution/metrics/relative.rs index b624b614b..ea4974408 100644 --- a/crates/brk_computer/src/distribution/metrics/relative.rs +++ b/crates/brk_computer/src/distribution/metrics/relative.rs @@ -1,3 +1,4 @@ +use brk_cohort::Filter; use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Dollars, Sats, StoredF32, StoredF64, Version}; @@ -352,4 +353,95 @@ impl RelativeMetrics { }), }) } + + /// Add relative-to-circulating-supply metrics in a second step. + /// Called after the "all" cohort is available to provide global supply sources. + pub fn add_rel_to_circulating( + &mut self, + filter: &Filter, + full_name: &str, + version: Version, + unrealized: &UnrealizedMetrics, + supply: &SupplyMetrics, + all_supply: &SupplyMetrics, + ) { + let v1 = Version::ONE; + + // Skip if this is the "all" cohort itself + if !filter.compute_rel_to_all() { + return; + } + + let name = |suffix: &str| { + if full_name.is_empty() { + suffix.to_string() + } else { + format!("{full_name}_{suffix}") + } + }; + + // Global sources from "all" cohort + let global_supply_sats_height = &all_supply.total.sats.height; + let global_supply_sats_difficultyepoch = &all_supply.total.sats.difficultyepoch; + let global_supply_sats_dates = &all_supply.total.sats.rest.dates; + let global_supply_sats_dateindex = &all_supply.total.sats.rest.dateindex; + + // Fill in supply_rel_to_circulating_supply if not already set + if self.supply_rel_to_circulating_supply.is_none() { + self.supply_rel_to_circulating_supply = Some( + LazyBinaryFromDateLast::from_both_derived_last::( + &name("supply_rel_to_circulating_supply"), + version + v1, + supply.total.sats.rest.dateindex.boxed_clone(), + &supply.total.sats.rest.dates, + global_supply_sats_dateindex.boxed_clone(), + global_supply_sats_dates, + ), + ); + } + + // Fill in supply_in_profit_rel_to_circulating_supply if not already set + if self.supply_in_profit_rel_to_circulating_supply.is_none() { + self.supply_in_profit_rel_to_circulating_supply = Some( + LazyBinaryFromHeightLast::from_height_difficultyepoch_dates::( + &name("supply_in_profit_rel_to_circulating_supply"), + version + v1, + unrealized.supply_in_profit.height.boxed_clone(), + global_supply_sats_height.boxed_clone(), + unrealized.supply_in_profit.difficultyepoch.sats.boxed_clone(), + global_supply_sats_difficultyepoch.boxed_clone(), + unrealized + .supply_in_profit + .indexes + .sats_dateindex + .boxed_clone(), + &unrealized.supply_in_profit.indexes.sats, + global_supply_sats_dateindex.boxed_clone(), + global_supply_sats_dates, + ), + ); + } + + // Fill in supply_in_loss_rel_to_circulating_supply if not already set + if self.supply_in_loss_rel_to_circulating_supply.is_none() { + self.supply_in_loss_rel_to_circulating_supply = Some( + LazyBinaryFromHeightLast::from_height_difficultyepoch_dates::( + &name("supply_in_loss_rel_to_circulating_supply"), + version + v1, + unrealized.supply_in_loss.height.boxed_clone(), + global_supply_sats_height.boxed_clone(), + unrealized.supply_in_loss.difficultyepoch.sats.boxed_clone(), + global_supply_sats_difficultyepoch.boxed_clone(), + unrealized + .supply_in_loss + .indexes + .sats_dateindex + .boxed_clone(), + &unrealized.supply_in_loss.indexes.sats, + global_supply_sats_dateindex.boxed_clone(), + global_supply_sats_dates, + ), + ); + } + } } diff --git a/crates/brk_computer/src/pools/vecs.rs b/crates/brk_computer/src/pools/vecs.rs index f742014e1..98418cef2 100644 --- a/crates/brk_computer/src/pools/vecs.rs +++ b/crates/brk_computer/src/pools/vecs.rs @@ -34,6 +34,7 @@ pub struct Vecs { pub _1w_dominance: LazyBinaryFromHeightLast, pub _1m_dominance: LazyBinaryFromHeightLast, pub _1y_dominance: LazyBinaryFromHeightLast, + pub blocks_since_block: ComputedFromHeightLast, pub days_since_block: ComputedFromDateLast, } @@ -128,6 +129,12 @@ impl Vecs { >(&suffix("coinbase"), version, &subsidy, &fee), subsidy, fee, + blocks_since_block: ComputedFromHeightLast::forced_import( + db, + &suffix("blocks_since_block"), + version, + indexes, + )?, days_since_block: ComputedFromDateLast::forced_import( db, &suffix("days_since_block"), @@ -211,6 +218,26 @@ impl Vecs { self.fee.derive_from(indexes, starting_indexes, exit)?; + self.blocks_since_block + .compute_all(indexes, starting_indexes, exit, |v| { + let mut prev = StoredU32::ZERO; + v.compute_transform( + starting_indexes.height, + blocks_mined_height, + |(h, mined, ..)| { + let blocks = if mined.is_zero() { + prev + StoredU32::ONE + } else { + StoredU32::ZERO + }; + prev = blocks; + (h, blocks) + }, + exit, + )?; + Ok(()) + })?; + self.days_since_block .compute_all(starting_indexes, exit, |v| { let mut prev = None; diff --git a/crates/brk_playground/Cargo.toml b/crates/brk_playground/Cargo.toml index 60c91014f..2fcda31c5 100644 --- a/crates/brk_playground/Cargo.toml +++ b/crates/brk_playground/Cargo.toml @@ -40,3 +40,15 @@ path = "examples/tune_smooth.rs" [[example]] name = "debug_oracle" path = "examples/debug_oracle.rs" + +[[example]] +name = "filters" +path = "examples/filters.rs" + +[[example]] +name = "stencil" +path = "examples/stencil.rs" + +[[example]] +name = "epoch5_test" +path = "examples/epoch5_test.rs" diff --git a/modules/brk-client/README.md b/modules/brk-client/README.md index 7be9e20f7..2567dca2c 100644 --- a/modules/brk-client/README.md +++ b/modules/brk-client/README.md @@ -2,6 +2,8 @@ JavaScript/TypeScript client for the [Bitcoin Research Kit](https://github.com/bitcoinresearchkit/brk) API. +Zero dependencies. + [npm](https://www.npmjs.com/package/brk-client) | [API Reference](https://github.com/bitcoinresearchkit/brk/blob/main/modules/brk-client/docs/globals.md) ## Installation @@ -10,6 +12,8 @@ JavaScript/TypeScript client for the [Bitcoin Research Kit](https://github.com/b npm install brk-client ``` +Or just copy [`index.js`](./index.js) into your project - it's a single file with no dependencies. + ## Quick Start ```javascript diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 25e8ef5e8..8303bf481 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1815,6 +1815,7 @@ function createRelativePattern5(client, acc) { * @property {MetricPattern1} _24hBlocksMined * @property {MetricPattern1} _24hDominance * @property {BlockCountPattern} blocksMined + * @property {MetricPattern1} blocksSinceBlock * @property {CoinbasePattern2} coinbase * @property {MetricPattern4} daysSinceBlock * @property {MetricPattern1} dominance @@ -1839,6 +1840,7 @@ function createAaopoolPattern(client, acc) { _24hBlocksMined: createMetricPattern1(client, _m(acc, '24h_blocks_mined')), _24hDominance: createMetricPattern1(client, _m(acc, '24h_dominance')), blocksMined: createBlockCountPattern(client, _m(acc, 'blocks_mined')), + blocksSinceBlock: createMetricPattern1(client, _m(acc, 'blocks_since_block')), coinbase: createCoinbasePattern2(client, _m(acc, 'coinbase')), daysSinceBlock: createMetricPattern4(client, _m(acc, 'days_since_block')), dominance: createMetricPattern1(client, _m(acc, 'dominance')), @@ -1847,6 +1849,47 @@ function createAaopoolPattern(client, acc) { }; } +/** + * @typedef {Object} RelativePattern2 + * @property {MetricPattern1} negUnrealizedLossRelToOwnMarketCap + * @property {MetricPattern1} negUnrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern1} netUnrealizedPnlRelToOwnMarketCap + * @property {MetricPattern1} netUnrealizedPnlRelToOwnTotalUnrealizedPnl + * @property {MetricPattern1} supplyInLossRelToCirculatingSupply + * @property {MetricPattern1} supplyInLossRelToOwnSupply + * @property {MetricPattern1} supplyInProfitRelToCirculatingSupply + * @property {MetricPattern1} supplyInProfitRelToOwnSupply + * @property {MetricPattern4} supplyRelToCirculatingSupply + * @property {MetricPattern1} unrealizedLossRelToOwnMarketCap + * @property {MetricPattern1} unrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern1} unrealizedProfitRelToOwnMarketCap + * @property {MetricPattern1} unrealizedProfitRelToOwnTotalUnrealizedPnl + */ + +/** + * Create a RelativePattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {RelativePattern2} + */ +function createRelativePattern2(client, acc) { + return { + negUnrealizedLossRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')), + negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')), + netUnrealizedPnlRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')), + netUnrealizedPnlRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')), + supplyInLossRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')), + supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), + supplyInProfitRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), + supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')), + unrealizedLossRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), + unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), + unrealizedProfitRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), + unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), + }; +} + /** * @template T * @typedef {Object} LookbackPattern @@ -1929,6 +1972,47 @@ function createPeriodLumpSumStackPattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} ClassAveragePricePattern + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + * @property {MetricPattern4} _2026 + */ + +/** + * Create a ClassAveragePricePattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {ClassAveragePricePattern} + */ +function createClassAveragePricePattern(client, acc) { + return { + _2015: createMetricPattern4(client, _m(acc, '2015_average_price')), + _2016: createMetricPattern4(client, _m(acc, '2016_average_price')), + _2017: createMetricPattern4(client, _m(acc, '2017_average_price')), + _2018: createMetricPattern4(client, _m(acc, '2018_average_price')), + _2019: createMetricPattern4(client, _m(acc, '2019_average_price')), + _2020: createMetricPattern4(client, _m(acc, '2020_average_price')), + _2021: createMetricPattern4(client, _m(acc, '2021_average_price')), + _2022: createMetricPattern4(client, _m(acc, '2022_average_price')), + _2023: createMetricPattern4(client, _m(acc, '2023_average_price')), + _2024: createMetricPattern4(client, _m(acc, '2024_average_price')), + _2025: createMetricPattern4(client, _m(acc, '2025_average_price')), + _2026: createMetricPattern4(client, _m(acc, '2026_average_price')), + }; +} + /** * @template T * @typedef {Object} PeriodAveragePricePattern @@ -1970,47 +2054,6 @@ function createPeriodAveragePricePattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} ClassAveragePricePattern - * @property {MetricPattern4} _2015 - * @property {MetricPattern4} _2016 - * @property {MetricPattern4} _2017 - * @property {MetricPattern4} _2018 - * @property {MetricPattern4} _2019 - * @property {MetricPattern4} _2020 - * @property {MetricPattern4} _2021 - * @property {MetricPattern4} _2022 - * @property {MetricPattern4} _2023 - * @property {MetricPattern4} _2024 - * @property {MetricPattern4} _2025 - * @property {MetricPattern4} _2026 - */ - -/** - * Create a ClassAveragePricePattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {ClassAveragePricePattern} - */ -function createClassAveragePricePattern(client, acc) { - return { - _2015: createMetricPattern4(client, _m(acc, '2015_returns')), - _2016: createMetricPattern4(client, _m(acc, '2016_returns')), - _2017: createMetricPattern4(client, _m(acc, '2017_returns')), - _2018: createMetricPattern4(client, _m(acc, '2018_returns')), - _2019: createMetricPattern4(client, _m(acc, '2019_returns')), - _2020: createMetricPattern4(client, _m(acc, '2020_returns')), - _2021: createMetricPattern4(client, _m(acc, '2021_returns')), - _2022: createMetricPattern4(client, _m(acc, '2022_returns')), - _2023: createMetricPattern4(client, _m(acc, '2023_returns')), - _2024: createMetricPattern4(client, _m(acc, '2024_returns')), - _2025: createMetricPattern4(client, _m(acc, '2025_returns')), - _2026: createMetricPattern4(client, _m(acc, '2026_returns')), - }; -} - /** * @typedef {Object} BitcoinPattern * @property {MetricPattern2} average @@ -2122,41 +2165,6 @@ function createRelativePattern(client, acc) { }; } -/** - * @typedef {Object} RelativePattern2 - * @property {MetricPattern1} negUnrealizedLossRelToOwnMarketCap - * @property {MetricPattern1} negUnrealizedLossRelToOwnTotalUnrealizedPnl - * @property {MetricPattern1} netUnrealizedPnlRelToOwnMarketCap - * @property {MetricPattern1} netUnrealizedPnlRelToOwnTotalUnrealizedPnl - * @property {MetricPattern1} supplyInLossRelToOwnSupply - * @property {MetricPattern1} supplyInProfitRelToOwnSupply - * @property {MetricPattern1} unrealizedLossRelToOwnMarketCap - * @property {MetricPattern1} unrealizedLossRelToOwnTotalUnrealizedPnl - * @property {MetricPattern1} unrealizedProfitRelToOwnMarketCap - * @property {MetricPattern1} unrealizedProfitRelToOwnTotalUnrealizedPnl - */ - -/** - * Create a RelativePattern2 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {RelativePattern2} - */ -function createRelativePattern2(client, acc) { - return { - negUnrealizedLossRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')), - negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')), - netUnrealizedPnlRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')), - netUnrealizedPnlRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')), - supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), - unrealizedLossRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), - unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), - unrealizedProfitRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), - unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), - }; -} - /** * @template T * @typedef {Object} CountPattern2 @@ -2227,41 +2235,6 @@ function createAddrCountPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} FullnessPattern - * @property {MetricPattern2} average - * @property {MetricPattern11} base - * @property {MetricPattern2} max - * @property {MetricPattern6} median - * @property {MetricPattern2} min - * @property {MetricPattern6} pct10 - * @property {MetricPattern6} pct25 - * @property {MetricPattern6} pct75 - * @property {MetricPattern6} pct90 - */ - -/** - * Create a FullnessPattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {FullnessPattern} - */ -function createFullnessPattern(client, acc) { - return { - average: createMetricPattern2(client, _m(acc, 'average')), - base: createMetricPattern11(client, acc), - max: createMetricPattern2(client, _m(acc, 'max')), - median: createMetricPattern6(client, _m(acc, 'median')), - min: createMetricPattern2(client, _m(acc, 'min')), - pct10: createMetricPattern6(client, _m(acc, 'pct10')), - pct25: createMetricPattern6(client, _m(acc, 'pct25')), - pct75: createMetricPattern6(client, _m(acc, 'pct75')), - pct90: createMetricPattern6(client, _m(acc, 'pct90')), - }; -} - /** * @template T * @typedef {Object} FeeRatePattern @@ -2297,6 +2270,41 @@ function createFeeRatePattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} FullnessPattern + * @property {MetricPattern2} average + * @property {MetricPattern11} base + * @property {MetricPattern2} max + * @property {MetricPattern6} median + * @property {MetricPattern2} min + * @property {MetricPattern6} pct10 + * @property {MetricPattern6} pct25 + * @property {MetricPattern6} pct75 + * @property {MetricPattern6} pct90 + */ + +/** + * Create a FullnessPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {FullnessPattern} + */ +function createFullnessPattern(client, acc) { + return { + average: createMetricPattern2(client, _m(acc, 'average')), + base: createMetricPattern11(client, acc), + max: createMetricPattern2(client, _m(acc, 'max')), + median: createMetricPattern6(client, _m(acc, 'median')), + min: createMetricPattern2(client, _m(acc, 'min')), + pct10: createMetricPattern6(client, _m(acc, 'pct10')), + pct25: createMetricPattern6(client, _m(acc, 'pct25')), + pct75: createMetricPattern6(client, _m(acc, 'pct75')), + pct90: createMetricPattern6(client, _m(acc, 'pct90')), + }; +} + /** * @typedef {Object} _0satsPattern * @property {ActivityPattern2} activity @@ -2362,31 +2370,31 @@ function createPhaseDailyCentsPattern(client, acc) { } /** - * @typedef {Object} _10yTo12yPattern - * @property {ActivityPattern2} activity - * @property {CostBasisPattern2} costBasis - * @property {OutputsPattern} outputs - * @property {RealizedPattern2} realized - * @property {RelativePattern2} relative - * @property {SupplyPattern2} supply - * @property {UnrealizedPattern} unrealized + * @typedef {Object} PeriodCagrPattern + * @property {MetricPattern4} _10y + * @property {MetricPattern4} _2y + * @property {MetricPattern4} _3y + * @property {MetricPattern4} _4y + * @property {MetricPattern4} _5y + * @property {MetricPattern4} _6y + * @property {MetricPattern4} _8y */ /** - * Create a _10yTo12yPattern pattern node + * Create a PeriodCagrPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_10yTo12yPattern} + * @returns {PeriodCagrPattern} */ -function create_10yTo12yPattern(client, acc) { +function createPeriodCagrPattern(client, acc) { return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern2(client, acc), - outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), - realized: createRealizedPattern2(client, acc), - relative: createRelativePattern2(client, acc), - supply: createSupplyPattern2(client, _m(acc, 'supply')), - unrealized: createUnrealizedPattern(client, acc), + _10y: createMetricPattern4(client, _p('10y', acc)), + _2y: createMetricPattern4(client, _p('2y', acc)), + _3y: createMetricPattern4(client, _p('3y', acc)), + _4y: createMetricPattern4(client, _p('4y', acc)), + _5y: createMetricPattern4(client, _p('5y', acc)), + _6y: createMetricPattern4(client, _p('6y', acc)), + _8y: createMetricPattern4(client, _p('8y', acc)), }; } @@ -2442,14 +2450,14 @@ function create_0satsPattern2(client, acc) { costBasis: createCostBasisPattern(client, acc), outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), realized: createRealizedPattern(client, acc), - relative: createRelativePattern4(client, _m(acc, 'supply_in')), + relative: createRelativePattern4(client, _m(acc, 'supply')), supply: createSupplyPattern2(client, _m(acc, 'supply')), unrealized: createUnrealizedPattern(client, acc), }; } /** - * @typedef {Object} _100btcPattern + * @typedef {Object} _0Pattern * @property {ActivityPattern2} activity * @property {CostBasisPattern} costBasis * @property {OutputsPattern} outputs @@ -2460,12 +2468,12 @@ function create_0satsPattern2(client, acc) { */ /** - * Create a _100btcPattern pattern node + * Create a _0Pattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_100btcPattern} + * @returns {_0Pattern} */ -function create_100btcPattern(client, acc) { +function create_0Pattern(client, acc) { return { activity: createActivityPattern2(client, acc), costBasis: createCostBasisPattern(client, acc), @@ -2477,35 +2485,6 @@ function create_100btcPattern(client, acc) { }; } -/** - * @typedef {Object} PeriodCagrPattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _2y - * @property {MetricPattern4} _3y - * @property {MetricPattern4} _4y - * @property {MetricPattern4} _5y - * @property {MetricPattern4} _6y - * @property {MetricPattern4} _8y - */ - -/** - * Create a PeriodCagrPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {PeriodCagrPattern} - */ -function createPeriodCagrPattern(client, acc) { - return { - _10y: createMetricPattern4(client, _p('10y', acc)), - _2y: createMetricPattern4(client, _p('2y', acc)), - _3y: createMetricPattern4(client, _p('3y', acc)), - _4y: createMetricPattern4(client, _p('4y', acc)), - _5y: createMetricPattern4(client, _p('5y', acc)), - _6y: createMetricPattern4(client, _p('6y', acc)), - _8y: createMetricPattern4(client, _p('8y', acc)), - }; -} - /** * @typedef {Object} _10yPattern * @property {ActivityPattern2} activity @@ -2535,6 +2514,60 @@ function create_10yPattern(client, acc) { }; } +/** + * @typedef {Object} _10yTo12yPattern + * @property {ActivityPattern2} activity + * @property {CostBasisPattern2} costBasis + * @property {OutputsPattern} outputs + * @property {RealizedPattern2} realized + * @property {RelativePattern2} relative + * @property {SupplyPattern2} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _10yTo12yPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_10yTo12yPattern} + */ +function create_10yTo12yPattern(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern2(client, acc), + outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), + realized: createRealizedPattern2(client, acc), + relative: createRelativePattern2(client, acc), + supply: createSupplyPattern2(client, _m(acc, 'supply')), + unrealized: createUnrealizedPattern(client, acc), + }; +} + +/** + * @typedef {Object} RelativePattern4 + * @property {MetricPattern1} supplyInLossRelToCirculatingSupply + * @property {MetricPattern1} supplyInLossRelToOwnSupply + * @property {MetricPattern1} supplyInProfitRelToCirculatingSupply + * @property {MetricPattern1} supplyInProfitRelToOwnSupply + * @property {MetricPattern4} supplyRelToCirculatingSupply + */ + +/** + * Create a RelativePattern4 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {RelativePattern4} + */ +function createRelativePattern4(client, acc) { + return { + supplyInLossRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'in_loss_rel_to_circulating_supply')), + supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'in_loss_rel_to_own_supply')), + supplyInProfitRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'in_profit_rel_to_circulating_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'in_profit_rel_to_own_supply')), + supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'rel_to_circulating_supply')), + }; +} + /** * @typedef {Object} ActivityPattern2 * @property {BlockCountPattern} coinblocksDestroyed @@ -2585,27 +2618,6 @@ function createSplitPattern2(client, acc) { }; } -/** - * @typedef {Object} SegwitAdoptionPattern - * @property {MetricPattern11} base - * @property {MetricPattern2} cumulative - * @property {MetricPattern2} sum - */ - -/** - * Create a SegwitAdoptionPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SegwitAdoptionPattern} - */ -function createSegwitAdoptionPattern(client, acc) { - return { - base: createMetricPattern11(client, acc), - cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), - sum: createMetricPattern2(client, _m(acc, 'sum')), - }; -} - /** * @typedef {Object} UnclaimedRewardsPattern * @property {BitcoinPattern2} bitcoin @@ -2627,90 +2639,6 @@ function createUnclaimedRewardsPattern(client, acc) { }; } -/** - * @typedef {Object} ActiveSupplyPattern - * @property {MetricPattern1} bitcoin - * @property {MetricPattern1} dollars - * @property {MetricPattern1} sats - */ - -/** - * Create a ActiveSupplyPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {ActiveSupplyPattern} - */ -function createActiveSupplyPattern(client, acc) { - return { - bitcoin: createMetricPattern1(client, _m(acc, 'btc')), - dollars: createMetricPattern1(client, _m(acc, 'usd')), - sats: createMetricPattern1(client, acc), - }; -} - -/** - * @typedef {Object} CoinbasePattern2 - * @property {BlockCountPattern} bitcoin - * @property {BlockCountPattern} dollars - * @property {BlockCountPattern} sats - */ - -/** - * Create a CoinbasePattern2 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CoinbasePattern2} - */ -function createCoinbasePattern2(client, acc) { - return { - bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), - dollars: createBlockCountPattern(client, _m(acc, 'usd')), - sats: createBlockCountPattern(client, acc), - }; -} - -/** - * @typedef {Object} CostBasisPattern2 - * @property {MetricPattern1} max - * @property {MetricPattern1} min - * @property {PercentilesPattern} percentiles - */ - -/** - * Create a CostBasisPattern2 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CostBasisPattern2} - */ -function createCostBasisPattern2(client, acc) { - return { - max: createMetricPattern1(client, _m(acc, 'max_cost_basis')), - min: createMetricPattern1(client, _m(acc, 'min_cost_basis')), - percentiles: createPercentilesPattern(client, _m(acc, 'cost_basis')), - }; -} - -/** - * @typedef {Object} _2015Pattern - * @property {MetricPattern4} bitcoin - * @property {MetricPattern4} dollars - * @property {MetricPattern4} sats - */ - -/** - * Create a _2015Pattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_2015Pattern} - */ -function create_2015Pattern(client, acc) { - return { - bitcoin: createMetricPattern4(client, _m(acc, 'btc')), - dollars: createMetricPattern4(client, _m(acc, 'usd')), - sats: createMetricPattern4(client, acc), - }; -} - /** * @typedef {Object} CoinbasePattern * @property {BitcoinPattern} bitcoin @@ -2733,40 +2661,126 @@ function createCoinbasePattern(client, acc) { } /** - * @typedef {Object} RelativePattern4 - * @property {MetricPattern1} supplyInLossRelToOwnSupply - * @property {MetricPattern1} supplyInProfitRelToOwnSupply + * @typedef {Object} CostBasisPattern2 + * @property {MetricPattern1} max + * @property {MetricPattern1} min + * @property {PercentilesPattern} percentiles */ /** - * Create a RelativePattern4 pattern node + * Create a CostBasisPattern2 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {RelativePattern4} + * @returns {CostBasisPattern2} */ -function createRelativePattern4(client, acc) { +function createCostBasisPattern2(client, acc) { return { - supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'loss_rel_to_own_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'profit_rel_to_own_supply')), + max: createMetricPattern1(client, _m(acc, 'max_cost_basis')), + min: createMetricPattern1(client, _m(acc, 'min_cost_basis')), + percentiles: createPercentilesPattern(client, _m(acc, 'cost_basis')), }; } /** - * @typedef {Object} _1dReturns1mSdPattern - * @property {MetricPattern4} sd - * @property {MetricPattern4} sma + * @typedef {Object} ActiveSupplyPattern + * @property {MetricPattern1} bitcoin + * @property {MetricPattern1} dollars + * @property {MetricPattern1} sats */ /** - * Create a _1dReturns1mSdPattern pattern node + * Create a ActiveSupplyPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_1dReturns1mSdPattern} + * @returns {ActiveSupplyPattern} */ -function create_1dReturns1mSdPattern(client, acc) { +function createActiveSupplyPattern(client, acc) { return { - sd: createMetricPattern4(client, _m(acc, 'sd')), - sma: createMetricPattern4(client, _m(acc, 'sma')), + bitcoin: createMetricPattern1(client, _m(acc, 'btc')), + dollars: createMetricPattern1(client, _m(acc, 'usd')), + sats: createMetricPattern1(client, acc), + }; +} + +/** + * @typedef {Object} _2015Pattern + * @property {MetricPattern4} bitcoin + * @property {MetricPattern4} dollars + * @property {MetricPattern4} sats + */ + +/** + * Create a _2015Pattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_2015Pattern} + */ +function create_2015Pattern(client, acc) { + return { + bitcoin: createMetricPattern4(client, _m(acc, 'btc')), + dollars: createMetricPattern4(client, _m(acc, 'usd')), + sats: createMetricPattern4(client, acc), + }; +} + +/** + * @typedef {Object} SegwitAdoptionPattern + * @property {MetricPattern11} base + * @property {MetricPattern2} cumulative + * @property {MetricPattern2} sum + */ + +/** + * Create a SegwitAdoptionPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {SegwitAdoptionPattern} + */ +function createSegwitAdoptionPattern(client, acc) { + return { + base: createMetricPattern11(client, acc), + cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), + sum: createMetricPattern2(client, _m(acc, 'sum')), + }; +} + +/** + * @typedef {Object} CoinbasePattern2 + * @property {BlockCountPattern} bitcoin + * @property {BlockCountPattern} dollars + * @property {BlockCountPattern} sats + */ + +/** + * Create a CoinbasePattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CoinbasePattern2} + */ +function createCoinbasePattern2(client, acc) { + return { + bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), + dollars: createBlockCountPattern(client, _m(acc, 'usd')), + sats: createBlockCountPattern(client, acc), + }; +} + +/** + * @typedef {Object} SupplyPattern2 + * @property {ActiveSupplyPattern} halved + * @property {ActiveSupplyPattern} total + */ + +/** + * Create a SupplyPattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {SupplyPattern2} + */ +function createSupplyPattern2(client, acc) { + return { + halved: createActiveSupplyPattern(client, _m(acc, 'halved')), + total: createActiveSupplyPattern(client, acc), }; } @@ -2790,21 +2804,21 @@ function createCostBasisPattern(client, acc) { } /** - * @typedef {Object} SupplyPattern2 - * @property {ActiveSupplyPattern} halved - * @property {ActiveSupplyPattern} total + * @typedef {Object} _1dReturns1mSdPattern + * @property {MetricPattern4} sd + * @property {MetricPattern4} sma */ /** - * Create a SupplyPattern2 pattern node + * Create a _1dReturns1mSdPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {SupplyPattern2} + * @returns {_1dReturns1mSdPattern} */ -function createSupplyPattern2(client, acc) { +function create_1dReturns1mSdPattern(client, acc) { return { - halved: createActiveSupplyPattern(client, _m(acc, 'halved')), - total: createActiveSupplyPattern(client, acc), + sd: createMetricPattern4(client, _m(acc, 'sd')), + sma: createMetricPattern4(client, _m(acc, 'sma')), }; } @@ -2829,27 +2843,6 @@ function createSatsPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} BitcoinPattern2 - * @property {MetricPattern2} cumulative - * @property {MetricPattern1} sum - */ - -/** - * Create a BitcoinPattern2 pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {BitcoinPattern2} - */ -function createBitcoinPattern2(client, acc) { - return { - cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), - sum: createMetricPattern1(client, acc), - }; -} - /** * @template T * @typedef {Object} BlockCountPattern @@ -2871,6 +2864,27 @@ function createBlockCountPattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} BitcoinPattern2 + * @property {MetricPattern2} cumulative + * @property {MetricPattern1} sum + */ + +/** + * Create a BitcoinPattern2 pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {BitcoinPattern2} + */ +function createBitcoinPattern2(client, acc) { + return { + cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), + sum: createMetricPattern1(client, acc), + }; +} + /** * @typedef {Object} OutputsPattern * @property {MetricPattern1} utxoCount @@ -3323,45 +3337,45 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_Epoch - * @property {_0satsPattern2} _0 - * @property {_0satsPattern2} _1 - * @property {_0satsPattern2} _2 - * @property {_0satsPattern2} _3 - * @property {_0satsPattern2} _4 + * @property {_0Pattern} _0 + * @property {_0Pattern} _1 + * @property {_0Pattern} _2 + * @property {_0Pattern} _3 + * @property {_0Pattern} _4 */ /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_GeAmount - * @property {_100btcPattern} _100btc - * @property {_100btcPattern} _100kSats - * @property {_100btcPattern} _100sats - * @property {_100btcPattern} _10btc - * @property {_100btcPattern} _10kBtc - * @property {_100btcPattern} _10kSats - * @property {_100btcPattern} _10mSats - * @property {_100btcPattern} _10sats - * @property {_100btcPattern} _1btc - * @property {_100btcPattern} _1kBtc - * @property {_100btcPattern} _1kSats - * @property {_100btcPattern} _1mSats - * @property {_100btcPattern} _1sat + * @property {_0Pattern} _100btc + * @property {_0Pattern} _100kSats + * @property {_0Pattern} _100sats + * @property {_0Pattern} _10btc + * @property {_0Pattern} _10kBtc + * @property {_0Pattern} _10kSats + * @property {_0Pattern} _10mSats + * @property {_0Pattern} _10sats + * @property {_0Pattern} _1btc + * @property {_0Pattern} _1kBtc + * @property {_0Pattern} _1kSats + * @property {_0Pattern} _1mSats + * @property {_0Pattern} _1sat */ /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_LtAmount - * @property {_100btcPattern} _100btc - * @property {_100btcPattern} _100kBtc - * @property {_100btcPattern} _100kSats - * @property {_100btcPattern} _100sats - * @property {_100btcPattern} _10btc - * @property {_100btcPattern} _10kBtc - * @property {_100btcPattern} _10kSats - * @property {_100btcPattern} _10mSats - * @property {_100btcPattern} _10sats - * @property {_100btcPattern} _1btc - * @property {_100btcPattern} _1kBtc - * @property {_100btcPattern} _1kSats - * @property {_100btcPattern} _1mSats + * @property {_0Pattern} _100btc + * @property {_0Pattern} _100kBtc + * @property {_0Pattern} _100kSats + * @property {_0Pattern} _100sats + * @property {_0Pattern} _10btc + * @property {_0Pattern} _10kBtc + * @property {_0Pattern} _10kSats + * @property {_0Pattern} _10mSats + * @property {_0Pattern} _10sats + * @property {_0Pattern} _1btc + * @property {_0Pattern} _1kBtc + * @property {_0Pattern} _1kSats + * @property {_0Pattern} _1mSats */ /** @@ -3388,24 +3402,24 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_MinAge - * @property {_100btcPattern} _10y - * @property {_100btcPattern} _12y - * @property {_100btcPattern} _1d - * @property {_100btcPattern} _1m - * @property {_100btcPattern} _1w - * @property {_100btcPattern} _1y - * @property {_100btcPattern} _2m - * @property {_100btcPattern} _2y - * @property {_100btcPattern} _3m - * @property {_100btcPattern} _3y - * @property {_100btcPattern} _4m - * @property {_100btcPattern} _4y - * @property {_100btcPattern} _5m - * @property {_100btcPattern} _5y - * @property {_100btcPattern} _6m - * @property {_100btcPattern} _6y - * @property {_100btcPattern} _7y - * @property {_100btcPattern} _8y + * @property {_0Pattern} _10y + * @property {_0Pattern} _12y + * @property {_0Pattern} _1d + * @property {_0Pattern} _1m + * @property {_0Pattern} _1w + * @property {_0Pattern} _1y + * @property {_0Pattern} _2m + * @property {_0Pattern} _2y + * @property {_0Pattern} _3m + * @property {_0Pattern} _3y + * @property {_0Pattern} _4m + * @property {_0Pattern} _4y + * @property {_0Pattern} _5m + * @property {_0Pattern} _5y + * @property {_0Pattern} _6m + * @property {_0Pattern} _6y + * @property {_0Pattern} _7y + * @property {_0Pattern} _8y */ /** @@ -3438,39 +3452,39 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_Type - * @property {_0satsPattern2} empty - * @property {_0satsPattern2} p2a - * @property {_0satsPattern2} p2ms - * @property {_0satsPattern2} p2pk33 - * @property {_0satsPattern2} p2pk65 - * @property {_0satsPattern2} p2pkh - * @property {_0satsPattern2} p2sh - * @property {_0satsPattern2} p2tr - * @property {_0satsPattern2} p2wpkh - * @property {_0satsPattern2} p2wsh - * @property {_0satsPattern2} unknown + * @property {_0Pattern} empty + * @property {_0Pattern} p2a + * @property {_0Pattern} p2ms + * @property {_0Pattern} p2pk33 + * @property {_0Pattern} p2pk65 + * @property {_0Pattern} p2pkh + * @property {_0Pattern} p2sh + * @property {_0Pattern} p2tr + * @property {_0Pattern} p2wpkh + * @property {_0Pattern} p2wsh + * @property {_0Pattern} unknown */ /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_Year - * @property {_0satsPattern2} _2009 - * @property {_0satsPattern2} _2010 - * @property {_0satsPattern2} _2011 - * @property {_0satsPattern2} _2012 - * @property {_0satsPattern2} _2013 - * @property {_0satsPattern2} _2014 - * @property {_0satsPattern2} _2015 - * @property {_0satsPattern2} _2016 - * @property {_0satsPattern2} _2017 - * @property {_0satsPattern2} _2018 - * @property {_0satsPattern2} _2019 - * @property {_0satsPattern2} _2020 - * @property {_0satsPattern2} _2021 - * @property {_0satsPattern2} _2022 - * @property {_0satsPattern2} _2023 - * @property {_0satsPattern2} _2024 - * @property {_0satsPattern2} _2025 - * @property {_0satsPattern2} _2026 + * @property {_0Pattern} _2009 + * @property {_0Pattern} _2010 + * @property {_0Pattern} _2011 + * @property {_0Pattern} _2012 + * @property {_0Pattern} _2013 + * @property {_0Pattern} _2014 + * @property {_0Pattern} _2015 + * @property {_0Pattern} _2016 + * @property {_0Pattern} _2017 + * @property {_0Pattern} _2018 + * @property {_0Pattern} _2019 + * @property {_0Pattern} _2020 + * @property {_0Pattern} _2021 + * @property {_0Pattern} _2022 + * @property {_0Pattern} _2023 + * @property {_0Pattern} _2024 + * @property {_0Pattern} _2025 + * @property {_0Pattern} _2026 */ /** @@ -3709,8 +3723,8 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} MetricsTree_Market_Dca - * @property {MetricsTree_Market_Dca_ClassAveragePrice} classAveragePrice - * @property {ClassAveragePricePattern} classReturns + * @property {ClassAveragePricePattern} classAveragePrice + * @property {MetricsTree_Market_Dca_ClassReturns} classReturns * @property {MetricsTree_Market_Dca_ClassStack} classStack * @property {PeriodAveragePricePattern} periodAveragePrice * @property {PeriodCagrPattern} periodCagr @@ -3720,19 +3734,19 @@ function createRealizedPriceExtraPattern(client, acc) { */ /** - * @typedef {Object} MetricsTree_Market_Dca_ClassAveragePrice - * @property {MetricPattern4} _2015 - * @property {MetricPattern4} _2016 - * @property {MetricPattern4} _2017 - * @property {MetricPattern4} _2018 - * @property {MetricPattern4} _2019 - * @property {MetricPattern4} _2020 - * @property {MetricPattern4} _2021 - * @property {MetricPattern4} _2022 - * @property {MetricPattern4} _2023 - * @property {MetricPattern4} _2024 - * @property {MetricPattern4} _2025 - * @property {MetricPattern4} _2026 + * @typedef {Object} MetricsTree_Market_Dca_ClassReturns + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + * @property {MetricPattern4} _2026 */ /** @@ -5484,41 +5498,41 @@ class BrkClient extends BrkClientBase { _1satTo10sats: create_0satsPattern2(this, 'utxos_above_1sat_under_10sats'), }, epoch: { - _0: create_0satsPattern2(this, 'epoch_0'), - _1: create_0satsPattern2(this, 'epoch_1'), - _2: create_0satsPattern2(this, 'epoch_2'), - _3: create_0satsPattern2(this, 'epoch_3'), - _4: create_0satsPattern2(this, 'epoch_4'), + _0: create_0Pattern(this, 'epoch_0'), + _1: create_0Pattern(this, 'epoch_1'), + _2: create_0Pattern(this, 'epoch_2'), + _3: create_0Pattern(this, 'epoch_3'), + _4: create_0Pattern(this, 'epoch_4'), }, geAmount: { - _100btc: create_100btcPattern(this, 'utxos_above_100btc'), - _100kSats: create_100btcPattern(this, 'utxos_above_100k_sats'), - _100sats: create_100btcPattern(this, 'utxos_above_100sats'), - _10btc: create_100btcPattern(this, 'utxos_above_10btc'), - _10kBtc: create_100btcPattern(this, 'utxos_above_10k_btc'), - _10kSats: create_100btcPattern(this, 'utxos_above_10k_sats'), - _10mSats: create_100btcPattern(this, 'utxos_above_10m_sats'), - _10sats: create_100btcPattern(this, 'utxos_above_10sats'), - _1btc: create_100btcPattern(this, 'utxos_above_1btc'), - _1kBtc: create_100btcPattern(this, 'utxos_above_1k_btc'), - _1kSats: create_100btcPattern(this, 'utxos_above_1k_sats'), - _1mSats: create_100btcPattern(this, 'utxos_above_1m_sats'), - _1sat: create_100btcPattern(this, 'utxos_above_1sat'), + _100btc: create_0Pattern(this, 'utxos_above_100btc'), + _100kSats: create_0Pattern(this, 'utxos_above_100k_sats'), + _100sats: create_0Pattern(this, 'utxos_above_100sats'), + _10btc: create_0Pattern(this, 'utxos_above_10btc'), + _10kBtc: create_0Pattern(this, 'utxos_above_10k_btc'), + _10kSats: create_0Pattern(this, 'utxos_above_10k_sats'), + _10mSats: create_0Pattern(this, 'utxos_above_10m_sats'), + _10sats: create_0Pattern(this, 'utxos_above_10sats'), + _1btc: create_0Pattern(this, 'utxos_above_1btc'), + _1kBtc: create_0Pattern(this, 'utxos_above_1k_btc'), + _1kSats: create_0Pattern(this, 'utxos_above_1k_sats'), + _1mSats: create_0Pattern(this, 'utxos_above_1m_sats'), + _1sat: create_0Pattern(this, 'utxos_above_1sat'), }, ltAmount: { - _100btc: create_100btcPattern(this, 'utxos_under_100btc'), - _100kBtc: create_100btcPattern(this, 'utxos_under_100k_btc'), - _100kSats: create_100btcPattern(this, 'utxos_under_100k_sats'), - _100sats: create_100btcPattern(this, 'utxos_under_100sats'), - _10btc: create_100btcPattern(this, 'utxos_under_10btc'), - _10kBtc: create_100btcPattern(this, 'utxos_under_10k_btc'), - _10kSats: create_100btcPattern(this, 'utxos_under_10k_sats'), - _10mSats: create_100btcPattern(this, 'utxos_under_10m_sats'), - _10sats: create_100btcPattern(this, 'utxos_under_10sats'), - _1btc: create_100btcPattern(this, 'utxos_under_1btc'), - _1kBtc: create_100btcPattern(this, 'utxos_under_1k_btc'), - _1kSats: create_100btcPattern(this, 'utxos_under_1k_sats'), - _1mSats: create_100btcPattern(this, 'utxos_under_1m_sats'), + _100btc: create_0Pattern(this, 'utxos_under_100btc'), + _100kBtc: create_0Pattern(this, 'utxos_under_100k_btc'), + _100kSats: create_0Pattern(this, 'utxos_under_100k_sats'), + _100sats: create_0Pattern(this, 'utxos_under_100sats'), + _10btc: create_0Pattern(this, 'utxos_under_10btc'), + _10kBtc: create_0Pattern(this, 'utxos_under_10k_btc'), + _10kSats: create_0Pattern(this, 'utxos_under_10k_sats'), + _10mSats: create_0Pattern(this, 'utxos_under_10m_sats'), + _10sats: create_0Pattern(this, 'utxos_under_10sats'), + _1btc: create_0Pattern(this, 'utxos_under_1btc'), + _1kBtc: create_0Pattern(this, 'utxos_under_1k_btc'), + _1kSats: create_0Pattern(this, 'utxos_under_1k_sats'), + _1mSats: create_0Pattern(this, 'utxos_under_1m_sats'), }, maxAge: { _10y: create_10yPattern(this, 'utxos_up_to_10y_old'), @@ -5541,24 +5555,24 @@ class BrkClient extends BrkClientBase { _8y: create_10yPattern(this, 'utxos_up_to_8y_old'), }, minAge: { - _10y: create_100btcPattern(this, 'utxos_at_least_10y_old'), - _12y: create_100btcPattern(this, 'utxos_at_least_12y_old'), - _1d: create_100btcPattern(this, 'utxos_at_least_1d_old'), - _1m: create_100btcPattern(this, 'utxos_at_least_1m_old'), - _1w: create_100btcPattern(this, 'utxos_at_least_1w_old'), - _1y: create_100btcPattern(this, 'utxos_at_least_1y_old'), - _2m: create_100btcPattern(this, 'utxos_at_least_2m_old'), - _2y: create_100btcPattern(this, 'utxos_at_least_2y_old'), - _3m: create_100btcPattern(this, 'utxos_at_least_3m_old'), - _3y: create_100btcPattern(this, 'utxos_at_least_3y_old'), - _4m: create_100btcPattern(this, 'utxos_at_least_4m_old'), - _4y: create_100btcPattern(this, 'utxos_at_least_4y_old'), - _5m: create_100btcPattern(this, 'utxos_at_least_5m_old'), - _5y: create_100btcPattern(this, 'utxos_at_least_5y_old'), - _6m: create_100btcPattern(this, 'utxos_at_least_6m_old'), - _6y: create_100btcPattern(this, 'utxos_at_least_6y_old'), - _7y: create_100btcPattern(this, 'utxos_at_least_7y_old'), - _8y: create_100btcPattern(this, 'utxos_at_least_8y_old'), + _10y: create_0Pattern(this, 'utxos_at_least_10y_old'), + _12y: create_0Pattern(this, 'utxos_at_least_12y_old'), + _1d: create_0Pattern(this, 'utxos_at_least_1d_old'), + _1m: create_0Pattern(this, 'utxos_at_least_1m_old'), + _1w: create_0Pattern(this, 'utxos_at_least_1w_old'), + _1y: create_0Pattern(this, 'utxos_at_least_1y_old'), + _2m: create_0Pattern(this, 'utxos_at_least_2m_old'), + _2y: create_0Pattern(this, 'utxos_at_least_2y_old'), + _3m: create_0Pattern(this, 'utxos_at_least_3m_old'), + _3y: create_0Pattern(this, 'utxos_at_least_3y_old'), + _4m: create_0Pattern(this, 'utxos_at_least_4m_old'), + _4y: create_0Pattern(this, 'utxos_at_least_4y_old'), + _5m: create_0Pattern(this, 'utxos_at_least_5m_old'), + _5y: create_0Pattern(this, 'utxos_at_least_5y_old'), + _6m: create_0Pattern(this, 'utxos_at_least_6m_old'), + _6y: create_0Pattern(this, 'utxos_at_least_6y_old'), + _7y: create_0Pattern(this, 'utxos_at_least_7y_old'), + _8y: create_0Pattern(this, 'utxos_at_least_8y_old'), }, term: { long: { @@ -5581,37 +5595,37 @@ class BrkClient extends BrkClientBase { }, }, type: { - empty: create_0satsPattern2(this, 'empty_outputs'), - p2a: create_0satsPattern2(this, 'p2a'), - p2ms: create_0satsPattern2(this, 'p2ms'), - p2pk33: create_0satsPattern2(this, 'p2pk33'), - p2pk65: create_0satsPattern2(this, 'p2pk65'), - p2pkh: create_0satsPattern2(this, 'p2pkh'), - p2sh: create_0satsPattern2(this, 'p2sh'), - p2tr: create_0satsPattern2(this, 'p2tr'), - p2wpkh: create_0satsPattern2(this, 'p2wpkh'), - p2wsh: create_0satsPattern2(this, 'p2wsh'), - unknown: create_0satsPattern2(this, 'unknown_outputs'), + empty: create_0Pattern(this, 'empty_outputs'), + p2a: create_0Pattern(this, 'p2a'), + p2ms: create_0Pattern(this, 'p2ms'), + p2pk33: create_0Pattern(this, 'p2pk33'), + p2pk65: create_0Pattern(this, 'p2pk65'), + p2pkh: create_0Pattern(this, 'p2pkh'), + p2sh: create_0Pattern(this, 'p2sh'), + p2tr: create_0Pattern(this, 'p2tr'), + p2wpkh: create_0Pattern(this, 'p2wpkh'), + p2wsh: create_0Pattern(this, 'p2wsh'), + unknown: create_0Pattern(this, 'unknown_outputs'), }, year: { - _2009: create_0satsPattern2(this, 'year_2009'), - _2010: create_0satsPattern2(this, 'year_2010'), - _2011: create_0satsPattern2(this, 'year_2011'), - _2012: create_0satsPattern2(this, 'year_2012'), - _2013: create_0satsPattern2(this, 'year_2013'), - _2014: create_0satsPattern2(this, 'year_2014'), - _2015: create_0satsPattern2(this, 'year_2015'), - _2016: create_0satsPattern2(this, 'year_2016'), - _2017: create_0satsPattern2(this, 'year_2017'), - _2018: create_0satsPattern2(this, 'year_2018'), - _2019: create_0satsPattern2(this, 'year_2019'), - _2020: create_0satsPattern2(this, 'year_2020'), - _2021: create_0satsPattern2(this, 'year_2021'), - _2022: create_0satsPattern2(this, 'year_2022'), - _2023: create_0satsPattern2(this, 'year_2023'), - _2024: create_0satsPattern2(this, 'year_2024'), - _2025: create_0satsPattern2(this, 'year_2025'), - _2026: create_0satsPattern2(this, 'year_2026'), + _2009: create_0Pattern(this, 'year_2009'), + _2010: create_0Pattern(this, 'year_2010'), + _2011: create_0Pattern(this, 'year_2011'), + _2012: create_0Pattern(this, 'year_2012'), + _2013: create_0Pattern(this, 'year_2013'), + _2014: create_0Pattern(this, 'year_2014'), + _2015: create_0Pattern(this, 'year_2015'), + _2016: create_0Pattern(this, 'year_2016'), + _2017: create_0Pattern(this, 'year_2017'), + _2018: create_0Pattern(this, 'year_2018'), + _2019: create_0Pattern(this, 'year_2019'), + _2020: create_0Pattern(this, 'year_2020'), + _2021: create_0Pattern(this, 'year_2021'), + _2022: create_0Pattern(this, 'year_2022'), + _2023: create_0Pattern(this, 'year_2023'), + _2024: create_0Pattern(this, 'year_2024'), + _2025: create_0Pattern(this, 'year_2025'), + _2026: create_0Pattern(this, 'year_2026'), }, }, }, @@ -5752,21 +5766,21 @@ class BrkClient extends BrkClientBase { yearsSincePriceAth: createMetricPattern4(this, 'years_since_price_ath'), }, dca: { - classAveragePrice: { - _2015: createMetricPattern4(this, 'dca_class_2015_average_price'), - _2016: createMetricPattern4(this, 'dca_class_2016_average_price'), - _2017: createMetricPattern4(this, 'dca_class_2017_average_price'), - _2018: createMetricPattern4(this, 'dca_class_2018_average_price'), - _2019: createMetricPattern4(this, 'dca_class_2019_average_price'), - _2020: createMetricPattern4(this, 'dca_class_2020_average_price'), - _2021: createMetricPattern4(this, 'dca_class_2021_average_price'), - _2022: createMetricPattern4(this, 'dca_class_2022_average_price'), - _2023: createMetricPattern4(this, 'dca_class_2023_average_price'), - _2024: createMetricPattern4(this, 'dca_class_2024_average_price'), - _2025: createMetricPattern4(this, 'dca_class_2025_average_price'), - _2026: createMetricPattern4(this, 'dca_class_2026_average_price'), + classAveragePrice: createClassAveragePricePattern(this, 'dca_class'), + classReturns: { + _2015: createMetricPattern4(this, 'dca_class_2015_returns'), + _2016: createMetricPattern4(this, 'dca_class_2016_returns'), + _2017: createMetricPattern4(this, 'dca_class_2017_returns'), + _2018: createMetricPattern4(this, 'dca_class_2018_returns'), + _2019: createMetricPattern4(this, 'dca_class_2019_returns'), + _2020: createMetricPattern4(this, 'dca_class_2020_returns'), + _2021: createMetricPattern4(this, 'dca_class_2021_returns'), + _2022: createMetricPattern4(this, 'dca_class_2022_returns'), + _2023: createMetricPattern4(this, 'dca_class_2023_returns'), + _2024: createMetricPattern4(this, 'dca_class_2024_returns'), + _2025: createMetricPattern4(this, 'dca_class_2025_returns'), + _2026: createMetricPattern4(this, 'dca_class_2026_returns'), }, - classReturns: createClassAveragePricePattern(this, 'dca_class'), classStack: { _2015: create_2015Pattern(this, 'dca_class_2015_stack'), _2016: create_2015Pattern(this, 'dca_class_2016_stack'), diff --git a/packages/brk_client/.python-version b/packages/brk_client/.python-version index e4fba2183..bd28b9c5c 100644 --- a/packages/brk_client/.python-version +++ b/packages/brk_client/.python-version @@ -1 +1 @@ -3.12 +3.9 diff --git a/packages/brk_client/README.md b/packages/brk_client/README.md index 2a9432218..a80683d16 100644 --- a/packages/brk_client/README.md +++ b/packages/brk_client/README.md @@ -2,6 +2,8 @@ Python client for the [Bitcoin Research Kit](https://github.com/bitcoinresearchkit/brk) API. +Requires Python 3.9+. Zero dependencies. + [PyPI](https://pypi.org/project/brk-client/) | [API Reference](https://github.com/bitcoinresearchkit/brk/blob/main/packages/brk_client/DOCS.md) ## Installation @@ -12,6 +14,8 @@ pip install brk-client uv add brk-client ``` +Or just copy [`brk_client/__init__.py`](./brk_client/__init__.py) into your project - it's a single file with no dependencies. + ## Quick Start ```python diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 6663603e5..c3fe7220d 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -1,6 +1,8 @@ # Auto-generated BRK Python client # Do not edit manually +from __future__ import annotations +from dataclasses import dataclass from typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol, overload from http.client import HTTPSConnection, HTTPConnection from urllib.parse import urlparse @@ -1039,7 +1041,8 @@ def _p(prefix: str, acc: str) -> str: return f"{prefix}_{acc}" if acc else prefix -class MetricData(TypedDict, Generic[T]): +@dataclass +class MetricData(Generic[T]): """Metric data with range information.""" version: int total: int @@ -1084,8 +1087,9 @@ class _EndpointConfig: p = self.path() return f"{p}?{query}" if query else p - def get_json(self) -> Any: - return self.client.get_json(self._build_path()) + def get_json(self) -> MetricData: + data = self.client.get_json(self._build_path()) + return MetricData(**data) def get_csv(self) -> str: return self.client.get_text(self._build_path(format='csv')) @@ -1288,7 +1292,7 @@ _i31 = ('loadedaddressindex',) _i32 = ('emptyaddressindex',) _i33 = ('pairoutputindex',) -def _ep(c: BrkClientBase, n: str, i: Index) -> MetricEndpointBuilder: +def _ep(c: BrkClientBase, n: str, i: Index) -> MetricEndpointBuilder[Any]: return MetricEndpointBuilder(c, n, i) # Index accessor classes @@ -1306,6 +1310,7 @@ class _MetricPattern1By(Generic[T]): def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex') class MetricPattern1(Generic[T]): + by: _MetricPattern1By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern1By(c, n) @property def name(self) -> str: return self._n @@ -1324,6 +1329,7 @@ class _MetricPattern2By(Generic[T]): def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex') class MetricPattern2(Generic[T]): + by: _MetricPattern2By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern2By(c, n) @property def name(self) -> str: return self._n @@ -1342,6 +1348,7 @@ class _MetricPattern3By(Generic[T]): def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex') class MetricPattern3(Generic[T]): + by: _MetricPattern3By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern3By(c, n) @property def name(self) -> str: return self._n @@ -1359,6 +1366,7 @@ class _MetricPattern4By(Generic[T]): def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex') class MetricPattern4(Generic[T]): + by: _MetricPattern4By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern4By(c, n) @property def name(self) -> str: return self._n @@ -1371,6 +1379,7 @@ class _MetricPattern5By(Generic[T]): def height(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'height') class MetricPattern5(Generic[T]): + by: _MetricPattern5By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern5By(c, n) @property def name(self) -> str: return self._n @@ -1382,6 +1391,7 @@ class _MetricPattern6By(Generic[T]): def dateindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'dateindex') class MetricPattern6(Generic[T]): + by: _MetricPattern6By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern6By(c, n) @property def name(self) -> str: return self._n @@ -1393,6 +1403,7 @@ class _MetricPattern7By(Generic[T]): def decadeindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'decadeindex') class MetricPattern7(Generic[T]): + by: _MetricPattern7By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern7By(c, n) @property def name(self) -> str: return self._n @@ -1404,6 +1415,7 @@ class _MetricPattern8By(Generic[T]): def difficultyepoch(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'difficultyepoch') class MetricPattern8(Generic[T]): + by: _MetricPattern8By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern8By(c, n) @property def name(self) -> str: return self._n @@ -1415,6 +1427,7 @@ class _MetricPattern9By(Generic[T]): def emptyoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'emptyoutputindex') class MetricPattern9(Generic[T]): + by: _MetricPattern9By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern9By(c, n) @property def name(self) -> str: return self._n @@ -1426,6 +1439,7 @@ class _MetricPattern10By(Generic[T]): def halvingepoch(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'halvingepoch') class MetricPattern10(Generic[T]): + by: _MetricPattern10By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern10By(c, n) @property def name(self) -> str: return self._n @@ -1437,6 +1451,7 @@ class _MetricPattern11By(Generic[T]): def height(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'height') class MetricPattern11(Generic[T]): + by: _MetricPattern11By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern11By(c, n) @property def name(self) -> str: return self._n @@ -1448,6 +1463,7 @@ class _MetricPattern12By(Generic[T]): def txinindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'txinindex') class MetricPattern12(Generic[T]): + by: _MetricPattern12By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern12By(c, n) @property def name(self) -> str: return self._n @@ -1459,6 +1475,7 @@ class _MetricPattern13By(Generic[T]): def monthindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'monthindex') class MetricPattern13(Generic[T]): + by: _MetricPattern13By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern13By(c, n) @property def name(self) -> str: return self._n @@ -1470,6 +1487,7 @@ class _MetricPattern14By(Generic[T]): def opreturnindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'opreturnindex') class MetricPattern14(Generic[T]): + by: _MetricPattern14By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern14By(c, n) @property def name(self) -> str: return self._n @@ -1481,6 +1499,7 @@ class _MetricPattern15By(Generic[T]): def txoutindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'txoutindex') class MetricPattern15(Generic[T]): + by: _MetricPattern15By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern15By(c, n) @property def name(self) -> str: return self._n @@ -1492,6 +1511,7 @@ class _MetricPattern16By(Generic[T]): def p2aaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2aaddressindex') class MetricPattern16(Generic[T]): + by: _MetricPattern16By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern16By(c, n) @property def name(self) -> str: return self._n @@ -1503,6 +1523,7 @@ class _MetricPattern17By(Generic[T]): def p2msoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2msoutputindex') class MetricPattern17(Generic[T]): + by: _MetricPattern17By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern17By(c, n) @property def name(self) -> str: return self._n @@ -1514,6 +1535,7 @@ class _MetricPattern18By(Generic[T]): def p2pk33addressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2pk33addressindex') class MetricPattern18(Generic[T]): + by: _MetricPattern18By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern18By(c, n) @property def name(self) -> str: return self._n @@ -1525,6 +1547,7 @@ class _MetricPattern19By(Generic[T]): def p2pk65addressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2pk65addressindex') class MetricPattern19(Generic[T]): + by: _MetricPattern19By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern19By(c, n) @property def name(self) -> str: return self._n @@ -1536,6 +1559,7 @@ class _MetricPattern20By(Generic[T]): def p2pkhaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2pkhaddressindex') class MetricPattern20(Generic[T]): + by: _MetricPattern20By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern20By(c, n) @property def name(self) -> str: return self._n @@ -1547,6 +1571,7 @@ class _MetricPattern21By(Generic[T]): def p2shaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2shaddressindex') class MetricPattern21(Generic[T]): + by: _MetricPattern21By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern21By(c, n) @property def name(self) -> str: return self._n @@ -1558,6 +1583,7 @@ class _MetricPattern22By(Generic[T]): def p2traddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2traddressindex') class MetricPattern22(Generic[T]): + by: _MetricPattern22By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern22By(c, n) @property def name(self) -> str: return self._n @@ -1569,6 +1595,7 @@ class _MetricPattern23By(Generic[T]): def p2wpkhaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2wpkhaddressindex') class MetricPattern23(Generic[T]): + by: _MetricPattern23By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern23By(c, n) @property def name(self) -> str: return self._n @@ -1580,6 +1607,7 @@ class _MetricPattern24By(Generic[T]): def p2wshaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2wshaddressindex') class MetricPattern24(Generic[T]): + by: _MetricPattern24By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern24By(c, n) @property def name(self) -> str: return self._n @@ -1591,6 +1619,7 @@ class _MetricPattern25By(Generic[T]): def quarterindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'quarterindex') class MetricPattern25(Generic[T]): + by: _MetricPattern25By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern25By(c, n) @property def name(self) -> str: return self._n @@ -1602,6 +1631,7 @@ class _MetricPattern26By(Generic[T]): def semesterindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'semesterindex') class MetricPattern26(Generic[T]): + by: _MetricPattern26By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern26By(c, n) @property def name(self) -> str: return self._n @@ -1613,6 +1643,7 @@ class _MetricPattern27By(Generic[T]): def txindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'txindex') class MetricPattern27(Generic[T]): + by: _MetricPattern27By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern27By(c, n) @property def name(self) -> str: return self._n @@ -1624,6 +1655,7 @@ class _MetricPattern28By(Generic[T]): def unknownoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'unknownoutputindex') class MetricPattern28(Generic[T]): + by: _MetricPattern28By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern28By(c, n) @property def name(self) -> str: return self._n @@ -1635,6 +1667,7 @@ class _MetricPattern29By(Generic[T]): def weekindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'weekindex') class MetricPattern29(Generic[T]): + by: _MetricPattern29By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern29By(c, n) @property def name(self) -> str: return self._n @@ -1646,6 +1679,7 @@ class _MetricPattern30By(Generic[T]): def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex') class MetricPattern30(Generic[T]): + by: _MetricPattern30By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern30By(c, n) @property def name(self) -> str: return self._n @@ -1657,6 +1691,7 @@ class _MetricPattern31By(Generic[T]): def loadedaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'loadedaddressindex') class MetricPattern31(Generic[T]): + by: _MetricPattern31By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern31By(c, n) @property def name(self) -> str: return self._n @@ -1668,6 +1703,7 @@ class _MetricPattern32By(Generic[T]): def emptyaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'emptyaddressindex') class MetricPattern32(Generic[T]): + by: _MetricPattern32By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern32By(c, n) @property def name(self) -> str: return self._n @@ -1679,6 +1715,7 @@ class _MetricPattern33By(Generic[T]): def pairoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'pairoutputindex') class MetricPattern33(Generic[T]): + by: _MetricPattern33By[T] def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern33By(c, n) @property def name(self) -> str: return self._n @@ -1973,12 +2010,32 @@ class AaopoolPattern: self._24h_blocks_mined: MetricPattern1[StoredU32] = MetricPattern1(client, _m(acc, '24h_blocks_mined')) self._24h_dominance: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, '24h_dominance')) self.blocks_mined: BlockCountPattern[StoredU32] = BlockCountPattern(client, _m(acc, 'blocks_mined')) + self.blocks_since_block: MetricPattern1[StoredU32] = MetricPattern1(client, _m(acc, 'blocks_since_block')) self.coinbase: CoinbasePattern2 = CoinbasePattern2(client, _m(acc, 'coinbase')) self.days_since_block: MetricPattern4[StoredU16] = MetricPattern4(client, _m(acc, 'days_since_block')) self.dominance: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'dominance')) self.fee: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'fee')) self.subsidy: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'subsidy')) +class RelativePattern2: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')) + self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')) + self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')) + self.supply_in_loss_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')) + self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) + self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')) + self.unrealized_loss_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) + self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.unrealized_profit_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) + self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) + class LookbackPattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2016,6 +2073,24 @@ class PeriodLumpSumStackPattern: self._6y: _2015Pattern = _2015Pattern(client, _p('6y', acc)) self._8y: _2015Pattern = _2015Pattern(client, _p('8y', acc)) +class ClassAveragePricePattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self._2015: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2015_average_price')) + self._2016: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2016_average_price')) + self._2017: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2017_average_price')) + self._2018: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2018_average_price')) + self._2019: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2019_average_price')) + self._2020: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2020_average_price')) + self._2021: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2021_average_price')) + self._2022: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2022_average_price')) + self._2023: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2023_average_price')) + self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_average_price')) + self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_average_price')) + self._2026: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2026_average_price')) + class PeriodAveragePricePattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2034,24 +2109,6 @@ class PeriodAveragePricePattern(Generic[T]): self._6y: MetricPattern4[T] = MetricPattern4(client, _p('6y', acc)) self._8y: MetricPattern4[T] = MetricPattern4(client, _p('8y', acc)) -class ClassAveragePricePattern(Generic[T]): - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self._2015: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2015_returns')) - self._2016: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2016_returns')) - self._2017: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2017_returns')) - self._2018: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2018_returns')) - self._2019: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2019_returns')) - self._2020: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2020_returns')) - self._2021: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2021_returns')) - self._2022: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2022_returns')) - self._2023: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2023_returns')) - self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_returns')) - self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_returns')) - self._2026: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2026_returns')) - class BitcoinPattern: """Pattern struct for repeated tree structure.""" @@ -2102,22 +2159,6 @@ class RelativePattern: self.unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) self.unrealized_profit_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) -class RelativePattern2: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')) - self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')) - self.net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')) - self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')) - self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) - self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) - self.unrealized_loss_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) - self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) - self.unrealized_profit_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) - self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) - class CountPattern2(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2149,21 +2190,6 @@ class AddrCountPattern: self.p2wpkh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wpkh', acc)) self.p2wsh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wsh', acc)) -class FullnessPattern(Generic[T]): - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average')) - self.base: MetricPattern11[T] = MetricPattern11(client, acc) - self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) - self.median: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'median')) - self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) - self.pct10: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct10')) - self.pct25: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct25')) - self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) - self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) - class FeeRatePattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2179,6 +2205,21 @@ class FeeRatePattern(Generic[T]): self.pct90: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct90')) self.txindex: MetricPattern27[T] = MetricPattern27(client, acc) +class FullnessPattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average')) + self.base: MetricPattern11[T] = MetricPattern11(client, acc) + self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) + self.median: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'median')) + self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) + self.pct10: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct10')) + self.pct25: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct25')) + self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) + self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) + class _0satsPattern: """Pattern struct for repeated tree structure.""" @@ -2207,18 +2248,18 @@ class PhaseDailyCentsPattern(Generic[T]): self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) -class _10yTo12yPattern: +class PeriodCagrPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.activity: ActivityPattern2 = ActivityPattern2(client, acc) - self.cost_basis: CostBasisPattern2 = CostBasisPattern2(client, acc) - self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) - self.realized: RealizedPattern2 = RealizedPattern2(client, acc) - self.relative: RelativePattern2 = RelativePattern2(client, acc) - self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) - self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + self._10y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('10y', acc)) + self._2y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('2y', acc)) + self._3y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('3y', acc)) + self._4y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('4y', acc)) + self._5y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('5y', acc)) + self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('6y', acc)) + self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('8y', acc)) class UnrealizedPattern: """Pattern struct for repeated tree structure.""" @@ -2242,11 +2283,11 @@ class _0satsPattern2: self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) self.realized: RealizedPattern = RealizedPattern(client, acc) - self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in')) + self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply')) self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) -class _100btcPattern: +class _0Pattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -2259,19 +2300,6 @@ class _100btcPattern: self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) -class PeriodCagrPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self._10y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('10y', acc)) - self._2y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('2y', acc)) - self._3y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('3y', acc)) - self._4y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('4y', acc)) - self._5y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('5y', acc)) - self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('6y', acc)) - self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('8y', acc)) - class _10yPattern: """Pattern struct for repeated tree structure.""" @@ -2285,6 +2313,30 @@ class _10yPattern: self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) +class _10yTo12yPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.activity: ActivityPattern2 = ActivityPattern2(client, acc) + self.cost_basis: CostBasisPattern2 = CostBasisPattern2(client, acc) + self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) + self.realized: RealizedPattern2 = RealizedPattern2(client, acc) + self.relative: RelativePattern2 = RelativePattern2(client, acc) + self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) + self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + +class RelativePattern4: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.supply_in_loss_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'in_loss_rel_to_circulating_supply')) + self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'in_loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'in_profit_rel_to_circulating_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'in_profit_rel_to_own_supply')) + self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'rel_to_circulating_supply')) + class ActivityPattern2: """Pattern struct for repeated tree structure.""" @@ -2306,15 +2358,6 @@ class SplitPattern2(Generic[T]): self.low: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'low')) self.open: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'open')) -class SegwitAdoptionPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.base: MetricPattern11[StoredF32] = MetricPattern11(client, acc) - self.cumulative: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'cumulative')) - self.sum: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'sum')) - class UnclaimedRewardsPattern: """Pattern struct for repeated tree structure.""" @@ -2324,42 +2367,6 @@ class UnclaimedRewardsPattern: self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) -class ActiveSupplyPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.bitcoin: MetricPattern1[Bitcoin] = MetricPattern1(client, _m(acc, 'btc')) - self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd')) - self.sats: MetricPattern1[Sats] = MetricPattern1(client, acc) - -class CoinbasePattern2: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc')) - self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) - self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) - -class CostBasisPattern2: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) - self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) - self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis')) - -class _2015Pattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.bitcoin: MetricPattern4[Bitcoin] = MetricPattern4(client, _m(acc, 'btc')) - self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'usd')) - self.sats: MetricPattern4[Sats] = MetricPattern4(client, acc) - class CoinbasePattern: """Pattern struct for repeated tree structure.""" @@ -2369,29 +2376,50 @@ class CoinbasePattern: self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd')) self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc) -class RelativePattern4: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'loss_rel_to_own_supply')) - self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'profit_rel_to_own_supply')) - -class _1dReturns1mSdPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd')) - self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) - -class CostBasisPattern: +class CostBasisPattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) + self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis')) + +class ActiveSupplyPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.bitcoin: MetricPattern1[Bitcoin] = MetricPattern1(client, _m(acc, 'btc')) + self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd')) + self.sats: MetricPattern1[Sats] = MetricPattern1(client, acc) + +class _2015Pattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.bitcoin: MetricPattern4[Bitcoin] = MetricPattern4(client, _m(acc, 'btc')) + self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'usd')) + self.sats: MetricPattern4[Sats] = MetricPattern4(client, acc) + +class SegwitAdoptionPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.base: MetricPattern11[StoredF32] = MetricPattern11(client, acc) + self.cumulative: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'cumulative')) + self.sum: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'sum')) + +class CoinbasePattern2: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc')) + self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) + self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) class SupplyPattern2: """Pattern struct for repeated tree structure.""" @@ -2401,6 +2429,22 @@ class SupplyPattern2: self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved')) self.total: ActiveSupplyPattern = ActiveSupplyPattern(client, acc) +class CostBasisPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) + self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) + +class _1dReturns1mSdPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd')) + self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) + class SatsPattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2409,14 +2453,6 @@ class SatsPattern(Generic[T]): self.ohlc: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'ohlc_sats')) self.split: SplitPattern2[T] = SplitPattern2(client, _m(acc, 'sats')) -class BitcoinPattern2(Generic[T]): - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative')) - self.sum: MetricPattern1[T] = MetricPattern1(client, acc) - class BlockCountPattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2425,6 +2461,14 @@ class BlockCountPattern(Generic[T]): self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) self.sum: MetricPattern1[T] = MetricPattern1(client, acc) +class BitcoinPattern2(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative')) + self.sum: MetricPattern1[T] = MetricPattern1(client, acc) + class OutputsPattern: """Pattern struct for repeated tree structure.""" @@ -2842,47 +2886,47 @@ class MetricsTree_Distribution_UtxoCohorts_Epoch: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._0: _0satsPattern2 = _0satsPattern2(client, 'epoch_0') - self._1: _0satsPattern2 = _0satsPattern2(client, 'epoch_1') - self._2: _0satsPattern2 = _0satsPattern2(client, 'epoch_2') - self._3: _0satsPattern2 = _0satsPattern2(client, 'epoch_3') - self._4: _0satsPattern2 = _0satsPattern2(client, 'epoch_4') + self._0: _0Pattern = _0Pattern(client, 'epoch_0') + self._1: _0Pattern = _0Pattern(client, 'epoch_1') + self._2: _0Pattern = _0Pattern(client, 'epoch_2') + self._3: _0Pattern = _0Pattern(client, 'epoch_3') + self._4: _0Pattern = _0Pattern(client, 'epoch_4') class MetricsTree_Distribution_UtxoCohorts_GeAmount: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._100btc: _100btcPattern = _100btcPattern(client, 'utxos_above_100btc') - self._100k_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_100k_sats') - self._100sats: _100btcPattern = _100btcPattern(client, 'utxos_above_100sats') - self._10btc: _100btcPattern = _100btcPattern(client, 'utxos_above_10btc') - self._10k_btc: _100btcPattern = _100btcPattern(client, 'utxos_above_10k_btc') - self._10k_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_10k_sats') - self._10m_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_10m_sats') - self._10sats: _100btcPattern = _100btcPattern(client, 'utxos_above_10sats') - self._1btc: _100btcPattern = _100btcPattern(client, 'utxos_above_1btc') - self._1k_btc: _100btcPattern = _100btcPattern(client, 'utxos_above_1k_btc') - self._1k_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_1k_sats') - self._1m_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_1m_sats') - self._1sat: _100btcPattern = _100btcPattern(client, 'utxos_above_1sat') + self._100btc: _0Pattern = _0Pattern(client, 'utxos_above_100btc') + self._100k_sats: _0Pattern = _0Pattern(client, 'utxos_above_100k_sats') + self._100sats: _0Pattern = _0Pattern(client, 'utxos_above_100sats') + self._10btc: _0Pattern = _0Pattern(client, 'utxos_above_10btc') + self._10k_btc: _0Pattern = _0Pattern(client, 'utxos_above_10k_btc') + self._10k_sats: _0Pattern = _0Pattern(client, 'utxos_above_10k_sats') + self._10m_sats: _0Pattern = _0Pattern(client, 'utxos_above_10m_sats') + self._10sats: _0Pattern = _0Pattern(client, 'utxos_above_10sats') + self._1btc: _0Pattern = _0Pattern(client, 'utxos_above_1btc') + self._1k_btc: _0Pattern = _0Pattern(client, 'utxos_above_1k_btc') + self._1k_sats: _0Pattern = _0Pattern(client, 'utxos_above_1k_sats') + self._1m_sats: _0Pattern = _0Pattern(client, 'utxos_above_1m_sats') + self._1sat: _0Pattern = _0Pattern(client, 'utxos_above_1sat') class MetricsTree_Distribution_UtxoCohorts_LtAmount: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._100btc: _100btcPattern = _100btcPattern(client, 'utxos_under_100btc') - self._100k_btc: _100btcPattern = _100btcPattern(client, 'utxos_under_100k_btc') - self._100k_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_100k_sats') - self._100sats: _100btcPattern = _100btcPattern(client, 'utxos_under_100sats') - self._10btc: _100btcPattern = _100btcPattern(client, 'utxos_under_10btc') - self._10k_btc: _100btcPattern = _100btcPattern(client, 'utxos_under_10k_btc') - self._10k_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_10k_sats') - self._10m_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_10m_sats') - self._10sats: _100btcPattern = _100btcPattern(client, 'utxos_under_10sats') - self._1btc: _100btcPattern = _100btcPattern(client, 'utxos_under_1btc') - self._1k_btc: _100btcPattern = _100btcPattern(client, 'utxos_under_1k_btc') - self._1k_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_1k_sats') - self._1m_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_1m_sats') + self._100btc: _0Pattern = _0Pattern(client, 'utxos_under_100btc') + self._100k_btc: _0Pattern = _0Pattern(client, 'utxos_under_100k_btc') + self._100k_sats: _0Pattern = _0Pattern(client, 'utxos_under_100k_sats') + self._100sats: _0Pattern = _0Pattern(client, 'utxos_under_100sats') + self._10btc: _0Pattern = _0Pattern(client, 'utxos_under_10btc') + self._10k_btc: _0Pattern = _0Pattern(client, 'utxos_under_10k_btc') + self._10k_sats: _0Pattern = _0Pattern(client, 'utxos_under_10k_sats') + self._10m_sats: _0Pattern = _0Pattern(client, 'utxos_under_10m_sats') + self._10sats: _0Pattern = _0Pattern(client, 'utxos_under_10sats') + self._1btc: _0Pattern = _0Pattern(client, 'utxos_under_1btc') + self._1k_btc: _0Pattern = _0Pattern(client, 'utxos_under_1k_btc') + self._1k_sats: _0Pattern = _0Pattern(client, 'utxos_under_1k_sats') + self._1m_sats: _0Pattern = _0Pattern(client, 'utxos_under_1m_sats') class MetricsTree_Distribution_UtxoCohorts_MaxAge: """Metrics tree node.""" @@ -2911,24 +2955,24 @@ class MetricsTree_Distribution_UtxoCohorts_MinAge: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._10y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_10y_old') - self._12y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_12y_old') - self._1d: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1d_old') - self._1m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1m_old') - self._1w: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1w_old') - self._1y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1y_old') - self._2m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_2m_old') - self._2y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_2y_old') - self._3m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_3m_old') - self._3y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_3y_old') - self._4m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_4m_old') - self._4y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_4y_old') - self._5m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_5m_old') - self._5y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_5y_old') - self._6m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_6m_old') - self._6y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_6y_old') - self._7y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_7y_old') - self._8y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_8y_old') + self._10y: _0Pattern = _0Pattern(client, 'utxos_at_least_10y_old') + self._12y: _0Pattern = _0Pattern(client, 'utxos_at_least_12y_old') + self._1d: _0Pattern = _0Pattern(client, 'utxos_at_least_1d_old') + self._1m: _0Pattern = _0Pattern(client, 'utxos_at_least_1m_old') + self._1w: _0Pattern = _0Pattern(client, 'utxos_at_least_1w_old') + self._1y: _0Pattern = _0Pattern(client, 'utxos_at_least_1y_old') + self._2m: _0Pattern = _0Pattern(client, 'utxos_at_least_2m_old') + self._2y: _0Pattern = _0Pattern(client, 'utxos_at_least_2y_old') + self._3m: _0Pattern = _0Pattern(client, 'utxos_at_least_3m_old') + self._3y: _0Pattern = _0Pattern(client, 'utxos_at_least_3y_old') + self._4m: _0Pattern = _0Pattern(client, 'utxos_at_least_4m_old') + self._4y: _0Pattern = _0Pattern(client, 'utxos_at_least_4y_old') + self._5m: _0Pattern = _0Pattern(client, 'utxos_at_least_5m_old') + self._5y: _0Pattern = _0Pattern(client, 'utxos_at_least_5y_old') + self._6m: _0Pattern = _0Pattern(client, 'utxos_at_least_6m_old') + self._6y: _0Pattern = _0Pattern(client, 'utxos_at_least_6y_old') + self._7y: _0Pattern = _0Pattern(client, 'utxos_at_least_7y_old') + self._8y: _0Pattern = _0Pattern(client, 'utxos_at_least_8y_old') class MetricsTree_Distribution_UtxoCohorts_Term_Long: """Metrics tree node.""" @@ -2965,40 +3009,40 @@ class MetricsTree_Distribution_UtxoCohorts_Type: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.empty: _0satsPattern2 = _0satsPattern2(client, 'empty_outputs') - self.p2a: _0satsPattern2 = _0satsPattern2(client, 'p2a') - self.p2ms: _0satsPattern2 = _0satsPattern2(client, 'p2ms') - self.p2pk33: _0satsPattern2 = _0satsPattern2(client, 'p2pk33') - self.p2pk65: _0satsPattern2 = _0satsPattern2(client, 'p2pk65') - self.p2pkh: _0satsPattern2 = _0satsPattern2(client, 'p2pkh') - self.p2sh: _0satsPattern2 = _0satsPattern2(client, 'p2sh') - self.p2tr: _0satsPattern2 = _0satsPattern2(client, 'p2tr') - self.p2wpkh: _0satsPattern2 = _0satsPattern2(client, 'p2wpkh') - self.p2wsh: _0satsPattern2 = _0satsPattern2(client, 'p2wsh') - self.unknown: _0satsPattern2 = _0satsPattern2(client, 'unknown_outputs') + self.empty: _0Pattern = _0Pattern(client, 'empty_outputs') + self.p2a: _0Pattern = _0Pattern(client, 'p2a') + self.p2ms: _0Pattern = _0Pattern(client, 'p2ms') + self.p2pk33: _0Pattern = _0Pattern(client, 'p2pk33') + self.p2pk65: _0Pattern = _0Pattern(client, 'p2pk65') + self.p2pkh: _0Pattern = _0Pattern(client, 'p2pkh') + self.p2sh: _0Pattern = _0Pattern(client, 'p2sh') + self.p2tr: _0Pattern = _0Pattern(client, 'p2tr') + self.p2wpkh: _0Pattern = _0Pattern(client, 'p2wpkh') + self.p2wsh: _0Pattern = _0Pattern(client, 'p2wsh') + self.unknown: _0Pattern = _0Pattern(client, 'unknown_outputs') class MetricsTree_Distribution_UtxoCohorts_Year: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._2009: _0satsPattern2 = _0satsPattern2(client, 'year_2009') - self._2010: _0satsPattern2 = _0satsPattern2(client, 'year_2010') - self._2011: _0satsPattern2 = _0satsPattern2(client, 'year_2011') - self._2012: _0satsPattern2 = _0satsPattern2(client, 'year_2012') - self._2013: _0satsPattern2 = _0satsPattern2(client, 'year_2013') - self._2014: _0satsPattern2 = _0satsPattern2(client, 'year_2014') - self._2015: _0satsPattern2 = _0satsPattern2(client, 'year_2015') - self._2016: _0satsPattern2 = _0satsPattern2(client, 'year_2016') - self._2017: _0satsPattern2 = _0satsPattern2(client, 'year_2017') - self._2018: _0satsPattern2 = _0satsPattern2(client, 'year_2018') - self._2019: _0satsPattern2 = _0satsPattern2(client, 'year_2019') - self._2020: _0satsPattern2 = _0satsPattern2(client, 'year_2020') - self._2021: _0satsPattern2 = _0satsPattern2(client, 'year_2021') - self._2022: _0satsPattern2 = _0satsPattern2(client, 'year_2022') - self._2023: _0satsPattern2 = _0satsPattern2(client, 'year_2023') - self._2024: _0satsPattern2 = _0satsPattern2(client, 'year_2024') - self._2025: _0satsPattern2 = _0satsPattern2(client, 'year_2025') - self._2026: _0satsPattern2 = _0satsPattern2(client, 'year_2026') + self._2009: _0Pattern = _0Pattern(client, 'year_2009') + self._2010: _0Pattern = _0Pattern(client, 'year_2010') + self._2011: _0Pattern = _0Pattern(client, 'year_2011') + self._2012: _0Pattern = _0Pattern(client, 'year_2012') + self._2013: _0Pattern = _0Pattern(client, 'year_2013') + self._2014: _0Pattern = _0Pattern(client, 'year_2014') + self._2015: _0Pattern = _0Pattern(client, 'year_2015') + self._2016: _0Pattern = _0Pattern(client, 'year_2016') + self._2017: _0Pattern = _0Pattern(client, 'year_2017') + self._2018: _0Pattern = _0Pattern(client, 'year_2018') + self._2019: _0Pattern = _0Pattern(client, 'year_2019') + self._2020: _0Pattern = _0Pattern(client, 'year_2020') + self._2021: _0Pattern = _0Pattern(client, 'year_2021') + self._2022: _0Pattern = _0Pattern(client, 'year_2022') + self._2023: _0Pattern = _0Pattern(client, 'year_2023') + self._2024: _0Pattern = _0Pattern(client, 'year_2024') + self._2025: _0Pattern = _0Pattern(client, 'year_2025') + self._2026: _0Pattern = _0Pattern(client, 'year_2026') class MetricsTree_Distribution_UtxoCohorts: """Metrics tree node.""" @@ -3282,22 +3326,22 @@ class MetricsTree_Market_Ath: self.price_drawdown: MetricPattern3[StoredF32] = MetricPattern3(client, 'price_drawdown') self.years_since_price_ath: MetricPattern4[StoredF32] = MetricPattern4(client, 'years_since_price_ath') -class MetricsTree_Market_Dca_ClassAveragePrice: +class MetricsTree_Market_Dca_ClassReturns: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._2015: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2015_average_price') - self._2016: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2016_average_price') - self._2017: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2017_average_price') - self._2018: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2018_average_price') - self._2019: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2019_average_price') - self._2020: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2020_average_price') - self._2021: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2021_average_price') - self._2022: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2022_average_price') - self._2023: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2023_average_price') - self._2024: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2024_average_price') - self._2025: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2025_average_price') - self._2026: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2026_average_price') + self._2015: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2015_returns') + self._2016: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2016_returns') + self._2017: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2017_returns') + self._2018: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2018_returns') + self._2019: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2019_returns') + self._2020: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2020_returns') + self._2021: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2021_returns') + self._2022: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2022_returns') + self._2023: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2023_returns') + self._2024: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2024_returns') + self._2025: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2025_returns') + self._2026: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2026_returns') class MetricsTree_Market_Dca_ClassStack: """Metrics tree node.""" @@ -3320,8 +3364,8 @@ class MetricsTree_Market_Dca: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.class_average_price: MetricsTree_Market_Dca_ClassAveragePrice = MetricsTree_Market_Dca_ClassAveragePrice(client) - self.class_returns: ClassAveragePricePattern[StoredF32] = ClassAveragePricePattern(client, 'dca_class') + self.class_average_price: ClassAveragePricePattern[Dollars] = ClassAveragePricePattern(client, 'dca_class') + self.class_returns: MetricsTree_Market_Dca_ClassReturns = MetricsTree_Market_Dca_ClassReturns(client) self.class_stack: MetricsTree_Market_Dca_ClassStack = MetricsTree_Market_Dca_ClassStack(client) self.period_average_price: PeriodAveragePricePattern[Dollars] = PeriodAveragePricePattern(client, 'dca_average_price') self.period_cagr: PeriodCagrPattern = PeriodCagrPattern(client, 'dca_cagr') diff --git a/packages/brk_client/pyproject.toml b/packages/brk_client/pyproject.toml index 1e7c2453b..19abe4617 100644 --- a/packages/brk_client/pyproject.toml +++ b/packages/brk_client/pyproject.toml @@ -3,7 +3,7 @@ name = "brk-client" version = "0.1.0-alpha.6" description = "Python client for the Bitcoin Research Kit" readme = "README.md" -requires-python = ">=3.11" +requires-python = ">=3.9" license = "MIT" keywords = ["bitcoin", "blockchain", "analytics", "on-chain"] classifiers = [ @@ -11,6 +11,8 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", diff --git a/website/scripts/chart/colors.js b/website/scripts/chart/colors.js index 803ecd265..002ef81fe 100644 --- a/website/scripts/chart/colors.js +++ b/website/scripts/chart/colors.js @@ -67,32 +67,65 @@ function getLightDarkValue(property) { return dark ? _dark : light; } +const red = createColor(() => getColor("red")); +const orange = createColor(() => getColor("orange")); +const amber = createColor(() => getColor("amber")); +const yellow = createColor(() => getColor("yellow")); +const avocado = createColor(() => getColor("avocado")); +const lime = createColor(() => getColor("lime")); +const green = createColor(() => getColor("green")); +const emerald = createColor(() => getColor("emerald")); +const teal = createColor(() => getColor("teal")); +const cyan = createColor(() => getColor("cyan")); +const sky = createColor(() => getColor("sky")); +const blue = createColor(() => getColor("blue")); +const indigo = createColor(() => getColor("indigo")); +const violet = createColor(() => getColor("violet")); +const purple = createColor(() => getColor("purple")); +const fuchsia = createColor(() => getColor("fuchsia")); +const pink = createColor(() => getColor("pink")); +const rose = createColor(() => getColor("rose")); + export const colors = { default: createColor(() => getLightDarkValue("--color")), gray: createColor(() => getColor("gray")), border: createColor(() => getLightDarkValue("--border-color")), - red: createColor(() => getColor("red")), - orange: createColor(() => getColor("orange")), - amber: createColor(() => getColor("amber")), - yellow: createColor(() => getColor("yellow")), - avocado: createColor(() => getColor("avocado")), - lime: createColor(() => getColor("lime")), - green: createColor(() => getColor("green")), - emerald: createColor(() => getColor("emerald")), - teal: createColor(() => getColor("teal")), - cyan: createColor(() => getColor("cyan")), - sky: createColor(() => getColor("sky")), - blue: createColor(() => getColor("blue")), - indigo: createColor(() => getColor("indigo")), - violet: createColor(() => getColor("violet")), - purple: createColor(() => getColor("purple")), - fuchsia: createColor(() => getColor("fuchsia")), - pink: createColor(() => getColor("pink")), - rose: createColor(() => getColor("rose")), + red, + orange, + amber, + yellow, + avocado, + lime, + green, + emerald, + teal, + cyan, + sky, + blue, + indigo, + violet, + purple, + fuchsia, + pink, + rose, + + /** Semantic stat colors for pattern helpers */ + stat: { + sum: blue, + cumulative: indigo, + avg: orange, + max: green, + pct90: cyan, + pct75: blue, + median: yellow, + pct25: violet, + pct10: fuchsia, + min: red, + }, }; /** * @typedef {typeof colors} Colors - * @typedef {keyof Colors} ColorName + * @typedef {Exclude} ColorName */ diff --git a/website/scripts/chart/index.js b/website/scripts/chart/index.js index 1902c208c..531736a7f 100644 --- a/website/scripts/chart/index.js +++ b/website/scripts/chart/index.js @@ -219,6 +219,10 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { ? initialRange.to - initialRange.from : Infinity; + /** @param {number} count */ + const getDotsRadius = (count) => + count > 1000 ? 1 : count > 200 ? 1.5 : count > 100 ? 2 : 3; + /** @type {Set} */ const onZoomChange = new Set(); @@ -1023,11 +1027,12 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { let active = defaultActive !== false; let highlighted = true; + const showLastValue = options?.lastValueVisible !== false; function update() { iseries.applyOptions({ visible: active, - lastValueVisible: highlighted, + lastValueVisible: showLastValue && highlighted, color: color.highlight(highlighted), }); } @@ -1117,21 +1122,21 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { let active = defaultActive !== false; let highlighted = true; - let radius = - visibleBarsCount > 1000 ? 1 : visibleBarsCount > 200 ? 1.5 : 2; + let radius = getDotsRadius(visibleBarsCount); function update() { iseries.applyOptions({ visible: active, lastValueVisible: highlighted, color: color.highlight(highlighted), + pointMarkersRadius: radius, }); } update(); /** @type {ZoomChangeCallback} */ function handleZoom(count) { - const newRadius = count > 1000 ? 1 : count > 200 ? 1.5 : 2; + const newRadius = getDotsRadius(count); if (newRadius === radius) return; radius = newRadius; iseries.applyOptions({ pointMarkersRadius: radius }); @@ -1507,8 +1512,13 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { } const defaultUnit = units[0]; + const sortedUnitIds = units + .map((u) => u.id) + .sort() + .join(","); const persistedUnit = createPersistedValue({ defaultValue: /** @type {string} */ (defaultUnit.id), + storageKey: `unit-${sortedUnitIds}`, urlKey: paneIndex === 0 ? "u0" : "u1", serialize: (v) => v, deserialize: (s) => s, diff --git a/website/scripts/options/chain.js b/website/scripts/options/chain.js index d99fd35de..4497ade1e 100644 --- a/website/scripts/options/chain.js +++ b/website/scripts/options/chain.js @@ -33,6 +33,7 @@ export function createChainSection(ctx) { market, scripts, supply, + distribution, } = brk.metrics; // Build pools tree dynamically @@ -49,10 +50,10 @@ export function createChainSection(ctx) { name: "Dominance", title: `${poolName} Dominance`, bottom: [ - line({ + dots({ metric: pool._24hDominance, name: "24h", - color: colors.orange, + color: colors.pink, unit: Unit.percentage, defaultActive: false, }), @@ -88,7 +89,7 @@ export function createChainSection(ctx) { name: "Blocks mined", title: `${poolName} Blocks`, bottom: [ - line({ + dots({ metric: pool.blocksMined.sum, name: "Sum", unit: Unit.count, @@ -98,6 +99,14 @@ export function createChainSection(ctx) { name: "Cumulative", color: colors.blue, unit: Unit.count, + defaultActive: false, + }), + line({ + metric: pool._24hBlocksMined, + name: "24h Sum", + color: colors.pink, + unit: Unit.count, + defaultActive: false, }), line({ metric: pool._1wBlocksMined, @@ -142,12 +151,17 @@ export function createChainSection(ctx) { ], }, { - name: "Days since block", - title: `${poolName} Last Block`, + name: "Since last block", + title: `${poolName} Since Last Block`, bottom: [ + line({ + metric: pool.blocksSinceBlock, + name: "Blocks", + unit: Unit.count, + }), line({ metric: pool.daysSinceBlock, - name: "Since block", + name: "Days", unit: Unit.days, }), ], @@ -227,12 +241,35 @@ export function createChainSection(ctx) { title: "Transaction Count", bottom: fromDollarsPattern(transactions.count.txCount, Unit.count), }, + { + name: "Speed", + title: "Transactions Per Second", + bottom: [ + dots({ + metric: transactions.volume.txPerSec, + name: "Transactions", + unit: Unit.perSec, + }), + ], + }, { name: "Volume", title: "Transaction Volume", bottom: [ ...satsBtcUsd(transactions.volume.sentSum, "Sent"), - ...satsBtcUsd(transactions.volume.receivedSum, "Received", colors.cyan, { + ...satsBtcUsd( + transactions.volume.receivedSum, + "Received", + colors.cyan, + { + defaultActive: false, + }, + ), + line({ + metric: transactions.volume.annualizedVolume.bitcoin, + name: "annualized", + color: colors.red, + unit: Unit.btc, defaultActive: false, }), line({ @@ -242,13 +279,6 @@ export function createChainSection(ctx) { unit: Unit.sats, defaultActive: false, }), - line({ - metric: transactions.volume.annualizedVolume.bitcoin, - name: "annualized", - color: colors.red, - unit: Unit.btc, - defaultActive: false, - }), line({ metric: transactions.volume.annualizedVolume.dollars, name: "annualized", @@ -266,6 +296,11 @@ export function createChainSection(ctx) { ...fromFeeRatePattern(transactions.size.vsize, Unit.vb), ], }, + { + name: "Fee Rate", + title: "Fee Rate", + bottom: fromFeeRatePattern(transactions.fees.feeRate, Unit.feeRate), + }, { name: "Versions", title: "Transaction Versions", @@ -310,17 +345,6 @@ export function createChainSection(ctx) { }), ], }, - { - name: "Speed", - title: "Transactions Per Second", - bottom: [ - dots({ - metric: transactions.volume.txPerSec, - name: "Transactions", - unit: Unit.perSec, - }), - ], - }, ], }, @@ -356,6 +380,11 @@ export function createChainSection(ctx) { title: "Output Count", bottom: [...fromSizePattern(outputs.count.totalCount, Unit.count)], }, + { + name: "OP_RETURN", + title: "OP_RETURN Outputs", + bottom: fromFullnessPattern(scripts.count.opreturn, Unit.count), + }, { name: "Speed", title: "Outputs Per Second", @@ -387,70 +416,99 @@ export function createChainSection(ctx) { ], }, - // Coinbase + // Supply { - name: "Coinbase", - title: "Coinbase Rewards", - bottom: fromCoinbasePattern(blocks.rewards.coinbase, "Coinbase"), - }, - - // Subsidy - { - name: "Subsidy", - title: "Block Subsidy", - bottom: [ - ...fromCoinbasePattern(blocks.rewards.subsidy, "Subsidy"), - line({ - metric: blocks.rewards.subsidyDominance, - name: "Dominance", - color: colors.purple, - unit: Unit.percentage, - defaultActive: false, - }), + name: "Supply", + tree: [ + { + name: "Circulating", + title: "Circulating Supply", + bottom: fromSupplyPattern(supply.circulating, "Supply"), + }, + { + name: "Inflation", + title: "Inflation Rate", + bottom: [ + dots({ + metric: supply.inflation, + name: "Rate", + unit: Unit.percentage, + }), + ], + }, + { + name: "Unspendable", + title: "Unspendable Supply", + bottom: fromValuePattern(supply.burned.unspendable), + }, + { + name: "OP_RETURN", + title: "OP_RETURN Supply", + bottom: fromValuePattern(supply.burned.opreturn), + }, ], }, - // Fee + // Rewards { - name: "Fee", + name: "Rewards", tree: [ { - name: "Total", + name: "Coinbase", + title: "Coinbase Rewards", + bottom: fromCoinbasePattern(blocks.rewards.coinbase), + }, + { + name: "Subsidy", + title: "Block Subsidy", + bottom: [ + ...fromCoinbasePattern(blocks.rewards.subsidy), + line({ + metric: blocks.rewards.subsidyDominance, + name: "Dominance", + color: colors.purple, + unit: Unit.percentage, + defaultActive: false, + }), + ], + }, + { + name: "Fee", title: "Transaction Fees", bottom: [ - line({ - metric: transactions.fees.fee.sats.sum, - name: "Sum", - unit: Unit.sats, - }), - line({ - metric: transactions.fees.fee.sats.cumulative, - name: "Cumulative", - color: colors.blue, - unit: Unit.sats, - defaultActive: false, - }), line({ metric: transactions.fees.fee.bitcoin.sum, - name: "Sum", + name: "sum", unit: Unit.btc, }), line({ metric: transactions.fees.fee.bitcoin.cumulative, - name: "Cumulative", - color: colors.blue, + name: "cumulative", + color: colors.stat.cumulative, unit: Unit.btc, defaultActive: false, }), + line({ + metric: transactions.fees.fee.sats.sum, + name: "sum", + unit: Unit.sats, + }), + line({ + metric: transactions.fees.fee.sats.cumulative, + name: "cumulative", + color: colors.stat.cumulative, + unit: Unit.sats, + defaultActive: false, + }), line({ metric: transactions.fees.fee.dollars.sum, - name: "Sum", + name: "sum", unit: Unit.usd, }), line({ metric: transactions.fees.fee.dollars.cumulative, - name: "Cumulative", - color: colors.blue, + name: "cumulative", + color: colors.stat.cumulative, unit: Unit.usd, defaultActive: false, }), @@ -464,64 +522,98 @@ export function createChainSection(ctx) { ], }, { - name: "Rate", - title: "Fee Rate", - bottom: [ - line({ - metric: transactions.fees.feeRate.median, - name: "Median", - color: colors.purple, - unit: Unit.feeRate, - }), - line({ - metric: transactions.fees.feeRate.average, - name: "Average", - color: colors.blue, - unit: Unit.feeRate, - defaultActive: false, - }), - line({ - metric: transactions.fees.feeRate.min, - name: "Min", - color: colors.red, - unit: Unit.feeRate, - defaultActive: false, - }), - line({ - metric: transactions.fees.feeRate.max, - name: "Max", - color: colors.green, - unit: Unit.feeRate, - defaultActive: false, - }), - line({ - metric: transactions.fees.feeRate.pct10, - name: "pct10", - color: colors.rose, - unit: Unit.feeRate, - defaultActive: false, - }), - line({ - metric: transactions.fees.feeRate.pct25, - name: "pct25", - color: colors.pink, - unit: Unit.feeRate, - defaultActive: false, - }), - line({ - metric: transactions.fees.feeRate.pct75, - name: "pct75", - color: colors.violet, - unit: Unit.feeRate, - defaultActive: false, - }), - line({ - metric: transactions.fees.feeRate.pct90, - name: "pct90", - color: colors.fuchsia, - unit: Unit.feeRate, - defaultActive: false, - }), + name: "Unclaimed", + title: "Unclaimed Rewards", + bottom: fromValuePattern( + blocks.rewards.unclaimedRewards, + "Unclaimed", + ), + }, + ], + }, + + // Addresses + { + name: "Addresses", + tree: [ + { + name: "Count", + tree: [ + { + name: "All", + title: "Total Address Count", + bottom: [ + line({ + metric: distribution.addrCount.all, + name: "Loaded", + unit: Unit.count, + }), + line({ + metric: distribution.emptyAddrCount.all, + name: "Empty", + color: colors.gray, + unit: Unit.count, + defaultActive: false, + }), + ], + }, + { + name: "By Type", + title: "Address Count by Type", + bottom: [ + line({ + metric: distribution.addrCount.p2pkh, + name: "P2PKH", + color: colors.orange, + unit: Unit.count, + }), + line({ + metric: distribution.addrCount.p2sh, + name: "P2SH", + color: colors.yellow, + unit: Unit.count, + }), + line({ + metric: distribution.addrCount.p2wpkh, + name: "P2WPKH", + color: colors.green, + unit: Unit.count, + }), + line({ + metric: distribution.addrCount.p2wsh, + name: "P2WSH", + color: colors.teal, + unit: Unit.count, + }), + line({ + metric: distribution.addrCount.p2tr, + name: "P2TR", + color: colors.purple, + unit: Unit.count, + }), + line({ + metric: distribution.addrCount.p2pk65, + name: "P2PK65", + color: colors.pink, + unit: Unit.count, + defaultActive: false, + }), + line({ + metric: distribution.addrCount.p2pk33, + name: "P2PK33", + color: colors.red, + unit: Unit.count, + defaultActive: false, + }), + line({ + metric: distribution.addrCount.p2a, + name: "P2A", + color: colors.blue, + unit: Unit.count, + defaultActive: false, + }), + ], + }, ], }, ], @@ -568,6 +660,13 @@ export function createChainSection(ctx) { unit: Unit.hashRate, defaultActive: false, }), + line({ + metric: blocks.difficulty.asHash, + name: "Difficulty", + color: colors.default, + unit: Unit.hashRate, + options: { lineStyle: 1 }, + }), ], }, { @@ -579,34 +678,17 @@ export function createChainSection(ctx) { name: "Difficulty", unit: Unit.difficulty, }), - line({ - metric: blocks.difficulty.adjustment, - name: "Adjustment", - color: colors.orange, - unit: Unit.percentage, - defaultActive: false, - }), - line({ - metric: blocks.difficulty.asHash, - name: "As hash", - color: colors.default, - unit: Unit.hashRate, - defaultActive: false, - options: { lineStyle: 1 }, - }), line({ metric: blocks.difficulty.blocksBeforeNextAdjustment, - name: "Blocks until adj.", + name: "before next", color: colors.indigo, unit: Unit.blocks, - defaultActive: false, }), line({ metric: blocks.difficulty.daysBeforeNextAdjustment, - name: "Days until adj.", + name: "before next", color: colors.purple, unit: Unit.days, - defaultActive: false, }), ], }, @@ -619,6 +701,7 @@ export function createChainSection(ctx) { name: "Difficulty Change", unit: Unit.percentage, }), + priceLine({ ctx, number: 0, unit: Unit.percentage }), ], }, { @@ -701,23 +784,22 @@ export function createChainSection(ctx) { name: "Halving", title: "Halving", bottom: [ - line({ - metric: blocks.halving.blocksBeforeNextHalving, - name: "Blocks before next", - unit: Unit.blocks, - }), - line({ - metric: blocks.halving.daysBeforeNextHalving, - name: "Days before next", - color: colors.orange, - unit: Unit.days, - }), line({ metric: blocks.halving.epoch, name: "Epoch", color: colors.purple, unit: Unit.epoch, - defaultActive: false, + }), + line({ + metric: blocks.halving.blocksBeforeNextHalving, + name: "before next", + unit: Unit.blocks, + }), + line({ + metric: blocks.halving.daysBeforeNextHalving, + name: "before next", + color: colors.blue, + unit: Unit.days, }), ], }, @@ -725,10 +807,11 @@ export function createChainSection(ctx) { name: "Puell Multiple", title: "Puell Multiple", bottom: [ - line({ + baseline({ metric: market.indicators.puellMultiple, name: "Puell Multiple", unit: Unit.ratio, + base: 1, }), priceLine({ ctx, unit: Unit.ratio, number: 1 }), ], @@ -741,60 +824,6 @@ export function createChainSection(ctx) { name: "Pools", tree: poolsTree, }, - - // Unspendable - { - name: "Unspendable", - tree: [ - { - name: "Supply", - title: "Unspendable Supply", - bottom: fromValuePattern(supply.burned.unspendable, "Supply"), - }, - { - name: "OP_RETURN", - tree: [ - { - name: "Outputs", - title: "OP_RETURN Outputs", - bottom: fromFullnessPattern(scripts.count.opreturn, Unit.count), - }, - { - name: "Supply", - title: "OP_RETURN Supply", - bottom: fromValuePattern(supply.burned.opreturn, "Supply"), - }, - ], - }, - ], - }, - - // Supply - { - name: "Supply", - title: "Circulating Supply", - bottom: fromSupplyPattern(supply.circulating, "Supply"), - }, - - // Inflation - { - name: "Inflation", - title: "Inflation Rate", - bottom: [ - line({ - metric: supply.inflation, - name: "Rate", - unit: Unit.percentage, - }), - ], - }, - - // Unclaimed Rewards - { - name: "Unclaimed Rewards", - title: "Unclaimed Rewards", - bottom: fromValuePattern(blocks.rewards.unclaimedRewards, "Unclaimed"), - }, ], }; } diff --git a/website/scripts/options/cointime.js b/website/scripts/options/cointime.js index bba003613..3e93a4303 100644 --- a/website/scripts/options/cointime.js +++ b/website/scripts/options/cointime.js @@ -6,7 +6,8 @@ import { percentileUsdMap, percentileMap, sdPatterns, - sdBands, + sdBandsUsd, + sdBandsRatio, } from "./shared.js"; /** @@ -56,8 +57,8 @@ function createCointimePriceWithRatioOptions( baseline({ metric: ratio.ratio, name: "Ratio", - color, unit: Unit.ratio, + base: 1, }), line({ metric: ratio.ratio1wSma, @@ -191,7 +192,7 @@ function createCointimePriceWithRatioOptions( title: `${title} ${titleAddon} Z-Score`, top: [ line({ metric: price, name: legend, color, unit: Unit.usd }), - ...sdBands(colors, sd).map( + ...sdBandsUsd(colors, sd).map( ({ name: bandName, prop, color: bandColor }) => line({ metric: prop, @@ -203,7 +204,33 @@ function createCointimePriceWithRatioOptions( ), ], bottom: [ - line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }), + baseline({ + metric: sd.zscore, + name: "Z-Score", + unit: Unit.sd, + }), + baseline({ + metric: ratio.ratio, + name: "Ratio", + unit: Unit.ratio, + base: 1, + }), + line({ + metric: sd.sd, + name: "Volatility", + color: colors.gray, + unit: Unit.percentage, + }), + ...sdBandsRatio(colors, sd).map( + ({ name: bandName, prop, color: bandColor }) => + line({ + metric: prop, + name: bandName, + color: bandColor, + unit: Unit.ratio, + defaultActive: false, + }), + ), ...priceLines({ ctx, unit: Unit.sd, diff --git a/website/scripts/options/context.js b/website/scripts/options/context.js index 0aa33c857..9e11df3fb 100644 --- a/website/scripts/options/context.js +++ b/website/scripts/options/context.js @@ -15,35 +15,51 @@ import { } from "./series.js"; import { colors } from "../chart/colors.js"; +/** + * @template {(arg: any, ...args: any[]) => any} F + * @typedef {F extends (arg: any, ...args: infer P) => infer R ? (...args: P) => R : never} OmitFirstArg + */ + +/** @typedef {ReturnType} PartialContext */ + /** * Create a context object with all dependencies for building partial options * @param {Object} args * @param {BrkClient} args.brk - * @returns {PartialContext} */ export function createContext({ brk }) { return { colors, brk, + /** @type {OmitFirstArg} */ fromBlockCount: (pattern, title, color) => fromBlockCount(colors, pattern, title, color), + /** @type {OmitFirstArg} */ fromBitcoin: (pattern, title, color) => fromBitcoin(colors, pattern, title, color), + /** @type {OmitFirstArg} */ fromBlockSize: (pattern, title, color) => fromBlockSize(colors, pattern, title, color), + /** @type {OmitFirstArg} */ fromSizePattern: (pattern, unit, title) => fromSizePattern(colors, pattern, unit, title), + /** @type {OmitFirstArg} */ fromFullnessPattern: (pattern, unit, title) => fromFullnessPattern(colors, pattern, unit, title), + /** @type {OmitFirstArg} */ fromDollarsPattern: (pattern, unit, title) => fromDollarsPattern(colors, pattern, unit, title), + /** @type {OmitFirstArg} */ fromFeeRatePattern: (pattern, unit, title) => fromFeeRatePattern(colors, pattern, unit, title), + /** @type {OmitFirstArg} */ fromCoinbasePattern: (pattern, title) => fromCoinbasePattern(colors, pattern, title), + /** @type {OmitFirstArg} */ fromValuePattern: (pattern, title, sumColor, cumulativeColor) => fromValuePattern(colors, pattern, title, sumColor, cumulativeColor), + /** @type {OmitFirstArg} */ fromBitcoinPatternWithUnit: ( pattern, title, @@ -59,6 +75,7 @@ export function createContext({ brk }) { sumColor, cumulativeColor, ), + /** @type {OmitFirstArg} */ fromBlockCountWithUnit: (pattern, unit, title, sumColor, cumulativeColor) => fromBlockCountWithUnit( colors, @@ -68,9 +85,11 @@ export function createContext({ brk }) { sumColor, cumulativeColor, ), + /** @type {OmitFirstArg} */ fromIntervalPattern: (pattern, unit, title, color) => fromIntervalPattern(colors, pattern, unit, title, color), + /** @type {fromSupplyPattern} */ fromSupplyPattern: (pattern, title, color) => - fromSupplyPattern(colors, pattern, title, color), + fromSupplyPattern(pattern, title, color), }; } diff --git a/website/scripts/options/cohorts/address.js b/website/scripts/options/distribution/address.js similarity index 99% rename from website/scripts/options/cohorts/address.js rename to website/scripts/options/distribution/address.js index 58fab5762..29185e90a 100644 --- a/website/scripts/options/cohorts/address.js +++ b/website/scripts/options/distribution/address.js @@ -51,7 +51,7 @@ export function createAddressCohortFolder(ctx, args) { { name: "total", title: `Supply ${title}`, - bottom: createGroupedSupplyTotalSeries(ctx, list), + bottom: createGroupedSupplyTotalSeries(list), }, { name: "in profit", diff --git a/website/scripts/options/cohorts/data.js b/website/scripts/options/distribution/data.js similarity index 87% rename from website/scripts/options/cohorts/data.js rename to website/scripts/options/distribution/data.js index 5f56981c8..cabf30f46 100644 --- a/website/scripts/options/cohorts/data.js +++ b/website/scripts/options/distribution/data.js @@ -23,6 +23,12 @@ const entries = (obj) => Object.entries(obj) ); +/** @type {readonly AddressableType[]} */ +const ADDRESSABLE_TYPES = ["p2pk65", "p2pk33", "p2pkh", "p2sh", "p2wpkh", "p2wsh", "p2tr", "p2a"]; + +/** @type {(key: SpendableType) => key is AddressableType} */ +const isAddressable = (key) => ADDRESSABLE_TYPES.includes(/** @type {any} */ (key)); + /** * Build all cohort data from brk tree * @param {Colors} colors @@ -31,6 +37,7 @@ const entries = (obj) => export function buildCohortData(colors, brk) { const utxoCohorts = brk.metrics.distribution.utxoCohorts; const addressCohorts = brk.metrics.distribution.addressCohorts; + const { addrCount } = brk.metrics.distribution; const { TERM_NAMES, EPOCH_NAMES, @@ -51,6 +58,7 @@ export function buildCohortData(colors, brk) { title: "", color: colors.orange, tree: utxoCohorts.all, + addrCount: addrCount.all, }; // Term cohorts - split because short is CohortFull, long is CohortWithPercentiles @@ -200,18 +208,32 @@ export function buildCohortData(colors, brk) { }, ); - // Spendable type cohorts - CohortBasic (neither adjustedSopr nor percentiles) - /** @type {readonly CohortBasic[]} */ - const type = entries(utxoCohorts.type).map(([key, tree]) => { + // Spendable type cohorts - split by addressability + /** @type {readonly CohortAddress[]} */ + const typeAddressable = ADDRESSABLE_TYPES.map((key) => { const names = SPENDABLE_TYPE_NAMES[key]; return { name: names.short, title: names.long, color: colors[spendableTypeColors[key]], - tree, + tree: utxoCohorts.type[key], + addrCount: addrCount[key], }; }); + /** @type {readonly CohortBasic[]} */ + const typeOther = entries(utxoCohorts.type) + .filter(([key]) => !isAddressable(key)) + .map(([key, tree]) => { + const names = SPENDABLE_TYPE_NAMES[key]; + return { + name: names.short, + title: names.long, + color: colors[spendableTypeColors[key]], + tree, + }; + }); + // Year cohorts - CohortBasic (neither adjustedSopr nor percentiles) /** @type {readonly CohortBasic[]} */ const year = entries(utxoCohorts.year).map(([key, tree]) => { @@ -238,7 +260,8 @@ export function buildCohortData(colors, brk) { addressesUnderAmount, utxosAmountRanges, addressesAmountRanges, - type, + typeAddressable, + typeOther, year, }; } diff --git a/website/scripts/options/cohorts/index.js b/website/scripts/options/distribution/index.js similarity index 96% rename from website/scripts/options/cohorts/index.js rename to website/scripts/options/distribution/index.js index 8db281f3c..5681cce0f 100644 --- a/website/scripts/options/cohorts/index.js +++ b/website/scripts/options/distribution/index.js @@ -12,6 +12,7 @@ export { createCohortFolderWithAdjusted, createCohortFolderWithPercentiles, createCohortFolderBasic, + createCohortFolderAddress, } from "./utxo.js"; export { createAddressCohortFolder } from "./address.js"; diff --git a/website/scripts/options/cohorts/shared.js b/website/scripts/options/distribution/shared.js similarity index 93% rename from website/scripts/options/cohorts/shared.js rename to website/scripts/options/distribution/shared.js index 1c18d6d27..8d0b53cd7 100644 --- a/website/scripts/options/cohorts/shared.js +++ b/website/scripts/options/distribution/shared.js @@ -2,7 +2,7 @@ import { Unit } from "../../utils/units.js"; import { priceLine } from "../constants.js"; -import { line } from "../series.js"; +import { baseline, line } from "../series.js"; import { satsBtcUsd } from "../shared.js"; /** @@ -74,25 +74,22 @@ export function createSingleSupplySeries(ctx, cohort) { /** * Create supply total series for grouped cohorts - * @param {PartialContext} ctx * @param {readonly CohortObject[]} list * @returns {AnyFetchedSeriesBlueprint[]} */ -export function createGroupedSupplyTotalSeries(ctx, list) { - const { brk } = ctx; - const constant100 = brk.metrics.constants.constant100; - +export function createGroupedSupplyTotalSeries(list) { return list.flatMap(({ color, name, tree }) => [ ...satsBtcUsd(tree.supply.total, name, color), - line({ - metric: - "supplyRelToCirculatingSupply" in tree.relative - ? tree.relative.supplyRelToCirculatingSupply - : constant100, - name, - color, - unit: Unit.pctSupply, - }), + ...("supplyRelToCirculatingSupply" in tree.relative + ? [ + line({ + metric: tree.relative.supplyRelToCirculatingSupply, + name, + color, + unit: Unit.pctSupply, + }), + ] + : []), ]); } @@ -194,12 +191,12 @@ export function createRealizedPriceSeries(list) { */ export function createRealizedPriceRatioSeries(ctx, list) { return [ - ...list.map(({ color, name, tree }) => - line({ + ...list.map(({ name, tree }) => + baseline({ metric: tree.realized.realizedPriceExtra.ratio, name, - color, unit: Unit.ratio, + base: 1, }), ), priceLine({ ctx, unit: Unit.ratio, number: 1 }), diff --git a/website/scripts/options/cohorts/utxo.js b/website/scripts/options/distribution/utxo.js similarity index 73% rename from website/scripts/options/cohorts/utxo.js rename to website/scripts/options/distribution/utxo.js index d03b0d180..ce2cf9a28 100644 --- a/website/scripts/options/cohorts/utxo.js +++ b/website/scripts/options/distribution/utxo.js @@ -33,6 +33,7 @@ import { createRealizedPriceRatioSeries, createCostBasisPercentilesSeries, } from "./shared.js"; +import { createRatioChart, createZScoresFolder } from "../shared.js"; import { Unit } from "../../utils/units.js"; import { line, baseline } from "../series.js"; import { priceLine } from "../constants.js"; @@ -54,10 +55,11 @@ export function createCohortFolderAll(ctx, args) { tree: [ createSingleSupplyChart(ctx, args, title), createSingleUtxoCountChart(args, title), - createSingleRealizedSectionWithAdjusted(ctx, args, title), + createSingleAddrCountChart(ctx, args, title), + createSingleRealizedSectionFull(ctx, args, title), createSingleUnrealizedSectionAll(ctx, args, title), createSingleCostBasisSectionWithPercentiles(args, title), - ...createSingleActivitySectionWithAdjusted(ctx, args, title), + createSingleActivitySectionWithAdjusted(ctx, args, title), ], }; } @@ -75,12 +77,12 @@ export function createCohortFolderFull(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(ctx, list, title), + createGroupedSupplySection(list, title), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionWithAdjusted(ctx, list, title), createGroupedUnrealizedSectionFull(ctx, list, title), createGroupedCostBasisSectionWithPercentiles(list, title), - ...createGroupedActivitySectionWithAdjusted(list, title), + createGroupedActivitySectionWithAdjusted(list, title), ], }; } @@ -90,10 +92,10 @@ export function createCohortFolderFull(ctx, args) { tree: [ createSingleSupplyChart(ctx, args, title), createSingleUtxoCountChart(args, title), - createSingleRealizedSectionWithAdjusted(ctx, args, title), + createSingleRealizedSectionFull(ctx, args, title), createSingleUnrealizedSectionFull(ctx, args, title), createSingleCostBasisSectionWithPercentiles(args, title), - ...createSingleActivitySectionWithAdjusted(ctx, args, title), + createSingleActivitySectionWithAdjusted(ctx, args, title), ], }; } @@ -111,12 +113,12 @@ export function createCohortFolderWithAdjusted(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(ctx, list, title), + createGroupedSupplySection(list, title), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionWithAdjusted(ctx, list, title), createGroupedUnrealizedSectionWithMarketCap(ctx, list, title), createGroupedCostBasisSection(list, title), - ...createGroupedActivitySectionWithAdjusted(list, title), + createGroupedActivitySectionWithAdjusted(list, title), ], }; } @@ -129,7 +131,7 @@ export function createCohortFolderWithAdjusted(ctx, args) { createSingleRealizedSectionWithAdjusted(ctx, args, title), createSingleUnrealizedSectionWithMarketCap(ctx, args, title), createSingleCostBasisSection(args, title), - ...createSingleActivitySectionWithAdjusted(ctx, args, title), + createSingleActivitySectionWithAdjusted(ctx, args, title), ], }; } @@ -147,12 +149,12 @@ export function createCohortFolderWithPercentiles(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(ctx, list, title), + createGroupedSupplySection(list, title), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionBasic(ctx, list, title), createGroupedUnrealizedSectionWithOwnCaps(ctx, list, title), createGroupedCostBasisSectionWithPercentiles(list, title), - ...createGroupedActivitySectionBasic(list, title), + createGroupedActivitySectionBasic(list, title), ], }; } @@ -162,10 +164,10 @@ export function createCohortFolderWithPercentiles(ctx, args) { tree: [ createSingleSupplyChart(ctx, args, title), createSingleUtxoCountChart(args, title), - createSingleRealizedSectionBasic(ctx, args, title), + createSingleRealizedSectionWithPercentiles(ctx, args, title), createSingleUnrealizedSectionWithOwnCaps(ctx, args, title), createSingleCostBasisSectionWithPercentiles(args, title), - ...createSingleActivitySectionBasic(ctx, args, title), + createSingleActivitySectionBasic(ctx, args, title), ], }; } @@ -183,12 +185,12 @@ export function createCohortFolderBasic(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(ctx, list, title), + createGroupedSupplySection(list, title), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionBasic(ctx, list, title), createGroupedUnrealizedSectionBase(ctx, list, title), createGroupedCostBasisSection(list, title), - ...createGroupedActivitySectionBasic(list, title), + createGroupedActivitySectionBasic(list, title), ], }; } @@ -201,7 +203,52 @@ export function createCohortFolderBasic(ctx, args) { createSingleRealizedSectionBasic(ctx, args, title), createSingleUnrealizedSectionBase(ctx, args, title), createSingleCostBasisSection(args, title), - ...createSingleActivitySectionBasic(ctx, args, title), + createSingleActivitySectionBasic(ctx, args, title), + ], + }; +} + +/** + * @typedef {Object} CohortGroupAddress + * @property {string} name + * @property {string} title + * @property {readonly CohortAddress[]} list + */ + +/** + * Address folder: like basic but with address count (addressable type cohorts) + * @param {PartialContext} ctx + * @param {CohortAddress | CohortGroupAddress} args + * @returns {PartialOptionsGroup} + */ +export function createCohortFolderAddress(ctx, args) { + if ("list" in args) { + const { list } = args; + const title = args.title ? `by ${args.title}` : ""; + return { + name: args.name || "all", + tree: [ + createGroupedSupplySection(list, title), + createGroupedUtxoCountChart(list, title), + createGroupedAddrCountChart(ctx, list, title), + createGroupedRealizedSectionBasic(ctx, list, title), + createGroupedUnrealizedSectionBase(ctx, list, title), + createGroupedCostBasisSection(list, title), + createGroupedActivitySectionBasic(list, title), + ], + }; + } + const title = args.title ? `of ${args.title}` : ""; + return { + name: args.name || "all", + tree: [ + createSingleSupplyChart(ctx, args, title), + createSingleUtxoCountChart(args, title), + createSingleAddrCountChart(ctx, args, title), + createSingleRealizedSectionBasic(ctx, args, title), + createSingleUnrealizedSectionBase(ctx, args, title), + createSingleCostBasisSection(args, title), + createSingleActivitySectionBasic(ctx, args, title), ], }; } @@ -223,19 +270,18 @@ function createSingleSupplyChart(ctx, cohort, title) { /** * Create supply section for grouped cohorts - * @param {PartialContext} ctx * @param {readonly UtxoCohortObject[]} list * @param {string} title * @returns {PartialOptionsGroup} */ -function createGroupedSupplySection(ctx, list, title) { +function createGroupedSupplySection(list, title) { return { name: "supply", tree: [ { name: "total", title: `Supply ${title}`, - bottom: createGroupedSupplyTotalSeries(ctx, list), + bottom: createGroupedSupplyTotalSeries(list), }, { name: "in profit", @@ -280,9 +326,71 @@ function createGroupedUtxoCountChart(list, title) { } /** - * Create realized section with adjusted SOPR (for cohorts with RealizedPattern3/4) + * Create address count chart for single cohort with addrCount * @param {PartialContext} ctx - * @param {CohortAll | CohortFull | CohortWithAdjusted} cohort + * @param {CohortAll | CohortAddress} cohort + * @param {string} title + * @returns {PartialChartOption} + */ +function createSingleAddrCountChart(ctx, cohort, title) { + return { + name: "address count", + title: `Address Count ${title}`, + bottom: [ + line({ + metric: cohort.addrCount, + name: "Count", + color: ctx.colors.orange, + unit: Unit.count, + }), + ], + }; +} + +/** + * Create address count chart for grouped cohorts with addrCount + * @param {PartialContext} _ctx + * @param {readonly CohortAddress[]} list + * @param {string} title + * @returns {PartialChartOption} + */ +function createGroupedAddrCountChart(_ctx, list, title) { + return { + name: "address count", + title: `Address Count ${title}`, + bottom: list.map(({ color, name, addrCount }) => + line({ metric: addrCount, name, color, unit: Unit.count }), + ), + }; +} + +/** + * Create realized section for CohortAll/CohortFull (adjustedSopr + full ratio) + * @param {PartialContext} ctx + * @param {CohortAll | CohortFull} cohort + * @param {string} title + * @returns {PartialOptionsGroup} + */ +function createSingleRealizedSectionFull(ctx, cohort, title) { + return { + name: "Realized", + tree: [ + ...createSingleRealizedPriceChartsWithRatio(ctx, cohort, title), + { + name: "capitalization", + title: `Realized Cap ${title}`, + bottom: createSingleRealizedCapSeries(ctx, cohort), + }, + ...createSingleRealizedPnlSection(ctx, cohort, title), + createSingleSoprSectionWithAdjusted(ctx, cohort, title), + ], + }; +} + +/** + * Create realized section for CohortWithAdjusted (adjustedSopr but partial ratio) + * @param {PartialContext} ctx + * @param {CohortWithAdjusted} cohort * @param {string} title * @returns {PartialOptionsGroup} */ @@ -290,7 +398,7 @@ function createSingleRealizedSectionWithAdjusted(ctx, cohort, title) { return { name: "Realized", tree: [ - createSingleRealizedPriceChart(cohort, title), + ...createSingleRealizedPriceChartsBasic(ctx, cohort, title), { name: "capitalization", title: `Realized Cap ${title}`, @@ -335,9 +443,32 @@ function createGroupedRealizedSectionWithAdjusted(ctx, list, title) { } /** - * Create realized section without adjusted SOPR (for cohorts with RealizedPattern/2) + * Create realized section for CohortWithPercentiles (no adjustedSopr but full ratio) * @param {PartialContext} ctx - * @param {CohortWithPercentiles | CohortBasic} cohort + * @param {CohortWithPercentiles} cohort + * @param {string} title + * @returns {PartialOptionsGroup} + */ +function createSingleRealizedSectionWithPercentiles(ctx, cohort, title) { + return { + name: "Realized", + tree: [ + ...createSingleRealizedPriceChartsWithRatio(ctx, cohort, title), + { + name: "capitalization", + title: `Realized Cap ${title}`, + bottom: createSingleRealizedCapSeries(ctx, cohort), + }, + ...createSingleRealizedPnlSection(ctx, cohort, title), + createSingleSoprSectionBasic(ctx, cohort, title), + ], + }; +} + +/** + * Create realized section for CohortBasic (no adjustedSopr, partial ratio) + * @param {PartialContext} ctx + * @param {CohortBasic} cohort * @param {string} title * @returns {PartialOptionsGroup} */ @@ -345,7 +476,7 @@ function createSingleRealizedSectionBasic(ctx, cohort, title) { return { name: "Realized", tree: [ - createSingleRealizedPriceChart(cohort, title), + ...createSingleRealizedPriceChartsBasic(ctx, cohort, title), { name: "capitalization", title: `Realized Cap ${title}`, @@ -397,7 +528,6 @@ function createGroupedRealizedSectionBasic(ctx, list, title) { */ function createSingleRealizedPriceChart(cohort, title) { const { tree, color } = cohort; - return { name: "price", title: `Realized Price ${title}`, @@ -412,6 +542,65 @@ function createSingleRealizedPriceChart(cohort, title) { }; } +/** + * Create realized price and ratio charts for cohorts with full ActivePriceRatioPattern + * (CohortAll, CohortFull, CohortWithPercentiles have RealizedPattern2/3 which has ActivePriceRatioPattern) + * @param {PartialContext} ctx + * @param {CohortAll | CohortFull | CohortWithPercentiles} cohort + * @param {string} title + * @returns {PartialOptionsTree} + */ +function createSingleRealizedPriceChartsWithRatio(ctx, cohort, title) { + const { tree, color } = cohort; + const ratio = /** @type {ActivePriceRatioPattern} */ ( + tree.realized.realizedPriceExtra + ); + return [ + createSingleRealizedPriceChart(cohort, title), + createRatioChart(ctx, { + title: `Realized Price ${title}`, + price: tree.realized.realizedPrice, + ratio, + color, + }), + createZScoresFolder(ctx, { + title: `Realized Price ${title}`, + legend: "price", + price: tree.realized.realizedPrice, + ratio, + color, + }), + ]; +} + +/** + * Create realized price and basic ratio charts for cohorts with RealizedPriceExtraPattern + * (CohortWithAdjusted, CohortBasic have RealizedPattern/4 which has RealizedPriceExtraPattern) + * @param {PartialContext} ctx + * @param {CohortWithAdjusted | CohortBasic} cohort + * @param {string} title + * @returns {PartialChartOption[]} + */ +function createSingleRealizedPriceChartsBasic(ctx, cohort, title) { + const { tree, color } = cohort; + return [ + createSingleRealizedPriceChart(cohort, title), + { + name: "ratio", + title: `Realized Price Ratio ${title}`, + bottom: [ + baseline({ + metric: tree.realized.realizedPriceExtra.ratio, + name: "Ratio", + color, + unit: Unit.ratio, + }), + priceLine({ ctx, unit: Unit.ratio, number: 1 }), + ], + }, + ]; +} + /** * Create realized cap series for single cohort * @param {PartialContext} ctx @@ -419,7 +608,6 @@ function createSingleRealizedPriceChart(cohort, title) { * @returns {AnyFetchedSeriesBlueprint[]} */ function createSingleRealizedCapSeries(ctx, cohort) { - const { colors } = ctx; const { color, tree } = cohort; return [ @@ -443,7 +631,6 @@ function createSingleRealizedCapSeries(ctx, cohort) { name: "ratio", unit: Unit.pctOwnMcap, options: { baseValue: { price: 100 } }, - color: [colors.red, colors.green], }), priceLine({ ctx, @@ -1764,113 +1951,105 @@ function createGroupedCostBasisSection(list, title) { * @param {PartialContext} ctx * @param {CohortAll | CohortFull | CohortWithAdjusted} cohort * @param {string} title - * @returns {PartialOptionsTree} + * @returns {PartialOptionsGroup} */ function createSingleActivitySectionWithAdjusted(ctx, cohort, title) { const { colors } = ctx; const { tree, color } = cohort; - return [ - { - name: "Sell Side Risk", - title: `Sell Side Risk Ratio ${title}`, - bottom: [ - line({ - metric: tree.realized.sellSideRiskRatio, - name: "Raw", - color: colors.orange, - unit: Unit.ratio, - }), - line({ - metric: tree.realized.sellSideRiskRatio7dEma, - name: "7d EMA", - color: colors.red, - unit: Unit.ratio, - defaultActive: false, - }), - line({ - metric: tree.realized.sellSideRiskRatio30dEma, - name: "30d EMA", - color: colors.rose, - unit: Unit.ratio, - defaultActive: false, - }), - ], - }, - { - name: "value", - tree: [ - { - name: "created", - title: `Value Created ${title}`, - bottom: [ - line({ - metric: tree.realized.valueCreated, - name: "Normal", - color: colors.emerald, - unit: Unit.usd, - }), - line({ - metric: tree.realized.adjustedValueCreated, - name: "Adjusted", - color: colors.lime, - unit: Unit.usd, - }), - ], - }, - { - name: "destroyed", - title: `Value Destroyed ${title}`, - bottom: [ - line({ - metric: tree.realized.valueDestroyed, - name: "Normal", - color: colors.red, - unit: Unit.usd, - }), - line({ - metric: tree.realized.adjustedValueDestroyed, - name: "Adjusted", - color: colors.pink, - unit: Unit.usd, - }), - ], - }, - ], - }, - { - name: "Coins Destroyed", - title: `Coins Destroyed ${title}`, - bottom: [ - line({ - metric: tree.activity.coinblocksDestroyed.sum, - name: "Coinblocks", - color, - unit: Unit.coinblocks, - }), - line({ - metric: tree.activity.coinblocksDestroyed.cumulative, - name: "Cumulative", - color, - unit: Unit.coinblocks, - defaultActive: false, - }), - line({ - metric: tree.activity.coindaysDestroyed.sum, - name: "Coindays", - color, - unit: Unit.coindays, - }), - line({ - metric: tree.activity.coindaysDestroyed.cumulative, - name: "Cumulative", - color, - unit: Unit.coindays, - defaultActive: false, - }), - ], - }, - ]; + return { + name: "Activity", + tree: [ + { + name: "Sell Side Risk", + title: `Sell Side Risk Ratio ${title}`, + bottom: [ + line({ + metric: tree.realized.sellSideRiskRatio, + name: "Raw", + color: colors.orange, + unit: Unit.ratio, + }), + line({ + metric: tree.realized.sellSideRiskRatio7dEma, + name: "7d EMA", + color: colors.red, + unit: Unit.ratio, + defaultActive: false, + }), + line({ + metric: tree.realized.sellSideRiskRatio30dEma, + name: "30d EMA", + color: colors.rose, + unit: Unit.ratio, + defaultActive: false, + }), + ], + }, + { + name: "value", + title: `Value Created & Destroyed ${title}`, + bottom: [ + line({ + metric: tree.realized.valueCreated, + name: "Created", + color: colors.emerald, + unit: Unit.usd, + }), + line({ + metric: tree.realized.adjustedValueCreated, + name: "Adjusted Created", + color: colors.lime, + unit: Unit.usd, + }), + line({ + metric: tree.realized.valueDestroyed, + name: "Destroyed", + color: colors.red, + unit: Unit.usd, + }), + line({ + metric: tree.realized.adjustedValueDestroyed, + name: "Adjusted Destroyed", + color: colors.pink, + unit: Unit.usd, + }), + ], + }, + { + name: "Coins Destroyed", + title: `Coins Destroyed ${title}`, + bottom: [ + line({ + metric: tree.activity.coinblocksDestroyed.sum, + name: "Coinblocks", + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coinblocksDestroyed.cumulative, + name: "Cumulative", + color, + unit: Unit.coinblocks, + defaultActive: false, + }), + line({ + metric: tree.activity.coindaysDestroyed.sum, + name: "Coindays", + color, + unit: Unit.coindays, + }), + line({ + metric: tree.activity.coindaysDestroyed.cumulative, + name: "Cumulative", + color, + unit: Unit.coindays, + defaultActive: false, + }), + ], + }, + ], + }; } /** @@ -1878,319 +2057,317 @@ function createSingleActivitySectionWithAdjusted(ctx, cohort, title) { * @param {PartialContext} ctx * @param {CohortWithPercentiles | CohortBasic} cohort * @param {string} title - * @returns {PartialOptionsTree} + * @returns {PartialOptionsGroup} */ function createSingleActivitySectionBasic(ctx, cohort, title) { const { colors } = ctx; const { tree, color } = cohort; - return [ - { - name: "Sell Side Risk", - title: `Sell Side Risk Ratio ${title}`, - bottom: [ - line({ - metric: tree.realized.sellSideRiskRatio, - name: "Raw", - color: colors.orange, - unit: Unit.ratio, - }), - line({ - metric: tree.realized.sellSideRiskRatio7dEma, - name: "7d EMA", - color: colors.red, - unit: Unit.ratio, - defaultActive: false, - }), - line({ - metric: tree.realized.sellSideRiskRatio30dEma, - name: "30d EMA", - color: colors.rose, - unit: Unit.ratio, - defaultActive: false, - }), - ], - }, - { - name: "value", - tree: [ - { - name: "created", - title: `Value Created ${title}`, - bottom: [ - line({ - metric: tree.realized.valueCreated, - name: "Value Created", - color: colors.emerald, - unit: Unit.usd, - }), - ], - }, - { - name: "destroyed", - title: `Value Destroyed ${title}`, - bottom: [ - line({ - metric: tree.realized.valueDestroyed, - name: "Value Destroyed", - color: colors.red, - unit: Unit.usd, - }), - ], - }, - ], - }, - { - name: "Coins Destroyed", - title: `Coins Destroyed ${title}`, - bottom: [ - line({ - metric: tree.activity.coinblocksDestroyed.sum, - name: "Coinblocks", - color, - unit: Unit.coinblocks, - }), - line({ - metric: tree.activity.coinblocksDestroyed.cumulative, - name: "Cumulative", - color, - unit: Unit.coinblocks, - defaultActive: false, - }), - line({ - metric: tree.activity.coindaysDestroyed.sum, - name: "Coindays", - color, - unit: Unit.coindays, - }), - line({ - metric: tree.activity.coindaysDestroyed.cumulative, - name: "Cumulative", - color, - unit: Unit.coindays, - defaultActive: false, - }), - ], - }, - ]; + return { + name: "Activity", + tree: [ + { + name: "Sell Side Risk", + title: `Sell Side Risk Ratio ${title}`, + bottom: [ + line({ + metric: tree.realized.sellSideRiskRatio, + name: "Raw", + color: colors.orange, + unit: Unit.ratio, + }), + line({ + metric: tree.realized.sellSideRiskRatio7dEma, + name: "7d EMA", + color: colors.red, + unit: Unit.ratio, + defaultActive: false, + }), + line({ + metric: tree.realized.sellSideRiskRatio30dEma, + name: "30d EMA", + color: colors.rose, + unit: Unit.ratio, + defaultActive: false, + }), + ], + }, + { + name: "value", + title: `Value Created & Destroyed ${title}`, + bottom: [ + line({ + metric: tree.realized.valueCreated, + name: "Created", + color: colors.emerald, + unit: Unit.usd, + }), + line({ + metric: tree.realized.valueDestroyed, + name: "Destroyed", + color: colors.red, + unit: Unit.usd, + }), + ], + }, + { + name: "Coins Destroyed", + title: `Coins Destroyed ${title}`, + bottom: [ + line({ + metric: tree.activity.coinblocksDestroyed.sum, + name: "Coinblocks", + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coinblocksDestroyed.cumulative, + name: "Cumulative", + color, + unit: Unit.coinblocks, + defaultActive: false, + }), + line({ + metric: tree.activity.coindaysDestroyed.sum, + name: "Coindays", + color, + unit: Unit.coindays, + }), + line({ + metric: tree.activity.coindaysDestroyed.cumulative, + name: "Cumulative", + color, + unit: Unit.coindays, + defaultActive: false, + }), + ], + }, + ], + }; } /** * Create activity section for grouped cohorts with adjusted values (for cohorts with RealizedPattern3/4) * @param {readonly (CohortFull | CohortWithAdjusted)[]} list * @param {string} title - * @returns {PartialOptionsTree} + * @returns {PartialOptionsGroup} */ function createGroupedActivitySectionWithAdjusted(list, title) { - return [ - { - name: "Sell Side Risk", - title: `Sell Side Risk Ratio ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.sellSideRiskRatio, - name, - color, - unit: Unit.ratio, - }), - ]), - }, - { - name: "value", - tree: [ - { - name: "created", - tree: [ - { - name: "Normal", - title: `Value Created ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.valueCreated, - name, - color, - unit: Unit.usd, - }), - ]), - }, - { - name: "Adjusted", - title: `Adjusted Value Created ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.adjustedValueCreated, - name, - color, - unit: Unit.usd, - }), - ]), - }, - ], - }, - { - name: "destroyed", - tree: [ - { - name: "Normal", - title: `Value Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.valueDestroyed, - name, - color, - unit: Unit.usd, - }), - ]), - }, - { - name: "Adjusted", - title: `Adjusted Value Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.adjustedValueDestroyed, - name, - color, - unit: Unit.usd, - }), - ]), - }, - ], - }, - ], - }, - { - name: "Coins Destroyed", - tree: [ - { - name: "Sum", - title: `Coins Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.coinblocksDestroyed.sum, - name, - color, - unit: Unit.coinblocks, - }), - line({ - metric: tree.activity.coindaysDestroyed.sum, - name, - color, - unit: Unit.coindays, - }), - ]), - }, - { - name: "Cumulative", - title: `Cumulative Coins Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.coinblocksDestroyed.cumulative, - name, - color, - unit: Unit.coinblocks, - }), - line({ - metric: tree.activity.coindaysDestroyed.cumulative, - name, - color, - unit: Unit.coindays, - }), - ]), - }, - ], - }, - ]; + return { + name: "Activity", + tree: [ + { + name: "Sell Side Risk", + title: `Sell Side Risk Ratio ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.sellSideRiskRatio, + name, + color, + unit: Unit.ratio, + }), + ]), + }, + { + name: "value", + tree: [ + { + name: "created", + tree: [ + { + name: "Normal", + title: `Value Created ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.valueCreated, + name, + color, + unit: Unit.usd, + }), + ]), + }, + { + name: "Adjusted", + title: `Adjusted Value Created ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.adjustedValueCreated, + name, + color, + unit: Unit.usd, + }), + ]), + }, + ], + }, + { + name: "destroyed", + tree: [ + { + name: "Normal", + title: `Value Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.valueDestroyed, + name, + color, + unit: Unit.usd, + }), + ]), + }, + { + name: "Adjusted", + title: `Adjusted Value Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.adjustedValueDestroyed, + name, + color, + unit: Unit.usd, + }), + ]), + }, + ], + }, + ], + }, + { + name: "Coins Destroyed", + tree: [ + { + name: "Sum", + title: `Coins Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.activity.coinblocksDestroyed.sum, + name, + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coindaysDestroyed.sum, + name, + color, + unit: Unit.coindays, + }), + ]), + }, + { + name: "Cumulative", + title: `Cumulative Coins Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.activity.coinblocksDestroyed.cumulative, + name, + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coindaysDestroyed.cumulative, + name, + color, + unit: Unit.coindays, + }), + ]), + }, + ], + }, + ], + }; } /** * Create activity section for grouped cohorts without adjusted values (for cohorts with RealizedPattern/2) * @param {readonly (CohortWithPercentiles | CohortBasic)[]} list * @param {string} title - * @returns {PartialOptionsTree} + * @returns {PartialOptionsGroup} */ function createGroupedActivitySectionBasic(list, title) { - return [ - { - name: "Sell Side Risk", - title: `Sell Side Risk Ratio ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.sellSideRiskRatio, - name, - color, - unit: Unit.ratio, - }), - ]), - }, - { - name: "value", - tree: [ - { - name: "created", - title: `Value Created ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.valueCreated, - name, - color, - unit: Unit.usd, - }), - ]), - }, - { - name: "destroyed", - title: `Value Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.realized.valueDestroyed, - name, - color, - unit: Unit.usd, - }), - ]), - }, - ], - }, - { - name: "Coins Destroyed", - tree: [ - { - name: "Sum", - title: `Coins Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.coinblocksDestroyed.sum, - name, - color, - unit: Unit.coinblocks, - }), - line({ - metric: tree.activity.coindaysDestroyed.sum, - name, - color, - unit: Unit.coindays, - }), - ]), - }, - { - name: "Cumulative", - title: `Cumulative Coins Destroyed ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.coinblocksDestroyed.cumulative, - name, - color, - unit: Unit.coinblocks, - }), - line({ - metric: tree.activity.coindaysDestroyed.cumulative, - name, - color, - unit: Unit.coindays, - }), - ]), - }, - ], - }, - ]; + return { + name: "Activity", + tree: [ + { + name: "Sell Side Risk", + title: `Sell Side Risk Ratio ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.sellSideRiskRatio, + name, + color, + unit: Unit.ratio, + }), + ]), + }, + { + name: "value", + tree: [ + { + name: "created", + title: `Value Created ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.valueCreated, + name, + color, + unit: Unit.usd, + }), + ]), + }, + { + name: "destroyed", + title: `Value Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.valueDestroyed, + name, + color, + unit: Unit.usd, + }), + ]), + }, + ], + }, + { + name: "Coins Destroyed", + tree: [ + { + name: "Sum", + title: `Coins Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.activity.coinblocksDestroyed.sum, + name, + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coindaysDestroyed.sum, + name, + color, + unit: Unit.coindays, + }), + ]), + }, + { + name: "Cumulative", + title: `Cumulative Coins Destroyed ${title}`, + bottom: list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.activity.coinblocksDestroyed.cumulative, + name, + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coindaysDestroyed.cumulative, + name, + color, + unit: Unit.coindays, + }), + ]), + }, + ], + }, + ], + }; } diff --git a/website/scripts/options/market/averages.js b/website/scripts/options/market/averages.js index 28d56870f..4b8eece33 100644 --- a/website/scripts/options/market/averages.js +++ b/website/scripts/options/market/averages.js @@ -7,7 +7,8 @@ import { percentileUsdMap, percentileMap, sdPatterns, - sdBands, + sdBandsUsd, + sdBandsRatio, } from "../shared.js"; import { periodIdToName } from "./utils.js"; @@ -90,7 +91,6 @@ export function createPriceWithRatioOptions( metric: ratio.ratio, name: "Ratio", base: 1, - color, unit: Unit.ratio, }), .../** @type {const} */ ([ @@ -222,7 +222,7 @@ export function createPriceWithRatioOptions( title: `${title} ${titleAddon} Z-Score`, top: [ line({ metric: priceMetric, name: legend, color, unit: Unit.usd }), - ...sdBands(colors, sd).map( + ...sdBandsUsd(colors, sd).map( ({ name: bandName, prop, color: bandColor }) => line({ metric: prop, @@ -237,9 +237,31 @@ export function createPriceWithRatioOptions( baseline({ metric: sd.zscore, name: "Z-Score", - color, unit: Unit.sd, }), + baseline({ + metric: ratio.ratio, + name: "Ratio", + unit: Unit.ratio, + base: 1, + }), + line({ + metric: sd.sd, + name: "Volatility", + color: colors.gray, + unit: Unit.percentage, + }), + ...sdBandsRatio(colors, sd).map( + ({ name: bandName, prop, color: bandColor }) => + line({ + metric: prop, + name: bandName, + color: bandColor, + unit: Unit.ratio, + defaultActive: false, + }), + ), + priceLine({ ctx, unit: Unit.ratio, number: 1 }), priceLine({ ctx, unit: Unit.sd, diff --git a/website/scripts/options/partial.js b/website/scripts/options/partial.js index 626d40853..310598dfa 100644 --- a/website/scripts/options/partial.js +++ b/website/scripts/options/partial.js @@ -8,8 +8,9 @@ import { createCohortFolderWithAdjusted, createCohortFolderWithPercentiles, createCohortFolderBasic, + createCohortFolderAddress, createAddressCohortFolder, -} from "./cohorts/index.js"; +} from "./distribution/index.js"; import { createMarketSection } from "./market/index.js"; import { createChainSection } from "./chain.js"; import { createCointimeSection } from "./cointime.js"; @@ -17,6 +18,7 @@ import { colors } from "../chart/colors.js"; // Re-export types for external consumers export * from "./types.js"; +export * from "./context.js"; /** * Create partial options tree @@ -43,17 +45,22 @@ export function createPartialOptions({ brk }) { addressesUnderAmount, utxosAmountRanges, addressesAmountRanges, - type, + typeAddressable, + typeOther, year, } = buildCohortData(colors, brk); // Helpers to map cohorts by capability type /** @param {CohortWithAdjusted} cohort */ - const mapWithAdjusted = (cohort) => createCohortFolderWithAdjusted(ctx, cohort); + const mapWithAdjusted = (cohort) => + createCohortFolderWithAdjusted(ctx, cohort); /** @param {CohortWithPercentiles} cohort */ - const mapWithPercentiles = (cohort) => createCohortFolderWithPercentiles(ctx, cohort); + const mapWithPercentiles = (cohort) => + createCohortFolderWithPercentiles(ctx, cohort); /** @param {CohortBasic} cohort */ const mapBasic = (cohort) => createCohortFolderBasic(ctx, cohort); + /** @param {CohortAddress} cohort */ + const mapAddress = (cohort) => createCohortFolderAddress(ctx, cohort); /** @param {AddressCohortObject} cohort */ const mapAddressCohorts = (cohort) => createAddressCohortFolder(ctx, cohort); @@ -81,7 +88,7 @@ export function createPartialOptions({ brk }) { // Cohorts section { - name: "Cohorts", + name: "Distribution", tree: [ // All UTXOs - CohortAll (adjustedSopr + percentiles but no RelToMarketCap) createCohortFolderAll(ctx, cohortAll), @@ -90,22 +97,29 @@ export function createPartialOptions({ brk }) { { name: "Terms", tree: [ + // Compare folder uses WithPercentiles (common capabilities) + createCohortFolderWithPercentiles(ctx, { + name: "Compare", + title: "Term", + list: [termShort, termLong], + }), // Individual cohorts with their specific capabilities createCohortFolderFull(ctx, termShort), createCohortFolderWithPercentiles(ctx, termLong), ], }, - // Types - CohortBasic + // Types - addressable types have addrCount, others don't { name: "Types", tree: [ - createCohortFolderBasic(ctx, { + createCohortFolderAddress(ctx, { name: "Compare", title: "Type", - list: type, + list: typeAddressable, }), - ...type.map(mapBasic), + ...typeAddressable.map(mapAddress), + ...typeOther.map(mapBasic), ], }, diff --git a/website/scripts/options/series.js b/website/scripts/options/series.js index dfda0e068..2390ffa01 100644 --- a/website/scripts/options/series.js +++ b/website/scripts/options/series.js @@ -193,8 +193,8 @@ export function fromBlockCount(colors, pattern, title, color) { { metric: pattern.sum, title, color: color ?? colors.default }, { metric: pattern.cumulative, - title: `${title} (cum.)`, - color: colors.cyan, + title: `${title} cumulative`, + color: colors.stat.cumulative, defaultActive: false, }, ]; @@ -209,49 +209,55 @@ export function fromBlockCount(colors, pattern, title, color) { * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromBitcoin(colors, pattern, title, color) { + const { stat } = colors; return [ { metric: pattern.base, title, color: color ?? colors.default }, - { metric: pattern.average, title: "Average", defaultActive: false }, + { + metric: pattern.average, + title: `${title} avg`, + color: stat.avg, + defaultActive: false, + }, { metric: pattern.max, - title: "Max", - color: colors.pink, + title: `${title} max`, + color: stat.max, defaultActive: false, }, { metric: pattern.min, - title: "Min", - color: colors.green, + title: `${title} min`, + color: stat.min, defaultActive: false, }, { metric: pattern.median, - title: "Median", - color: colors.amber, + title: `${title} median`, + color: stat.median, defaultActive: false, }, { metric: pattern.pct75, - title: "pct75", - color: colors.red, + title: `${title} pct75`, + color: stat.pct75, defaultActive: false, }, { metric: pattern.pct25, - title: "pct25", - color: colors.yellow, + title: `${title} pct25`, + color: stat.pct25, defaultActive: false, }, { metric: pattern.pct90, - title: "pct90", - color: colors.rose, + title: `${title} pct90`, + color: stat.pct90, defaultActive: false, }, { metric: pattern.pct10, - title: "pct10", - color: colors.lime, + title: `${title} pct10`, + color: stat.pct10, defaultActive: false, }, ]; @@ -266,55 +272,61 @@ export function fromBitcoin(colors, pattern, title, color) { * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromBlockSize(colors, pattern, title, color) { + const { stat } = colors; return [ { metric: pattern.sum, title, color: color ?? colors.default }, - { metric: pattern.average, title: "Average", defaultActive: false }, + { + metric: pattern.average, + title: `${title} avg`, + color: stat.avg, + defaultActive: false, + }, { metric: pattern.cumulative, - title: `Cumulative`, - color: colors.cyan, + title: `${title} cumulative`, + color: stat.cumulative, defaultActive: false, }, { metric: pattern.max, - title: "Max", - color: colors.pink, + title: `${title} max`, + color: stat.max, defaultActive: false, }, { metric: pattern.min, - title: "Min", - color: colors.green, + title: `${title} min`, + color: stat.min, defaultActive: false, }, { metric: pattern.median, - title: "Median", - color: colors.amber, + title: `${title} median`, + color: stat.median, defaultActive: false, }, { metric: pattern.pct75, - title: "pct75", - color: colors.red, + title: `${title} pct75`, + color: stat.pct75, defaultActive: false, }, { metric: pattern.pct25, - title: "pct25", - color: colors.yellow, + title: `${title} pct25`, + color: stat.pct25, defaultActive: false, }, { metric: pattern.pct90, - title: "pct90", - color: colors.rose, + title: `${title} pct90`, + color: stat.pct90, defaultActive: false, }, { metric: pattern.pct10, - title: "pct10", - color: colors.lime, + title: `${title} pct10`, + color: stat.pct10, defaultActive: false, }, ]; @@ -329,68 +341,69 @@ export function fromBlockSize(colors, pattern, title, color) { * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromSizePattern(colors, pattern, unit, title = "") { + const { stat } = colors; return [ { metric: pattern.average, title: `${title} avg`.trim(), unit }, { metric: pattern.sum, title: `${title} sum`.trim(), - color: colors.blue, + color: stat.sum, unit, defaultActive: false, }, { metric: pattern.cumulative, title: `${title} cumulative`.trim(), - color: colors.indigo, - unit, - defaultActive: false, - }, - { - metric: pattern.min, - title: `${title} min`.trim(), - color: colors.red, + color: stat.cumulative, unit, defaultActive: false, }, { metric: pattern.max, title: `${title} max`.trim(), - color: colors.green, + color: stat.max, unit, defaultActive: false, }, { - metric: pattern.pct10, - title: `${title} pct10`.trim(), - color: colors.rose, - unit, - defaultActive: false, - }, - { - metric: pattern.pct25, - title: `${title} pct25`.trim(), - color: colors.pink, + metric: pattern.min, + title: `${title} min`.trim(), + color: stat.min, unit, defaultActive: false, }, { metric: pattern.median, title: `${title} median`.trim(), - color: colors.purple, + color: stat.median, unit, defaultActive: false, }, { metric: pattern.pct75, title: `${title} pct75`.trim(), - color: colors.violet, + color: stat.pct75, + unit, + defaultActive: false, + }, + { + metric: pattern.pct25, + title: `${title} pct25`.trim(), + color: stat.pct25, unit, defaultActive: false, }, { metric: pattern.pct90, title: `${title} pct90`.trim(), - color: colors.fuchsia, + color: stat.pct90, + unit, + defaultActive: false, + }, + { + metric: pattern.pct10, + title: `${title} pct10`.trim(), + color: stat.pct10, unit, defaultActive: false, }, @@ -406,61 +419,61 @@ export function fromSizePattern(colors, pattern, unit, title = "") { * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromFullnessPattern(colors, pattern, unit, title = "") { + const { stat } = colors; return [ { metric: pattern.base, title: title || "base", unit }, { metric: pattern.average, title: `${title} avg`.trim(), - color: colors.purple, + color: stat.avg, + unit, + }, + { + metric: pattern.max, + title: `${title} max`.trim(), + color: stat.max, unit, defaultActive: false, }, { metric: pattern.min, title: `${title} min`.trim(), - color: colors.red, - unit, - defaultActive: false, - }, - { - metric: pattern.max, - title: `${title} max`.trim(), - color: colors.green, - unit, - defaultActive: false, - }, - { - metric: pattern.pct10, - title: `${title} pct10`.trim(), - color: colors.rose, - unit, - defaultActive: false, - }, - { - metric: pattern.pct25, - title: `${title} pct25`.trim(), - color: colors.pink, + color: stat.min, unit, defaultActive: false, }, { metric: pattern.median, title: `${title} median`.trim(), - color: colors.violet, + color: stat.median, unit, defaultActive: false, }, { metric: pattern.pct75, title: `${title} pct75`.trim(), - color: colors.fuchsia, + color: stat.pct75, + unit, + defaultActive: false, + }, + { + metric: pattern.pct25, + title: `${title} pct25`.trim(), + color: stat.pct25, unit, defaultActive: false, }, { metric: pattern.pct90, title: `${title} pct90`.trim(), - color: colors.amber, + color: stat.pct90, + unit, + defaultActive: false, + }, + { + metric: pattern.pct10, + title: `${title} pct10`.trim(), + color: stat.pct10, unit, defaultActive: false, }, @@ -476,74 +489,75 @@ export function fromFullnessPattern(colors, pattern, unit, title = "") { * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromDollarsPattern(colors, pattern, unit, title = "") { + const { stat } = colors; return [ { metric: pattern.base, title: title || "base", unit }, { metric: pattern.sum, title: `${title} sum`.trim(), - color: colors.blue, + color: stat.sum, unit, }, { metric: pattern.cumulative, title: `${title} cumulative`.trim(), - color: colors.cyan, + color: stat.cumulative, unit, defaultActive: false, }, { metric: pattern.average, title: `${title} avg`.trim(), - color: colors.purple, - unit, - defaultActive: false, - }, - { - metric: pattern.min, - title: `${title} min`.trim(), - color: colors.red, + color: stat.avg, unit, defaultActive: false, }, { metric: pattern.max, title: `${title} max`.trim(), - color: colors.green, + color: stat.max, unit, defaultActive: false, }, { - metric: pattern.pct10, - title: `${title} pct10`.trim(), - color: colors.rose, - unit, - defaultActive: false, - }, - { - metric: pattern.pct25, - title: `${title} pct25`.trim(), - color: colors.pink, + metric: pattern.min, + title: `${title} min`.trim(), + color: stat.min, unit, defaultActive: false, }, { metric: pattern.median, title: `${title} median`.trim(), - color: colors.violet, + color: stat.median, unit, defaultActive: false, }, { metric: pattern.pct75, title: `${title} pct75`.trim(), - color: colors.fuchsia, + color: stat.pct75, + unit, + defaultActive: false, + }, + { + metric: pattern.pct25, + title: `${title} pct25`.trim(), + color: stat.pct25, unit, defaultActive: false, }, { metric: pattern.pct90, title: `${title} pct90`.trim(), - color: colors.amber, + color: stat.pct90, + unit, + defaultActive: false, + }, + { + metric: pattern.pct10, + title: `${title} pct10`.trim(), + color: stat.pct10, unit, defaultActive: false, }, @@ -559,54 +573,67 @@ export function fromDollarsPattern(colors, pattern, unit, title = "") { * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromFeeRatePattern(colors, pattern, unit, title = "") { + const { stat } = colors; return [ - { metric: pattern.average, title: `${title} avg`.trim(), unit }, { - metric: pattern.min, - title: `${title} min`.trim(), - color: colors.red, + type: "Dots", + metric: pattern.average, + title: `${title} avg`.trim(), unit, - defaultActive: false, }, { + type: "Dots", metric: pattern.max, title: `${title} max`.trim(), - color: colors.green, + color: stat.max, unit, defaultActive: false, }, { - metric: pattern.pct10, - title: `${title} pct10`.trim(), - color: colors.rose, - unit, - defaultActive: false, - }, - { - metric: pattern.pct25, - title: `${title} pct25`.trim(), - color: colors.pink, + type: "Dots", + metric: pattern.min, + title: `${title} min`.trim(), + color: stat.min, unit, defaultActive: false, }, { + type: "Dots", metric: pattern.median, title: `${title} median`.trim(), - color: colors.purple, + color: stat.median, unit, defaultActive: false, }, { + type: "Dots", metric: pattern.pct75, title: `${title} pct75`.trim(), - color: colors.violet, + color: stat.pct75, unit, defaultActive: false, }, { + type: "Dots", + metric: pattern.pct25, + title: `${title} pct25`.trim(), + color: stat.pct25, + unit, + defaultActive: false, + }, + { + type: "Dots", metric: pattern.pct90, title: `${title} pct90`.trim(), - color: colors.fuchsia, + color: stat.pct90, + unit, + defaultActive: false, + }, + { + type: "Dots", + metric: pattern.pct10, + title: `${title} pct10`.trim(), + color: stat.pct10, unit, defaultActive: false, }, @@ -617,13 +644,13 @@ export function fromFeeRatePattern(colors, pattern, unit, title = "") { * Create series from a CoinbasePattern ({ sats, bitcoin, dollars } each as FullnessPattern) * @param {Colors} colors * @param {CoinbasePattern} pattern - * @param {string} title + * @param {string} [title] * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromCoinbasePattern(colors, pattern, title) { return [ - ...fromFullnessPattern(colors, pattern.sats, Unit.sats, title), ...fromFullnessPattern(colors, pattern.bitcoin, Unit.btc, title), + ...fromFullnessPattern(colors, pattern.sats, Unit.sats, title), ...fromFullnessPattern(colors, pattern.dollars, Unit.usd, title), ]; } @@ -632,7 +659,7 @@ export function fromCoinbasePattern(colors, pattern, title) { * Create series from a ValuePattern ({ sats, bitcoin, dollars } each as BlockCountPattern with sum + cumulative) * @param {Colors} colors * @param {ValuePattern} pattern - * @param {string} title + * @param {string} [title] * @param {Color} [sumColor] * @param {Color} [cumulativeColor] * @returns {AnyFetchedSeriesBlueprint[]} @@ -640,47 +667,47 @@ export function fromCoinbasePattern(colors, pattern, title) { export function fromValuePattern( colors, pattern, - title, + title = "", sumColor, cumulativeColor, ) { return [ - { - metric: pattern.sats.sum, - title, - color: sumColor, - unit: Unit.sats, - }, - { - metric: pattern.sats.cumulative, - title: `${title} cumulative`, - color: cumulativeColor ?? colors.blue, - unit: Unit.sats, - defaultActive: false, - }, { metric: pattern.bitcoin.sum, - title, + title: title || "sum", color: sumColor, unit: Unit.btc, }, { metric: pattern.bitcoin.cumulative, - title: `${title} cumulative`, - color: cumulativeColor ?? colors.blue, + title: `${title} cumulative`.trim(), + color: cumulativeColor ?? colors.stat.cumulative, unit: Unit.btc, defaultActive: false, }, + { + metric: pattern.sats.sum, + title: title || "sum", + color: sumColor, + unit: Unit.sats, + }, + { + metric: pattern.sats.cumulative, + title: `${title} cumulative`.trim(), + color: cumulativeColor ?? colors.stat.cumulative, + unit: Unit.sats, + defaultActive: false, + }, { metric: pattern.dollars.sum, - title, + title: title || "sum", color: sumColor, unit: Unit.usd, }, { metric: pattern.dollars.cumulative, - title: `${title} cumulative`, - color: cumulativeColor ?? colors.blue, + title: `${title} cumulative`.trim(), + color: cumulativeColor ?? colors.stat.cumulative, unit: Unit.usd, defaultActive: false, }, @@ -715,7 +742,7 @@ export function fromBitcoinPatternWithUnit( { metric: pattern.cumulative, title: `${title} cumulative`, - color: cumulativeColor ?? colors.blue, + color: cumulativeColor ?? colors.stat.cumulative, unit, defaultActive: false, }, @@ -750,7 +777,7 @@ export function fromBlockCountWithUnit( { metric: pattern.cumulative, title: `${title} cumulative`.trim(), - color: cumulativeColor ?? colors.blue, + color: cumulativeColor ?? colors.stat.cumulative, unit, defaultActive: false, }, @@ -767,61 +794,62 @@ export function fromBlockCountWithUnit( * @returns {AnyFetchedSeriesBlueprint[]} */ export function fromIntervalPattern(colors, pattern, unit, title = "", color) { + const { stat } = colors; return [ { metric: pattern.base, title: title ?? "base", color, unit }, { metric: pattern.average, title: `${title} avg`.trim(), - color: colors.cyan, - unit, - defaultActive: false, - }, - { - metric: pattern.min, - title: `${title} min`.trim(), - color: colors.red, + color: stat.avg, unit, defaultActive: false, }, { metric: pattern.max, title: `${title} max`.trim(), - color: colors.green, + color: stat.max, + unit, + defaultActive: false, + }, + { + metric: pattern.min, + title: `${title} min`.trim(), + color: stat.min, unit, defaultActive: false, }, { metric: pattern.median, title: `${title} median`.trim(), - color: colors.violet, - unit, - defaultActive: false, - }, - { - metric: pattern.pct10, - title: `${title} pct10`.trim(), - color: colors.rose, - unit, - defaultActive: false, - }, - { - metric: pattern.pct25, - title: `${title} pct25`.trim(), - color: colors.pink, + color: stat.median, unit, defaultActive: false, }, { metric: pattern.pct75, title: `${title} pct75`.trim(), - color: colors.fuchsia, + color: stat.pct75, + unit, + defaultActive: false, + }, + { + metric: pattern.pct25, + title: `${title} pct25`.trim(), + color: stat.pct25, unit, defaultActive: false, }, { metric: pattern.pct90, title: `${title} pct90`.trim(), - color: colors.amber, + color: stat.pct90, + unit, + defaultActive: false, + }, + { + metric: pattern.pct10, + title: `${title} pct10`.trim(), + color: stat.pct10, unit, defaultActive: false, }, @@ -830,30 +858,29 @@ export function fromIntervalPattern(colors, pattern, unit, title = "", color) { /** * Create series from a SupplyPattern (sats/bitcoin/dollars, no sum/cumulative) - * @param {Colors} colors * @param {SupplyPattern} pattern * @param {string} title * @param {Color} [color] * @returns {AnyFetchedSeriesBlueprint[]} */ -export function fromSupplyPattern(colors, pattern, title, color) { +export function fromSupplyPattern(pattern, title, color) { return [ - { - metric: pattern.sats, - title, - color: color ?? colors.default, - unit: Unit.sats, - }, { metric: pattern.bitcoin, title, - color: color ?? colors.default, + color, unit: Unit.btc, }, + { + metric: pattern.sats, + title, + color, + unit: Unit.sats, + }, { metric: pattern.dollars, title, - color: color ?? colors.default, + color, unit: Unit.usd, }, ]; diff --git a/website/scripts/options/shared.js b/website/scripts/options/shared.js index f11d35fd2..cb0bfbe98 100644 --- a/website/scripts/options/shared.js +++ b/website/scripts/options/shared.js @@ -1,7 +1,8 @@ /** Shared helpers for options */ import { Unit } from "../utils/units.js"; -import { line } from "./series.js"; +import { line, baseline } from "./series.js"; +import { priceLine, priceLines } from "./constants.js"; /** * Create sats/btc/usd line series from a pattern with .sats/.bitcoin/.dollars @@ -14,7 +15,6 @@ import { line } from "./series.js"; export function satsBtcUsd(pattern, name, color, options) { const { defaultActive } = options || {}; return [ - line({ metric: pattern.sats, name, color, unit: Unit.sats, defaultActive }), line({ metric: pattern.bitcoin, name, @@ -22,6 +22,7 @@ export function satsBtcUsd(pattern, name, color, options) { unit: Unit.btc, defaultActive, }), + line({ metric: pattern.sats, name, color, unit: Unit.sats, defaultActive }), line({ metric: pattern.dollars, name, @@ -82,7 +83,7 @@ export function sdPatterns(ratio) { * @param {Colors} colors * @param {Ratio1ySdPattern} sd */ -export function sdBands(colors, sd) { +export function sdBandsUsd(colors, sd) { return /** @type {const} */ ([ { name: "0σ", prop: sd._0sdUsd, color: colors.lime }, { name: "+0.5σ", prop: sd.p05sdUsd, color: colors.yellow }, @@ -95,7 +96,249 @@ export function sdBands(colors, sd) { { name: "−2σ", prop: sd.m2sdUsd, color: colors.blue }, { name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose }, { name: "−2.5σ", prop: sd.m25sdUsd, color: colors.indigo }, + { name: "+3σ", prop: sd.p3sdUsd, color: colors.pink }, + { name: "−3σ", prop: sd.m3sdUsd, color: colors.violet }, + ]); +} + +/** + * Build SD band mappings (ratio) from an SD pattern + * @param {Colors} colors + * @param {Ratio1ySdPattern} sd + */ +export function sdBandsRatio(colors, sd) { + return /** @type {const} */ ([ + { name: "0σ", prop: sd.sma, color: colors.lime }, + { name: "+0.5σ", prop: sd.p05sd, color: colors.yellow }, + { name: "−0.5σ", prop: sd.m05sd, color: colors.teal }, + { name: "+1σ", prop: sd.p1sd, color: colors.amber }, + { name: "−1σ", prop: sd.m1sd, color: colors.cyan }, + { name: "+1.5σ", prop: sd.p15sd, color: colors.orange }, + { name: "−1.5σ", prop: sd.m15sd, color: colors.sky }, + { name: "+2σ", prop: sd.p2sd, color: colors.red }, + { name: "−2σ", prop: sd.m2sd, color: colors.blue }, + { name: "+2.5σ", prop: sd.p25sd, color: colors.rose }, + { name: "−2.5σ", prop: sd.m25sd, color: colors.indigo }, { name: "+3σ", prop: sd.p3sd, color: colors.pink }, { name: "−3σ", prop: sd.m3sd, color: colors.violet }, ]); } + +/** + * Build ratio SMA series from a ratio pattern + * @param {Colors} colors + * @param {ActivePriceRatioPattern} ratio + */ +export function ratioSmas(colors, ratio) { + return /** @type {const} */ ([ + { name: "1w SMA", metric: ratio.ratio1wSma, color: colors.lime }, + { name: "1m SMA", metric: ratio.ratio1mSma, color: colors.teal }, + { name: "1y SMA", metric: ratio.ratio1ySd.sma, color: colors.sky }, + { name: "2y SMA", metric: ratio.ratio2ySd.sma, color: colors.indigo }, + { name: "4y SMA", metric: ratio.ratio4ySd.sma, color: colors.purple }, + { name: "All SMA", metric: ratio.ratioSd.sma, color: colors.rose }, + ]); +} + +/** + * Create ratio chart from ActivePriceRatioPattern + * @param {PartialContext} ctx + * @param {Object} args + * @param {string} args.title + * @param {AnyMetricPattern} args.price - The price metric to show in top pane + * @param {ActivePriceRatioPattern} args.ratio - The ratio pattern + * @param {Color} args.color + * @returns {PartialChartOption} + */ +export function createRatioChart(ctx, { title, price, ratio, color }) { + const { colors } = ctx; + + return { + name: "ratio", + title: `${title} Ratio`, + top: [ + line({ metric: price, name: "price", color, unit: Unit.usd }), + ...percentileUsdMap(colors, ratio).map(({ name, prop, color }) => + line({ + metric: prop, + name, + color, + defaultActive: false, + unit: Unit.usd, + options: { lineStyle: 1 }, + }), + ), + ], + bottom: [ + baseline({ + metric: ratio.ratio, + name: "Ratio", + unit: Unit.ratio, + base: 1, + }), + ...ratioSmas(colors, ratio).map(({ name, metric, color }) => + line({ metric, name, color, unit: Unit.ratio, defaultActive: false }), + ), + ...percentileMap(colors, ratio).map(({ name, prop, color }) => + line({ + metric: prop, + name, + color, + defaultActive: false, + unit: Unit.ratio, + options: { lineStyle: 1 }, + }), + ), + priceLine({ ctx, unit: Unit.ratio, number: 1 }), + ], + }; +} + +/** + * Create ZScores folder from ActivePriceRatioPattern + * @param {PartialContext} ctx + * @param {Object} args + * @param {string} args.title + * @param {string} args.legend + * @param {AnyMetricPattern} args.price - The price metric to show in top pane + * @param {ActivePriceRatioPattern} args.ratio - The ratio pattern + * @param {Color} args.color + * @returns {PartialOptionsGroup} + */ +export function createZScoresFolder( + ctx, + { title, legend, price, ratio, color }, +) { + const { colors } = ctx; + const sdPats = sdPatterns(ratio); + + return { + name: "ZScores", + tree: [ + { + name: "Compare", + title: `${title} Z-Scores`, + top: [ + line({ metric: price, name: legend, color, unit: Unit.usd }), + line({ + metric: ratio.ratio1ySd._0sdUsd, + name: "1y 0σ", + color: colors.orange, + defaultActive: false, + unit: Unit.usd, + }), + line({ + metric: ratio.ratio2ySd._0sdUsd, + name: "2y 0σ", + color: colors.yellow, + defaultActive: false, + unit: Unit.usd, + }), + line({ + metric: ratio.ratio4ySd._0sdUsd, + name: "4y 0σ", + color: colors.lime, + defaultActive: false, + unit: Unit.usd, + }), + line({ + metric: ratio.ratioSd._0sdUsd, + name: "all 0σ", + color: colors.blue, + defaultActive: false, + unit: Unit.usd, + }), + ], + bottom: [ + line({ + metric: ratio.ratioSd.zscore, + name: "all", + color: colors.blue, + unit: Unit.sd, + }), + line({ + metric: ratio.ratio4ySd.zscore, + name: "4y", + color: colors.lime, + unit: Unit.sd, + }), + line({ + metric: ratio.ratio2ySd.zscore, + name: "2y", + color: colors.yellow, + unit: Unit.sd, + }), + line({ + metric: ratio.ratio1ySd.zscore, + name: "1y", + color: colors.orange, + unit: Unit.sd, + }), + ...priceLines({ + ctx, + unit: Unit.sd, + numbers: [0, 1, -1, 2, -2, 3, -3], + defaultActive: false, + }), + ], + }, + ...sdPats.map(({ nameAddon, titleAddon, sd }) => ({ + name: nameAddon, + title: `${title} ${titleAddon} Z-Score`, + top: [ + line({ metric: price, name: legend, color, unit: Unit.usd }), + ...sdBandsUsd(colors, sd).map( + ({ name: bandName, prop, color: bandColor }) => + line({ + metric: prop, + name: bandName, + color: bandColor, + unit: Unit.usd, + defaultActive: false, + }), + ), + ], + bottom: [ + baseline({ + metric: sd.zscore, + name: "Z-Score", + unit: Unit.sd, + }), + baseline({ + metric: ratio.ratio, + name: "Ratio", + unit: Unit.ratio, + base: 1, + }), + line({ + metric: sd.sd, + name: "Volatility", + color: colors.gray, + unit: Unit.percentage, + }), + ...sdBandsRatio(colors, sd).map( + ({ name: bandName, prop, color: bandColor }) => + line({ + metric: prop, + name: bandName, + color: bandColor, + unit: Unit.ratio, + defaultActive: false, + }), + ), + priceLine({ ctx, unit: Unit.ratio, number: 1 }), + priceLine({ + ctx, + unit: Unit.sd, + }), + ...priceLines({ + ctx, + unit: Unit.sd, + numbers: [1, -1, 2, -2, 3, -3], + defaultActive: false, + }), + ], + })), + ], + }; +} diff --git a/website/scripts/options/types.js b/website/scripts/options/types.js index e4439dde1..33643a7e5 100644 --- a/website/scripts/options/types.js +++ b/website/scripts/options/types.js @@ -160,6 +160,7 @@ * @property {string} title * @property {Color} color * @property {PatternAll} tree + * @property {Brk.MetricPattern1} addrCount * * Full cohort: adjustedSopr + percentiles + RelToMarketCap (term.short) * @typedef {Object} CohortFull @@ -190,6 +191,13 @@ * @property {PatternBasic} tree * * ============================================================================ + * Extended Cohort Types (with address count) + * ============================================================================ + * + * Basic cohort with address count (for "type" cohorts) + * @typedef {CohortBasic & { addrCount: Brk.MetricPattern1 }} CohortAddress + * + * ============================================================================ * Cohort Group Types (by capability) * ============================================================================ * @@ -233,23 +241,6 @@ * @property {readonly AddressCohortObject[]} list * * @typedef {UtxoCohortGroupObject | AddressCohortGroupObject} CohortGroupObject - * - * @typedef {Object} PartialContext - * @property {Colors} colors - * @property {BrkClient} brk - * @property {(pattern: BlockCountPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCount - * @property {(pattern: FullnessPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoin - * @property {(pattern: AnyStatsPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockSize - * @property {(pattern: AnyStatsPattern, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromSizePattern - * @property {(pattern: FullnessPattern, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromFullnessPattern - * @property {(pattern: DollarsPattern, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromDollarsPattern - * @property {(pattern: FeeRatePattern, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromFeeRatePattern - * @property {(pattern: CoinbasePattern, title: string) => AnyFetchedSeriesBlueprint[]} fromCoinbasePattern - * @property {(pattern: ValuePattern, title: string, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromValuePattern - * @property {(pattern: { sum: AnyMetricPattern, cumulative: AnyMetricPattern }, title: string, unit: Unit, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoinPatternWithUnit - * @property {(pattern: BlockCountPattern, unit: Unit, title?: string, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCountWithUnit - * @property {(pattern: IntervalPattern, unit: Unit, title?: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromIntervalPattern - * @property {(pattern: SupplyPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromSupplyPattern */ // Re-export for type consumers diff --git a/website/scripts/types.js b/website/scripts/types.js index 79c11b853..768695680 100644 --- a/website/scripts/types.js +++ b/website/scripts/types.js @@ -14,7 +14,7 @@ * * @import { WebSockets } from "./utils/ws.js" * - * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupBasic, UtxoCohortGroupObject, AddressCohortGroupObject, FetchedDotsSeriesBlueprint, FetchedCandlestickSeriesBlueprint } from "./options/partial.js" + * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortAddress, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupBasic, UtxoCohortGroupObject, AddressCohortGroupObject, FetchedDotsSeriesBlueprint, FetchedCandlestickSeriesBlueprint } from "./options/partial.js" * * * @import { UnitObject as Unit } from "./utils/units.js" @@ -41,7 +41,7 @@ * @typedef {Brk._10yTo12yPattern} AgeRangePattern * @typedef {Brk._0satsPattern2} UtxoAmountPattern * @typedef {Brk._0satsPattern} AddressAmountPattern - * @typedef {Brk._100btcPattern} BasicUtxoPattern + * @typedef {Brk._0Pattern} BasicUtxoPattern * @typedef {Brk._0satsPattern2} EpochPattern * @typedef {Brk.Ratio1ySdPattern} Ratio1ySdPattern * @typedef {Brk.Dollars} Dollars @@ -53,6 +53,8 @@ * @typedef {Brk.AnyMetricEndpointBuilder} AnyMetricEndpoint * @typedef {Brk.AnyMetricData} AnyMetricData * @typedef {Brk.AddrCountPattern} AddrCountPattern + * @typedef {keyof Brk.MetricsTree_Distribution_UtxoCohorts_Type} SpendableType + * @typedef {keyof Brk.MetricsTree_Distribution_AnyAddressIndexes} AddressableType * @typedef {FullnessPattern} IntervalPattern * @typedef {Brk.MetricsTree_Supply_Circulating} SupplyPattern * @typedef {Brk.RelativePattern} GlobalRelativePattern diff --git a/website/scripts/utils/format.js b/website/scripts/utils/format.js index 4b2bcf923..fa7c486ca 100644 --- a/website/scripts/utils/format.js +++ b/website/scripts/utils/format.js @@ -31,7 +31,7 @@ export const numberToPercentage = new Intl.NumberFormat("en-US", { export function numberToShortUSFormat(value, digits) { const absoluteValue = Math.abs(value); - if (isNaN(value)) { + if (isNaN(value) || !isFinite(value)) { return ""; } else if (absoluteValue < 10) { return numberToUSNumber(value, Math.min(3, digits || 10)); @@ -41,13 +41,13 @@ export function numberToShortUSFormat(value, digits) { return numberToUSNumber(value, Math.min(1, digits || 10)); } else if (absoluteValue < 1_000_000) { return numberToUSNumber(value, 0); - } else if (absoluteValue >= 1_000_000_000_000_000_000_000) { + } else if (absoluteValue >= 1e27) { return "Inf."; } const log = Math.floor(Math.log10(absoluteValue) - 6); - const suffices = ["M", "B", "T", "P", "E", "Z"]; + const suffices = ["M", "B", "T", "P", "E", "Z", "Y"]; const letterIndex = Math.floor(log / 3); const letter = suffices[letterIndex]; diff --git a/website/scripts/utils/units.js b/website/scripts/utils/units.js index 8efa11732..d41f95e29 100644 --- a/website/scripts/utils/units.js +++ b/website/scripts/utils/units.js @@ -16,7 +16,7 @@ export const Unit = /** @type {const} */ ({ sd: { id: "sd", name: "Std Dev" }, // Relative percentages - pctSupply: { id: "pct-supply", name: "% of Supply" }, + pctSupply: { id: "pct-supply", name: "% of circulating Supply" }, pctOwn: { id: "pct-own", name: "% of Own Supply" }, pctMcap: { id: "pct-mcap", name: "% of Market Cap" }, pctRcap: { id: "pct-rcap", name: "% of Realized Cap" },