website: snapshot

This commit is contained in:
nym21
2026-01-24 19:22:03 +01:00
parent 9b706dfaee
commit 7cdf47a9e4
33 changed files with 3031 additions and 2132 deletions
@@ -131,7 +131,8 @@ def _p(prefix: str, acc: str) -> str:
pub fn generate_endpoint_class(output: &mut String) { pub fn generate_endpoint_class(output: &mut String) {
writeln!( writeln!(
output, output,
r#"class MetricData(TypedDict, Generic[T]): r#"@dataclass
class MetricData(Generic[T]):
"""Metric data with range information.""" """Metric data with range information."""
version: int version: int
total: int total: int
@@ -176,8 +177,9 @@ class _EndpointConfig:
p = self.path() p = self.path()
return f"{{p}}?{{query}}" if query else p return f"{{p}}?{{query}}" if query else p
def get_json(self) -> Any: def get_json(self) -> MetricData:
return self.client.get_json(self._build_path()) data = self.client.get_json(self._build_path())
return MetricData(**data)
def get_csv(self) -> str: def get_csv(self) -> str:
return self.client.get_text(self._build_path(format='csv')) 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 // Generate helper function
writeln!( writeln!(
output, 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) return MetricEndpointBuilder(c, n, i)
"# "#
) )
@@ -409,6 +411,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
// Generate the main accessor class // Generate the main accessor class
writeln!(output, "class {}(Generic[T]):", pattern.name).unwrap(); writeln!(output, "class {}(Generic[T]):", pattern.name).unwrap();
writeln!(output, " by: {}[T]", by_class_name).unwrap();
writeln!( writeln!(
output, output,
" def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, {}(c, n)", " def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, {}(c, n)",
@@ -24,12 +24,18 @@ pub fn generate_python_client(
writeln!(output, "# Auto-generated BRK Python client").unwrap(); writeln!(output, "# Auto-generated BRK Python client").unwrap();
writeln!(output, "# Do not edit manually\n").unwrap(); writeln!(output, "# Do not edit manually\n").unwrap();
writeln!(output, "from __future__ import annotations").unwrap();
writeln!(output, "from dataclasses import dataclass").unwrap();
writeln!( writeln!(
output, output,
"from typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol, overload" "from typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol, overload"
) )
.unwrap(); .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, "from urllib.parse import urlparse").unwrap();
writeln!(output, "import json\n").unwrap(); writeln!(output, "import json\n").unwrap();
writeln!(output, "T = TypeVar('T')\n").unwrap(); writeln!(output, "T = TypeVar('T')\n").unwrap();
File diff suppressed because it is too large Load Diff
@@ -38,8 +38,8 @@ impl UTXOCohorts {
) -> Result<Self> { ) -> Result<Self> {
let v = version + VERSION; let v = version + VERSION;
// Phase 1: Import base cohorts that don't need adjusted (age_range, amount_range, etc.) // Phase 1: Import base cohorts for overlapping computations (age_range, amount_range).
// These are the source cohorts for overlapping computations. // These are the source cohorts and must be imported before "all" to provide up_to_1h.
let base = |f: Filter, name: &'static str| { let base = |f: Filter, name: &'static str| {
UTXOCohortVecs::forced_import( UTXOCohortVecs::forced_import(
db, db,
@@ -57,9 +57,6 @@ impl UTXOCohorts {
let age_range = ByAgeRange::try_new(&base)?; let age_range = ByAgeRange::try_new(&base)?;
let amount_range = ByAmountRange::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) // 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(); 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); 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| { let price_only_adjusted = |f: Filter, name: &'static str| {
UTXOCohortVecs::forced_import( UTXOCohortVecs::forced_import(
db, db,
@@ -115,7 +132,17 @@ impl UTXOCohorts {
let max_age = ByMaxAge::try_new(&none_adjusted)?; 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| { let none = |f: Filter, name: &'static str| {
UTXOCohortVecs::forced_import( UTXOCohortVecs::forced_import(
db, db,
@@ -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. /// Get the starting height when state was imported.
pub fn state_starting_height(&self) -> Option<Height> { pub fn state_starting_height(&self) -> Option<Height> {
self.state_starting_height self.state_starting_height
@@ -333,6 +333,28 @@ impl CohortMetrics {
Ok(()) 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). /// Second phase of computed metrics (ratios, relative values).
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn compute_rest_part2( pub fn compute_rest_part2(
@@ -1,3 +1,4 @@
use brk_cohort::Filter;
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{Dollars, Sats, StoredF32, StoredF64, Version}; 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::<PercentageSatsF64>(
&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::<PercentageSatsF64>(
&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::<PercentageSatsF64>(
&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,
),
);
}
}
} }
+27
View File
@@ -34,6 +34,7 @@ pub struct Vecs {
pub _1w_dominance: LazyBinaryFromHeightLast<StoredF32, StoredU32, StoredU32>, pub _1w_dominance: LazyBinaryFromHeightLast<StoredF32, StoredU32, StoredU32>,
pub _1m_dominance: LazyBinaryFromHeightLast<StoredF32, StoredU32, StoredU32>, pub _1m_dominance: LazyBinaryFromHeightLast<StoredF32, StoredU32, StoredU32>,
pub _1y_dominance: LazyBinaryFromHeightLast<StoredF32, StoredU32, StoredU32>, pub _1y_dominance: LazyBinaryFromHeightLast<StoredF32, StoredU32, StoredU32>,
pub blocks_since_block: ComputedFromHeightLast<StoredU32>,
pub days_since_block: ComputedFromDateLast<StoredU16>, pub days_since_block: ComputedFromDateLast<StoredU16>,
} }
@@ -128,6 +129,12 @@ impl Vecs {
>(&suffix("coinbase"), version, &subsidy, &fee), >(&suffix("coinbase"), version, &subsidy, &fee),
subsidy, subsidy,
fee, fee,
blocks_since_block: ComputedFromHeightLast::forced_import(
db,
&suffix("blocks_since_block"),
version,
indexes,
)?,
days_since_block: ComputedFromDateLast::forced_import( days_since_block: ComputedFromDateLast::forced_import(
db, db,
&suffix("days_since_block"), &suffix("days_since_block"),
@@ -211,6 +218,26 @@ impl Vecs {
self.fee.derive_from(indexes, starting_indexes, exit)?; 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 self.days_since_block
.compute_all(starting_indexes, exit, |v| { .compute_all(starting_indexes, exit, |v| {
let mut prev = None; let mut prev = None;
+12
View File
@@ -40,3 +40,15 @@ path = "examples/tune_smooth.rs"
[[example]] [[example]]
name = "debug_oracle" name = "debug_oracle"
path = "examples/debug_oracle.rs" 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"
+4
View File
@@ -2,6 +2,8 @@
JavaScript/TypeScript client for the [Bitcoin Research Kit](https://github.com/bitcoinresearchkit/brk) API. 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) [npm](https://www.npmjs.com/package/brk-client) | [API Reference](https://github.com/bitcoinresearchkit/brk/blob/main/modules/brk-client/docs/globals.md)
## Installation ## Installation
@@ -10,6 +12,8 @@ JavaScript/TypeScript client for the [Bitcoin Research Kit](https://github.com/b
npm install brk-client npm install brk-client
``` ```
Or just copy [`index.js`](./index.js) into your project - it's a single file with no dependencies.
## Quick Start ## Quick Start
```javascript ```javascript
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
3.12 3.9
+4
View File
@@ -2,6 +2,8 @@
Python client for the [Bitcoin Research Kit](https://github.com/bitcoinresearchkit/brk) API. 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) [PyPI](https://pypi.org/project/brk-client/) | [API Reference](https://github.com/bitcoinresearchkit/brk/blob/main/packages/brk_client/DOCS.md)
## Installation ## Installation
@@ -12,6 +14,8 @@ pip install brk-client
uv add 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 ## Quick Start
```python ```python
+283 -239
View File
@@ -1,6 +1,8 @@
# Auto-generated BRK Python client # Auto-generated BRK Python client
# Do not edit manually # 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 typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol, overload
from http.client import HTTPSConnection, HTTPConnection from http.client import HTTPSConnection, HTTPConnection
from urllib.parse import urlparse from urllib.parse import urlparse
@@ -1039,7 +1041,8 @@ def _p(prefix: str, acc: str) -> str:
return f"{prefix}_{acc}" if acc else prefix return f"{prefix}_{acc}" if acc else prefix
class MetricData(TypedDict, Generic[T]): @dataclass
class MetricData(Generic[T]):
"""Metric data with range information.""" """Metric data with range information."""
version: int version: int
total: int total: int
@@ -1084,8 +1087,9 @@ class _EndpointConfig:
p = self.path() p = self.path()
return f"{p}?{query}" if query else p return f"{p}?{query}" if query else p
def get_json(self) -> Any: def get_json(self) -> MetricData:
return self.client.get_json(self._build_path()) data = self.client.get_json(self._build_path())
return MetricData(**data)
def get_csv(self) -> str: def get_csv(self) -> str:
return self.client.get_text(self._build_path(format='csv')) return self.client.get_text(self._build_path(format='csv'))
@@ -1288,7 +1292,7 @@ _i31 = ('loadedaddressindex',)
_i32 = ('emptyaddressindex',) _i32 = ('emptyaddressindex',)
_i33 = ('pairoutputindex',) _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) return MetricEndpointBuilder(c, n, i)
# Index accessor classes # Index accessor classes
@@ -1306,6 +1310,7 @@ class _MetricPattern1By(Generic[T]):
def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex') def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex')
class MetricPattern1(Generic[T]): class MetricPattern1(Generic[T]):
by: _MetricPattern1By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern1By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern1By(c, n)
@property @property
def name(self) -> str: return self._n 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') def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex')
class MetricPattern2(Generic[T]): class MetricPattern2(Generic[T]):
by: _MetricPattern2By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern2By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern2By(c, n)
@property @property
def name(self) -> str: return self._n 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') def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex')
class MetricPattern3(Generic[T]): class MetricPattern3(Generic[T]):
by: _MetricPattern3By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern3By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern3By(c, n)
@property @property
def name(self) -> str: return self._n 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') def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex')
class MetricPattern4(Generic[T]): class MetricPattern4(Generic[T]):
by: _MetricPattern4By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern4By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern4By(c, n)
@property @property
def name(self) -> str: return self._n 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') def height(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'height')
class MetricPattern5(Generic[T]): class MetricPattern5(Generic[T]):
by: _MetricPattern5By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern5By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern5By(c, n)
@property @property
def name(self) -> str: return self._n 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') def dateindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'dateindex')
class MetricPattern6(Generic[T]): class MetricPattern6(Generic[T]):
by: _MetricPattern6By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern6By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern6By(c, n)
@property @property
def name(self) -> str: return self._n 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') def decadeindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'decadeindex')
class MetricPattern7(Generic[T]): class MetricPattern7(Generic[T]):
by: _MetricPattern7By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern7By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern7By(c, n)
@property @property
def name(self) -> str: return self._n 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') def difficultyepoch(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'difficultyepoch')
class MetricPattern8(Generic[T]): class MetricPattern8(Generic[T]):
by: _MetricPattern8By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern8By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern8By(c, n)
@property @property
def name(self) -> str: return self._n 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') def emptyoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'emptyoutputindex')
class MetricPattern9(Generic[T]): class MetricPattern9(Generic[T]):
by: _MetricPattern9By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern9By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern9By(c, n)
@property @property
def name(self) -> str: return self._n 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') def halvingepoch(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'halvingepoch')
class MetricPattern10(Generic[T]): class MetricPattern10(Generic[T]):
by: _MetricPattern10By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern10By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern10By(c, n)
@property @property
def name(self) -> str: return self._n 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') def height(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'height')
class MetricPattern11(Generic[T]): class MetricPattern11(Generic[T]):
by: _MetricPattern11By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern11By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern11By(c, n)
@property @property
def name(self) -> str: return self._n 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') def txinindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'txinindex')
class MetricPattern12(Generic[T]): class MetricPattern12(Generic[T]):
by: _MetricPattern12By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern12By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern12By(c, n)
@property @property
def name(self) -> str: return self._n 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') def monthindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'monthindex')
class MetricPattern13(Generic[T]): class MetricPattern13(Generic[T]):
by: _MetricPattern13By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern13By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern13By(c, n)
@property @property
def name(self) -> str: return self._n 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') def opreturnindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'opreturnindex')
class MetricPattern14(Generic[T]): class MetricPattern14(Generic[T]):
by: _MetricPattern14By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern14By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern14By(c, n)
@property @property
def name(self) -> str: return self._n 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') def txoutindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'txoutindex')
class MetricPattern15(Generic[T]): class MetricPattern15(Generic[T]):
by: _MetricPattern15By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern15By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern15By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2aaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2aaddressindex')
class MetricPattern16(Generic[T]): class MetricPattern16(Generic[T]):
by: _MetricPattern16By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern16By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern16By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2msoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2msoutputindex')
class MetricPattern17(Generic[T]): class MetricPattern17(Generic[T]):
by: _MetricPattern17By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern17By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern17By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2pk33addressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2pk33addressindex')
class MetricPattern18(Generic[T]): class MetricPattern18(Generic[T]):
by: _MetricPattern18By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern18By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern18By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2pk65addressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2pk65addressindex')
class MetricPattern19(Generic[T]): class MetricPattern19(Generic[T]):
by: _MetricPattern19By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern19By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern19By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2pkhaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2pkhaddressindex')
class MetricPattern20(Generic[T]): class MetricPattern20(Generic[T]):
by: _MetricPattern20By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern20By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern20By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2shaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2shaddressindex')
class MetricPattern21(Generic[T]): class MetricPattern21(Generic[T]):
by: _MetricPattern21By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern21By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern21By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2traddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2traddressindex')
class MetricPattern22(Generic[T]): class MetricPattern22(Generic[T]):
by: _MetricPattern22By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern22By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern22By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2wpkhaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2wpkhaddressindex')
class MetricPattern23(Generic[T]): class MetricPattern23(Generic[T]):
by: _MetricPattern23By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern23By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern23By(c, n)
@property @property
def name(self) -> str: return self._n 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') def p2wshaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'p2wshaddressindex')
class MetricPattern24(Generic[T]): class MetricPattern24(Generic[T]):
by: _MetricPattern24By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern24By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern24By(c, n)
@property @property
def name(self) -> str: return self._n 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') def quarterindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'quarterindex')
class MetricPattern25(Generic[T]): class MetricPattern25(Generic[T]):
by: _MetricPattern25By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern25By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern25By(c, n)
@property @property
def name(self) -> str: return self._n 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') def semesterindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'semesterindex')
class MetricPattern26(Generic[T]): class MetricPattern26(Generic[T]):
by: _MetricPattern26By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern26By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern26By(c, n)
@property @property
def name(self) -> str: return self._n 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') def txindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'txindex')
class MetricPattern27(Generic[T]): class MetricPattern27(Generic[T]):
by: _MetricPattern27By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern27By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern27By(c, n)
@property @property
def name(self) -> str: return self._n 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') def unknownoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'unknownoutputindex')
class MetricPattern28(Generic[T]): class MetricPattern28(Generic[T]):
by: _MetricPattern28By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern28By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern28By(c, n)
@property @property
def name(self) -> str: return self._n 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') def weekindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'weekindex')
class MetricPattern29(Generic[T]): class MetricPattern29(Generic[T]):
by: _MetricPattern29By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern29By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern29By(c, n)
@property @property
def name(self) -> str: return self._n 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') def yearindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'yearindex')
class MetricPattern30(Generic[T]): class MetricPattern30(Generic[T]):
by: _MetricPattern30By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern30By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern30By(c, n)
@property @property
def name(self) -> str: return self._n 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') def loadedaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'loadedaddressindex')
class MetricPattern31(Generic[T]): class MetricPattern31(Generic[T]):
by: _MetricPattern31By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern31By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern31By(c, n)
@property @property
def name(self) -> str: return self._n 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') def emptyaddressindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'emptyaddressindex')
class MetricPattern32(Generic[T]): class MetricPattern32(Generic[T]):
by: _MetricPattern32By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern32By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern32By(c, n)
@property @property
def name(self) -> str: return self._n 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') def pairoutputindex(self) -> MetricEndpointBuilder[T]: return _ep(self._c, self._n, 'pairoutputindex')
class MetricPattern33(Generic[T]): class MetricPattern33(Generic[T]):
by: _MetricPattern33By[T]
def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern33By(c, n) def __init__(self, c: BrkClientBase, n: str): self._n, self.by = n, _MetricPattern33By(c, n)
@property @property
def name(self) -> str: return self._n 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_blocks_mined: MetricPattern1[StoredU32] = MetricPattern1(client, _m(acc, '24h_blocks_mined'))
self._24h_dominance: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, '24h_dominance')) self._24h_dominance: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, '24h_dominance'))
self.blocks_mined: BlockCountPattern[StoredU32] = BlockCountPattern(client, _m(acc, 'blocks_mined')) 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.coinbase: CoinbasePattern2 = CoinbasePattern2(client, _m(acc, 'coinbase'))
self.days_since_block: MetricPattern4[StoredU16] = MetricPattern4(client, _m(acc, 'days_since_block')) self.days_since_block: MetricPattern4[StoredU16] = MetricPattern4(client, _m(acc, 'days_since_block'))
self.dominance: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'dominance')) self.dominance: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'dominance'))
self.fee: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'fee')) self.fee: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'fee'))
self.subsidy: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'subsidy')) 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]): class LookbackPattern(Generic[T]):
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2016,6 +2073,24 @@ class PeriodLumpSumStackPattern:
self._6y: _2015Pattern = _2015Pattern(client, _p('6y', acc)) self._6y: _2015Pattern = _2015Pattern(client, _p('6y', acc))
self._8y: _2015Pattern = _2015Pattern(client, _p('8y', 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]): class PeriodAveragePricePattern(Generic[T]):
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2034,24 +2109,6 @@ class PeriodAveragePricePattern(Generic[T]):
self._6y: MetricPattern4[T] = MetricPattern4(client, _p('6y', acc)) self._6y: MetricPattern4[T] = MetricPattern4(client, _p('6y', acc))
self._8y: MetricPattern4[T] = MetricPattern4(client, _p('8y', 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: class BitcoinPattern:
"""Pattern struct for repeated tree structure.""" """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_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')) 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]): class CountPattern2(Generic[T]):
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2149,21 +2190,6 @@ class AddrCountPattern:
self.p2wpkh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wpkh', acc)) self.p2wpkh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wpkh', acc))
self.p2wsh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wsh', 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]): class FeeRatePattern(Generic[T]):
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2179,6 +2205,21 @@ class FeeRatePattern(Generic[T]):
self.pct90: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct90')) self.pct90: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct90'))
self.txindex: MetricPattern27[T] = MetricPattern27(client, acc) 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: class _0satsPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2207,18 +2248,18 @@ class PhaseDailyCentsPattern(Generic[T]):
self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75'))
self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90'))
class _10yTo12yPattern: class PeriodCagrPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name.""" """Create pattern node with accumulated metric name."""
self.activity: ActivityPattern2 = ActivityPattern2(client, acc) self._10y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('10y', acc))
self.cost_basis: CostBasisPattern2 = CostBasisPattern2(client, acc) self._2y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('2y', acc))
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) self._3y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('3y', acc))
self.realized: RealizedPattern2 = RealizedPattern2(client, acc) self._4y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('4y', acc))
self.relative: RelativePattern2 = RelativePattern2(client, acc) self._5y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('5y', acc))
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('6y', acc))
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('8y', acc))
class UnrealizedPattern: class UnrealizedPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2242,11 +2283,11 @@ class _0satsPattern2:
self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc)
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count'))
self.realized: RealizedPattern = RealizedPattern(client, acc) 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.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
class _100btcPattern: class _0Pattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -2259,19 +2300,6 @@ class _100btcPattern:
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) 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: class _10yPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2285,6 +2313,30 @@ class _10yPattern:
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) 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: class ActivityPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2306,15 +2358,6 @@ class SplitPattern2(Generic[T]):
self.low: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'low')) self.low: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'low'))
self.open: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'open')) 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: class UnclaimedRewardsPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2324,42 +2367,6 @@ class UnclaimedRewardsPattern:
self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd'))
self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) 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: class CoinbasePattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2369,29 +2376,50 @@ class CoinbasePattern:
self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd')) self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd'))
self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc) self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc)
class RelativePattern4: class CostBasisPattern2:
"""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:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name.""" """Create pattern node with accumulated metric name."""
self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis'))
self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_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: class SupplyPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2401,6 +2429,22 @@ class SupplyPattern2:
self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved')) self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved'))
self.total: ActiveSupplyPattern = ActiveSupplyPattern(client, acc) 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]): class SatsPattern(Generic[T]):
"""Pattern struct for repeated tree structure.""" """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.ohlc: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'ohlc_sats'))
self.split: SplitPattern2[T] = SplitPattern2(client, _m(acc, '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]): class BlockCountPattern(Generic[T]):
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2425,6 +2461,14 @@ class BlockCountPattern(Generic[T]):
self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative'))
self.sum: MetricPattern1[T] = MetricPattern1(client, acc) 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: class OutputsPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2842,47 +2886,47 @@ class MetricsTree_Distribution_UtxoCohorts_Epoch:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self._0: _0satsPattern2 = _0satsPattern2(client, 'epoch_0') self._0: _0Pattern = _0Pattern(client, 'epoch_0')
self._1: _0satsPattern2 = _0satsPattern2(client, 'epoch_1') self._1: _0Pattern = _0Pattern(client, 'epoch_1')
self._2: _0satsPattern2 = _0satsPattern2(client, 'epoch_2') self._2: _0Pattern = _0Pattern(client, 'epoch_2')
self._3: _0satsPattern2 = _0satsPattern2(client, 'epoch_3') self._3: _0Pattern = _0Pattern(client, 'epoch_3')
self._4: _0satsPattern2 = _0satsPattern2(client, 'epoch_4') self._4: _0Pattern = _0Pattern(client, 'epoch_4')
class MetricsTree_Distribution_UtxoCohorts_GeAmount: class MetricsTree_Distribution_UtxoCohorts_GeAmount:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self._100btc: _100btcPattern = _100btcPattern(client, 'utxos_above_100btc') self._100btc: _0Pattern = _0Pattern(client, 'utxos_above_100btc')
self._100k_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_100k_sats') self._100k_sats: _0Pattern = _0Pattern(client, 'utxos_above_100k_sats')
self._100sats: _100btcPattern = _100btcPattern(client, 'utxos_above_100sats') self._100sats: _0Pattern = _0Pattern(client, 'utxos_above_100sats')
self._10btc: _100btcPattern = _100btcPattern(client, 'utxos_above_10btc') self._10btc: _0Pattern = _0Pattern(client, 'utxos_above_10btc')
self._10k_btc: _100btcPattern = _100btcPattern(client, 'utxos_above_10k_btc') self._10k_btc: _0Pattern = _0Pattern(client, 'utxos_above_10k_btc')
self._10k_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_10k_sats') self._10k_sats: _0Pattern = _0Pattern(client, 'utxos_above_10k_sats')
self._10m_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_10m_sats') self._10m_sats: _0Pattern = _0Pattern(client, 'utxos_above_10m_sats')
self._10sats: _100btcPattern = _100btcPattern(client, 'utxos_above_10sats') self._10sats: _0Pattern = _0Pattern(client, 'utxos_above_10sats')
self._1btc: _100btcPattern = _100btcPattern(client, 'utxos_above_1btc') self._1btc: _0Pattern = _0Pattern(client, 'utxos_above_1btc')
self._1k_btc: _100btcPattern = _100btcPattern(client, 'utxos_above_1k_btc') self._1k_btc: _0Pattern = _0Pattern(client, 'utxos_above_1k_btc')
self._1k_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_1k_sats') self._1k_sats: _0Pattern = _0Pattern(client, 'utxos_above_1k_sats')
self._1m_sats: _100btcPattern = _100btcPattern(client, 'utxos_above_1m_sats') self._1m_sats: _0Pattern = _0Pattern(client, 'utxos_above_1m_sats')
self._1sat: _100btcPattern = _100btcPattern(client, 'utxos_above_1sat') self._1sat: _0Pattern = _0Pattern(client, 'utxos_above_1sat')
class MetricsTree_Distribution_UtxoCohorts_LtAmount: class MetricsTree_Distribution_UtxoCohorts_LtAmount:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self._100btc: _100btcPattern = _100btcPattern(client, 'utxos_under_100btc') self._100btc: _0Pattern = _0Pattern(client, 'utxos_under_100btc')
self._100k_btc: _100btcPattern = _100btcPattern(client, 'utxos_under_100k_btc') self._100k_btc: _0Pattern = _0Pattern(client, 'utxos_under_100k_btc')
self._100k_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_100k_sats') self._100k_sats: _0Pattern = _0Pattern(client, 'utxos_under_100k_sats')
self._100sats: _100btcPattern = _100btcPattern(client, 'utxos_under_100sats') self._100sats: _0Pattern = _0Pattern(client, 'utxos_under_100sats')
self._10btc: _100btcPattern = _100btcPattern(client, 'utxos_under_10btc') self._10btc: _0Pattern = _0Pattern(client, 'utxos_under_10btc')
self._10k_btc: _100btcPattern = _100btcPattern(client, 'utxos_under_10k_btc') self._10k_btc: _0Pattern = _0Pattern(client, 'utxos_under_10k_btc')
self._10k_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_10k_sats') self._10k_sats: _0Pattern = _0Pattern(client, 'utxos_under_10k_sats')
self._10m_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_10m_sats') self._10m_sats: _0Pattern = _0Pattern(client, 'utxos_under_10m_sats')
self._10sats: _100btcPattern = _100btcPattern(client, 'utxos_under_10sats') self._10sats: _0Pattern = _0Pattern(client, 'utxos_under_10sats')
self._1btc: _100btcPattern = _100btcPattern(client, 'utxos_under_1btc') self._1btc: _0Pattern = _0Pattern(client, 'utxos_under_1btc')
self._1k_btc: _100btcPattern = _100btcPattern(client, 'utxos_under_1k_btc') self._1k_btc: _0Pattern = _0Pattern(client, 'utxos_under_1k_btc')
self._1k_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_1k_sats') self._1k_sats: _0Pattern = _0Pattern(client, 'utxos_under_1k_sats')
self._1m_sats: _100btcPattern = _100btcPattern(client, 'utxos_under_1m_sats') self._1m_sats: _0Pattern = _0Pattern(client, 'utxos_under_1m_sats')
class MetricsTree_Distribution_UtxoCohorts_MaxAge: class MetricsTree_Distribution_UtxoCohorts_MaxAge:
"""Metrics tree node.""" """Metrics tree node."""
@@ -2911,24 +2955,24 @@ class MetricsTree_Distribution_UtxoCohorts_MinAge:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self._10y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_10y_old') self._10y: _0Pattern = _0Pattern(client, 'utxos_at_least_10y_old')
self._12y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_12y_old') self._12y: _0Pattern = _0Pattern(client, 'utxos_at_least_12y_old')
self._1d: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1d_old') self._1d: _0Pattern = _0Pattern(client, 'utxos_at_least_1d_old')
self._1m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1m_old') self._1m: _0Pattern = _0Pattern(client, 'utxos_at_least_1m_old')
self._1w: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1w_old') self._1w: _0Pattern = _0Pattern(client, 'utxos_at_least_1w_old')
self._1y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_1y_old') self._1y: _0Pattern = _0Pattern(client, 'utxos_at_least_1y_old')
self._2m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_2m_old') self._2m: _0Pattern = _0Pattern(client, 'utxos_at_least_2m_old')
self._2y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_2y_old') self._2y: _0Pattern = _0Pattern(client, 'utxos_at_least_2y_old')
self._3m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_3m_old') self._3m: _0Pattern = _0Pattern(client, 'utxos_at_least_3m_old')
self._3y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_3y_old') self._3y: _0Pattern = _0Pattern(client, 'utxos_at_least_3y_old')
self._4m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_4m_old') self._4m: _0Pattern = _0Pattern(client, 'utxos_at_least_4m_old')
self._4y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_4y_old') self._4y: _0Pattern = _0Pattern(client, 'utxos_at_least_4y_old')
self._5m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_5m_old') self._5m: _0Pattern = _0Pattern(client, 'utxos_at_least_5m_old')
self._5y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_5y_old') self._5y: _0Pattern = _0Pattern(client, 'utxos_at_least_5y_old')
self._6m: _100btcPattern = _100btcPattern(client, 'utxos_at_least_6m_old') self._6m: _0Pattern = _0Pattern(client, 'utxos_at_least_6m_old')
self._6y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_6y_old') self._6y: _0Pattern = _0Pattern(client, 'utxos_at_least_6y_old')
self._7y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_7y_old') self._7y: _0Pattern = _0Pattern(client, 'utxos_at_least_7y_old')
self._8y: _100btcPattern = _100btcPattern(client, 'utxos_at_least_8y_old') self._8y: _0Pattern = _0Pattern(client, 'utxos_at_least_8y_old')
class MetricsTree_Distribution_UtxoCohorts_Term_Long: class MetricsTree_Distribution_UtxoCohorts_Term_Long:
"""Metrics tree node.""" """Metrics tree node."""
@@ -2965,40 +3009,40 @@ class MetricsTree_Distribution_UtxoCohorts_Type:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.empty: _0satsPattern2 = _0satsPattern2(client, 'empty_outputs') self.empty: _0Pattern = _0Pattern(client, 'empty_outputs')
self.p2a: _0satsPattern2 = _0satsPattern2(client, 'p2a') self.p2a: _0Pattern = _0Pattern(client, 'p2a')
self.p2ms: _0satsPattern2 = _0satsPattern2(client, 'p2ms') self.p2ms: _0Pattern = _0Pattern(client, 'p2ms')
self.p2pk33: _0satsPattern2 = _0satsPattern2(client, 'p2pk33') self.p2pk33: _0Pattern = _0Pattern(client, 'p2pk33')
self.p2pk65: _0satsPattern2 = _0satsPattern2(client, 'p2pk65') self.p2pk65: _0Pattern = _0Pattern(client, 'p2pk65')
self.p2pkh: _0satsPattern2 = _0satsPattern2(client, 'p2pkh') self.p2pkh: _0Pattern = _0Pattern(client, 'p2pkh')
self.p2sh: _0satsPattern2 = _0satsPattern2(client, 'p2sh') self.p2sh: _0Pattern = _0Pattern(client, 'p2sh')
self.p2tr: _0satsPattern2 = _0satsPattern2(client, 'p2tr') self.p2tr: _0Pattern = _0Pattern(client, 'p2tr')
self.p2wpkh: _0satsPattern2 = _0satsPattern2(client, 'p2wpkh') self.p2wpkh: _0Pattern = _0Pattern(client, 'p2wpkh')
self.p2wsh: _0satsPattern2 = _0satsPattern2(client, 'p2wsh') self.p2wsh: _0Pattern = _0Pattern(client, 'p2wsh')
self.unknown: _0satsPattern2 = _0satsPattern2(client, 'unknown_outputs') self.unknown: _0Pattern = _0Pattern(client, 'unknown_outputs')
class MetricsTree_Distribution_UtxoCohorts_Year: class MetricsTree_Distribution_UtxoCohorts_Year:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self._2009: _0satsPattern2 = _0satsPattern2(client, 'year_2009') self._2009: _0Pattern = _0Pattern(client, 'year_2009')
self._2010: _0satsPattern2 = _0satsPattern2(client, 'year_2010') self._2010: _0Pattern = _0Pattern(client, 'year_2010')
self._2011: _0satsPattern2 = _0satsPattern2(client, 'year_2011') self._2011: _0Pattern = _0Pattern(client, 'year_2011')
self._2012: _0satsPattern2 = _0satsPattern2(client, 'year_2012') self._2012: _0Pattern = _0Pattern(client, 'year_2012')
self._2013: _0satsPattern2 = _0satsPattern2(client, 'year_2013') self._2013: _0Pattern = _0Pattern(client, 'year_2013')
self._2014: _0satsPattern2 = _0satsPattern2(client, 'year_2014') self._2014: _0Pattern = _0Pattern(client, 'year_2014')
self._2015: _0satsPattern2 = _0satsPattern2(client, 'year_2015') self._2015: _0Pattern = _0Pattern(client, 'year_2015')
self._2016: _0satsPattern2 = _0satsPattern2(client, 'year_2016') self._2016: _0Pattern = _0Pattern(client, 'year_2016')
self._2017: _0satsPattern2 = _0satsPattern2(client, 'year_2017') self._2017: _0Pattern = _0Pattern(client, 'year_2017')
self._2018: _0satsPattern2 = _0satsPattern2(client, 'year_2018') self._2018: _0Pattern = _0Pattern(client, 'year_2018')
self._2019: _0satsPattern2 = _0satsPattern2(client, 'year_2019') self._2019: _0Pattern = _0Pattern(client, 'year_2019')
self._2020: _0satsPattern2 = _0satsPattern2(client, 'year_2020') self._2020: _0Pattern = _0Pattern(client, 'year_2020')
self._2021: _0satsPattern2 = _0satsPattern2(client, 'year_2021') self._2021: _0Pattern = _0Pattern(client, 'year_2021')
self._2022: _0satsPattern2 = _0satsPattern2(client, 'year_2022') self._2022: _0Pattern = _0Pattern(client, 'year_2022')
self._2023: _0satsPattern2 = _0satsPattern2(client, 'year_2023') self._2023: _0Pattern = _0Pattern(client, 'year_2023')
self._2024: _0satsPattern2 = _0satsPattern2(client, 'year_2024') self._2024: _0Pattern = _0Pattern(client, 'year_2024')
self._2025: _0satsPattern2 = _0satsPattern2(client, 'year_2025') self._2025: _0Pattern = _0Pattern(client, 'year_2025')
self._2026: _0satsPattern2 = _0satsPattern2(client, 'year_2026') self._2026: _0Pattern = _0Pattern(client, 'year_2026')
class MetricsTree_Distribution_UtxoCohorts: class MetricsTree_Distribution_UtxoCohorts:
"""Metrics tree node.""" """Metrics tree node."""
@@ -3282,22 +3326,22 @@ class MetricsTree_Market_Ath:
self.price_drawdown: MetricPattern3[StoredF32] = MetricPattern3(client, 'price_drawdown') self.price_drawdown: MetricPattern3[StoredF32] = MetricPattern3(client, 'price_drawdown')
self.years_since_price_ath: MetricPattern4[StoredF32] = MetricPattern4(client, 'years_since_price_ath') 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.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self._2015: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2015_average_price') self._2015: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2015_returns')
self._2016: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2016_average_price') self._2016: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2016_returns')
self._2017: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2017_average_price') self._2017: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2017_returns')
self._2018: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2018_average_price') self._2018: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2018_returns')
self._2019: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2019_average_price') self._2019: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2019_returns')
self._2020: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2020_average_price') self._2020: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2020_returns')
self._2021: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2021_average_price') self._2021: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2021_returns')
self._2022: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2022_average_price') self._2022: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2022_returns')
self._2023: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2023_average_price') self._2023: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2023_returns')
self._2024: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2024_average_price') self._2024: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2024_returns')
self._2025: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2025_average_price') self._2025: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2025_returns')
self._2026: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2026_average_price') self._2026: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2026_returns')
class MetricsTree_Market_Dca_ClassStack: class MetricsTree_Market_Dca_ClassStack:
"""Metrics tree node.""" """Metrics tree node."""
@@ -3320,8 +3364,8 @@ class MetricsTree_Market_Dca:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.class_average_price: MetricsTree_Market_Dca_ClassAveragePrice = MetricsTree_Market_Dca_ClassAveragePrice(client) self.class_average_price: ClassAveragePricePattern[Dollars] = ClassAveragePricePattern(client, 'dca_class')
self.class_returns: ClassAveragePricePattern[StoredF32] = 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.class_stack: MetricsTree_Market_Dca_ClassStack = MetricsTree_Market_Dca_ClassStack(client)
self.period_average_price: PeriodAveragePricePattern[Dollars] = PeriodAveragePricePattern(client, 'dca_average_price') self.period_average_price: PeriodAveragePricePattern[Dollars] = PeriodAveragePricePattern(client, 'dca_average_price')
self.period_cagr: PeriodCagrPattern = PeriodCagrPattern(client, 'dca_cagr') self.period_cagr: PeriodCagrPattern = PeriodCagrPattern(client, 'dca_cagr')
+3 -1
View File
@@ -3,7 +3,7 @@ name = "brk-client"
version = "0.1.0-alpha.6" version = "0.1.0-alpha.6"
description = "Python client for the Bitcoin Research Kit" description = "Python client for the Bitcoin Research Kit"
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.9"
license = "MIT" license = "MIT"
keywords = ["bitcoin", "blockchain", "analytics", "on-chain"] keywords = ["bitcoin", "blockchain", "analytics", "on-chain"]
classifiers = [ classifiers = [
@@ -11,6 +11,8 @@ classifiers = [
"Intended Audience :: Developers", "Intended Audience :: Developers",
"License :: OSI Approved :: MIT License", "License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.13",
+52 -19
View File
@@ -67,32 +67,65 @@ function getLightDarkValue(property) {
return dark ? _dark : light; 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 = { export const colors = {
default: createColor(() => getLightDarkValue("--color")), default: createColor(() => getLightDarkValue("--color")),
gray: createColor(() => getColor("gray")), gray: createColor(() => getColor("gray")),
border: createColor(() => getLightDarkValue("--border-color")), border: createColor(() => getLightDarkValue("--border-color")),
red: createColor(() => getColor("red")), red,
orange: createColor(() => getColor("orange")), orange,
amber: createColor(() => getColor("amber")), amber,
yellow: createColor(() => getColor("yellow")), yellow,
avocado: createColor(() => getColor("avocado")), avocado,
lime: createColor(() => getColor("lime")), lime,
green: createColor(() => getColor("green")), green,
emerald: createColor(() => getColor("emerald")), emerald,
teal: createColor(() => getColor("teal")), teal,
cyan: createColor(() => getColor("cyan")), cyan,
sky: createColor(() => getColor("sky")), sky,
blue: createColor(() => getColor("blue")), blue,
indigo: createColor(() => getColor("indigo")), indigo,
violet: createColor(() => getColor("violet")), violet,
purple: createColor(() => getColor("purple")), purple,
fuchsia: createColor(() => getColor("fuchsia")), fuchsia,
pink: createColor(() => getColor("pink")), pink,
rose: createColor(() => getColor("rose")), 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 {typeof colors} Colors
* @typedef {keyof Colors} ColorName * @typedef {Exclude<keyof Colors, "stat">} ColorName
*/ */
+14 -4
View File
@@ -219,6 +219,10 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
? initialRange.to - initialRange.from ? initialRange.to - initialRange.from
: Infinity; : Infinity;
/** @param {number} count */
const getDotsRadius = (count) =>
count > 1000 ? 1 : count > 200 ? 1.5 : count > 100 ? 2 : 3;
/** @type {Set<ZoomChangeCallback>} */ /** @type {Set<ZoomChangeCallback>} */
const onZoomChange = new Set(); const onZoomChange = new Set();
@@ -1023,11 +1027,12 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
let active = defaultActive !== false; let active = defaultActive !== false;
let highlighted = true; let highlighted = true;
const showLastValue = options?.lastValueVisible !== false;
function update() { function update() {
iseries.applyOptions({ iseries.applyOptions({
visible: active, visible: active,
lastValueVisible: highlighted, lastValueVisible: showLastValue && highlighted,
color: color.highlight(highlighted), color: color.highlight(highlighted),
}); });
} }
@@ -1117,21 +1122,21 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
let active = defaultActive !== false; let active = defaultActive !== false;
let highlighted = true; let highlighted = true;
let radius = let radius = getDotsRadius(visibleBarsCount);
visibleBarsCount > 1000 ? 1 : visibleBarsCount > 200 ? 1.5 : 2;
function update() { function update() {
iseries.applyOptions({ iseries.applyOptions({
visible: active, visible: active,
lastValueVisible: highlighted, lastValueVisible: highlighted,
color: color.highlight(highlighted), color: color.highlight(highlighted),
pointMarkersRadius: radius,
}); });
} }
update(); update();
/** @type {ZoomChangeCallback} */ /** @type {ZoomChangeCallback} */
function handleZoom(count) { function handleZoom(count) {
const newRadius = count > 1000 ? 1 : count > 200 ? 1.5 : 2; const newRadius = getDotsRadius(count);
if (newRadius === radius) return; if (newRadius === radius) return;
radius = newRadius; radius = newRadius;
iseries.applyOptions({ pointMarkersRadius: radius }); iseries.applyOptions({ pointMarkersRadius: radius });
@@ -1507,8 +1512,13 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
} }
const defaultUnit = units[0]; const defaultUnit = units[0];
const sortedUnitIds = units
.map((u) => u.id)
.sort()
.join(",");
const persistedUnit = createPersistedValue({ const persistedUnit = createPersistedValue({
defaultValue: /** @type {string} */ (defaultUnit.id), defaultValue: /** @type {string} */ (defaultUnit.id),
storageKey: `unit-${sortedUnitIds}`,
urlKey: paneIndex === 0 ? "u0" : "u1", urlKey: paneIndex === 0 ? "u0" : "u1",
serialize: (v) => v, serialize: (v) => v,
deserialize: (s) => s, deserialize: (s) => s,
+238 -209
View File
@@ -33,6 +33,7 @@ export function createChainSection(ctx) {
market, market,
scripts, scripts,
supply, supply,
distribution,
} = brk.metrics; } = brk.metrics;
// Build pools tree dynamically // Build pools tree dynamically
@@ -49,10 +50,10 @@ export function createChainSection(ctx) {
name: "Dominance", name: "Dominance",
title: `${poolName} Dominance`, title: `${poolName} Dominance`,
bottom: [ bottom: [
line({ dots({
metric: pool._24hDominance, metric: pool._24hDominance,
name: "24h", name: "24h",
color: colors.orange, color: colors.pink,
unit: Unit.percentage, unit: Unit.percentage,
defaultActive: false, defaultActive: false,
}), }),
@@ -88,7 +89,7 @@ export function createChainSection(ctx) {
name: "Blocks mined", name: "Blocks mined",
title: `${poolName} Blocks`, title: `${poolName} Blocks`,
bottom: [ bottom: [
line({ dots({
metric: pool.blocksMined.sum, metric: pool.blocksMined.sum,
name: "Sum", name: "Sum",
unit: Unit.count, unit: Unit.count,
@@ -98,6 +99,14 @@ export function createChainSection(ctx) {
name: "Cumulative", name: "Cumulative",
color: colors.blue, color: colors.blue,
unit: Unit.count, unit: Unit.count,
defaultActive: false,
}),
line({
metric: pool._24hBlocksMined,
name: "24h Sum",
color: colors.pink,
unit: Unit.count,
defaultActive: false,
}), }),
line({ line({
metric: pool._1wBlocksMined, metric: pool._1wBlocksMined,
@@ -142,12 +151,17 @@ export function createChainSection(ctx) {
], ],
}, },
{ {
name: "Days since block", name: "Since last block",
title: `${poolName} Last Block`, title: `${poolName} Since Last Block`,
bottom: [ bottom: [
line({
metric: pool.blocksSinceBlock,
name: "Blocks",
unit: Unit.count,
}),
line({ line({
metric: pool.daysSinceBlock, metric: pool.daysSinceBlock,
name: "Since block", name: "Days",
unit: Unit.days, unit: Unit.days,
}), }),
], ],
@@ -227,12 +241,35 @@ export function createChainSection(ctx) {
title: "Transaction Count", title: "Transaction Count",
bottom: fromDollarsPattern(transactions.count.txCount, Unit.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", name: "Volume",
title: "Transaction Volume", title: "Transaction Volume",
bottom: [ bottom: [
...satsBtcUsd(transactions.volume.sentSum, "Sent"), ...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, defaultActive: false,
}), }),
line({ line({
@@ -242,13 +279,6 @@ export function createChainSection(ctx) {
unit: Unit.sats, unit: Unit.sats,
defaultActive: false, defaultActive: false,
}), }),
line({
metric: transactions.volume.annualizedVolume.bitcoin,
name: "annualized",
color: colors.red,
unit: Unit.btc,
defaultActive: false,
}),
line({ line({
metric: transactions.volume.annualizedVolume.dollars, metric: transactions.volume.annualizedVolume.dollars,
name: "annualized", name: "annualized",
@@ -266,6 +296,11 @@ export function createChainSection(ctx) {
...fromFeeRatePattern(transactions.size.vsize, Unit.vb), ...fromFeeRatePattern(transactions.size.vsize, Unit.vb),
], ],
}, },
{
name: "Fee Rate",
title: "Fee Rate",
bottom: fromFeeRatePattern(transactions.fees.feeRate, Unit.feeRate),
},
{ {
name: "Versions", name: "Versions",
title: "Transaction 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", title: "Output Count",
bottom: [...fromSizePattern(outputs.count.totalCount, Unit.count)], bottom: [...fromSizePattern(outputs.count.totalCount, Unit.count)],
}, },
{
name: "OP_RETURN",
title: "OP_RETURN Outputs",
bottom: fromFullnessPattern(scripts.count.opreturn, Unit.count),
},
{ {
name: "Speed", name: "Speed",
title: "Outputs Per Second", title: "Outputs Per Second",
@@ -387,70 +416,99 @@ export function createChainSection(ctx) {
], ],
}, },
// Coinbase // Supply
{ {
name: "Coinbase", name: "Supply",
title: "Coinbase Rewards", tree: [
bottom: fromCoinbasePattern(blocks.rewards.coinbase, "Coinbase"), {
}, name: "Circulating",
title: "Circulating Supply",
// Subsidy bottom: fromSupplyPattern(supply.circulating, "Supply"),
{ },
name: "Subsidy", {
title: "Block Subsidy", name: "Inflation",
bottom: [ title: "Inflation Rate",
...fromCoinbasePattern(blocks.rewards.subsidy, "Subsidy"), bottom: [
line({ dots({
metric: blocks.rewards.subsidyDominance, metric: supply.inflation,
name: "Dominance", name: "Rate",
color: colors.purple, unit: Unit.percentage,
unit: Unit.percentage, }),
defaultActive: false, ],
}), },
{
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: [ 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", title: "Transaction Fees",
bottom: [ 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({ line({
metric: transactions.fees.fee.bitcoin.sum, metric: transactions.fees.fee.bitcoin.sum,
name: "Sum", name: "sum",
unit: Unit.btc, unit: Unit.btc,
}), }),
line({ line({
metric: transactions.fees.fee.bitcoin.cumulative, metric: transactions.fees.fee.bitcoin.cumulative,
name: "Cumulative", name: "cumulative",
color: colors.blue, color: colors.stat.cumulative,
unit: Unit.btc, unit: Unit.btc,
defaultActive: false, 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({ line({
metric: transactions.fees.fee.dollars.sum, metric: transactions.fees.fee.dollars.sum,
name: "Sum", name: "sum",
unit: Unit.usd, unit: Unit.usd,
}), }),
line({ line({
metric: transactions.fees.fee.dollars.cumulative, metric: transactions.fees.fee.dollars.cumulative,
name: "Cumulative", name: "cumulative",
color: colors.blue, color: colors.stat.cumulative,
unit: Unit.usd, unit: Unit.usd,
defaultActive: false, defaultActive: false,
}), }),
@@ -464,64 +522,98 @@ export function createChainSection(ctx) {
], ],
}, },
{ {
name: "Rate", name: "Unclaimed",
title: "Fee Rate", title: "Unclaimed Rewards",
bottom: [ bottom: fromValuePattern(
line({ blocks.rewards.unclaimedRewards,
metric: transactions.fees.feeRate.median, "Unclaimed",
name: "Median", ),
color: colors.purple, },
unit: Unit.feeRate, ],
}), },
line({
metric: transactions.fees.feeRate.average, // Addresses
name: "Average", {
color: colors.blue, name: "Addresses",
unit: Unit.feeRate, tree: [
defaultActive: false, {
}), name: "Count",
line({ tree: [
metric: transactions.fees.feeRate.min, {
name: "Min", name: "All",
color: colors.red, title: "Total Address Count",
unit: Unit.feeRate, bottom: [
defaultActive: false, line({
}), metric: distribution.addrCount.all,
line({ name: "Loaded",
metric: transactions.fees.feeRate.max, unit: Unit.count,
name: "Max", }),
color: colors.green, line({
unit: Unit.feeRate, metric: distribution.emptyAddrCount.all,
defaultActive: false, name: "Empty",
}), color: colors.gray,
line({ unit: Unit.count,
metric: transactions.fees.feeRate.pct10, defaultActive: false,
name: "pct10", }),
color: colors.rose, ],
unit: Unit.feeRate, },
defaultActive: false, {
}), name: "By Type",
line({ title: "Address Count by Type",
metric: transactions.fees.feeRate.pct25, bottom: [
name: "pct25", line({
color: colors.pink, metric: distribution.addrCount.p2pkh,
unit: Unit.feeRate, name: "P2PKH",
defaultActive: false, color: colors.orange,
}), unit: Unit.count,
line({ }),
metric: transactions.fees.feeRate.pct75, line({
name: "pct75", metric: distribution.addrCount.p2sh,
color: colors.violet, name: "P2SH",
unit: Unit.feeRate, color: colors.yellow,
defaultActive: false, unit: Unit.count,
}), }),
line({ line({
metric: transactions.fees.feeRate.pct90, metric: distribution.addrCount.p2wpkh,
name: "pct90", name: "P2WPKH",
color: colors.fuchsia, color: colors.green,
unit: Unit.feeRate, unit: Unit.count,
defaultActive: false, }),
}), 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, unit: Unit.hashRate,
defaultActive: false, 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", name: "Difficulty",
unit: Unit.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({ line({
metric: blocks.difficulty.blocksBeforeNextAdjustment, metric: blocks.difficulty.blocksBeforeNextAdjustment,
name: "Blocks until adj.", name: "before next",
color: colors.indigo, color: colors.indigo,
unit: Unit.blocks, unit: Unit.blocks,
defaultActive: false,
}), }),
line({ line({
metric: blocks.difficulty.daysBeforeNextAdjustment, metric: blocks.difficulty.daysBeforeNextAdjustment,
name: "Days until adj.", name: "before next",
color: colors.purple, color: colors.purple,
unit: Unit.days, unit: Unit.days,
defaultActive: false,
}), }),
], ],
}, },
@@ -619,6 +701,7 @@ export function createChainSection(ctx) {
name: "Difficulty Change", name: "Difficulty Change",
unit: Unit.percentage, unit: Unit.percentage,
}), }),
priceLine({ ctx, number: 0, unit: Unit.percentage }),
], ],
}, },
{ {
@@ -701,23 +784,22 @@ export function createChainSection(ctx) {
name: "Halving", name: "Halving",
title: "Halving", title: "Halving",
bottom: [ 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({ line({
metric: blocks.halving.epoch, metric: blocks.halving.epoch,
name: "Epoch", name: "Epoch",
color: colors.purple, color: colors.purple,
unit: Unit.epoch, 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", name: "Puell Multiple",
title: "Puell Multiple", title: "Puell Multiple",
bottom: [ bottom: [
line({ baseline({
metric: market.indicators.puellMultiple, metric: market.indicators.puellMultiple,
name: "Puell Multiple", name: "Puell Multiple",
unit: Unit.ratio, unit: Unit.ratio,
base: 1,
}), }),
priceLine({ ctx, unit: Unit.ratio, number: 1 }), priceLine({ ctx, unit: Unit.ratio, number: 1 }),
], ],
@@ -741,60 +824,6 @@ export function createChainSection(ctx) {
name: "Pools", name: "Pools",
tree: poolsTree, 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"),
},
], ],
}; };
} }
+31 -4
View File
@@ -6,7 +6,8 @@ import {
percentileUsdMap, percentileUsdMap,
percentileMap, percentileMap,
sdPatterns, sdPatterns,
sdBands, sdBandsUsd,
sdBandsRatio,
} from "./shared.js"; } from "./shared.js";
/** /**
@@ -56,8 +57,8 @@ function createCointimePriceWithRatioOptions(
baseline({ baseline({
metric: ratio.ratio, metric: ratio.ratio,
name: "Ratio", name: "Ratio",
color,
unit: Unit.ratio, unit: Unit.ratio,
base: 1,
}), }),
line({ line({
metric: ratio.ratio1wSma, metric: ratio.ratio1wSma,
@@ -191,7 +192,7 @@ function createCointimePriceWithRatioOptions(
title: `${title} ${titleAddon} Z-Score`, title: `${title} ${titleAddon} Z-Score`,
top: [ top: [
line({ metric: price, name: legend, color, unit: Unit.usd }), line({ metric: price, name: legend, color, unit: Unit.usd }),
...sdBands(colors, sd).map( ...sdBandsUsd(colors, sd).map(
({ name: bandName, prop, color: bandColor }) => ({ name: bandName, prop, color: bandColor }) =>
line({ line({
metric: prop, metric: prop,
@@ -203,7 +204,33 @@ function createCointimePriceWithRatioOptions(
), ),
], ],
bottom: [ 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({ ...priceLines({
ctx, ctx,
unit: Unit.sd, unit: Unit.sd,
+21 -2
View File
@@ -15,35 +15,51 @@ import {
} from "./series.js"; } from "./series.js";
import { colors } from "../chart/colors.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<typeof createContext>} PartialContext */
/** /**
* Create a context object with all dependencies for building partial options * Create a context object with all dependencies for building partial options
* @param {Object} args * @param {Object} args
* @param {BrkClient} args.brk * @param {BrkClient} args.brk
* @returns {PartialContext}
*/ */
export function createContext({ brk }) { export function createContext({ brk }) {
return { return {
colors, colors,
brk, brk,
/** @type {OmitFirstArg<typeof fromBlockCount>} */
fromBlockCount: (pattern, title, color) => fromBlockCount: (pattern, title, color) =>
fromBlockCount(colors, pattern, title, color), fromBlockCount(colors, pattern, title, color),
/** @type {OmitFirstArg<typeof fromBitcoin>} */
fromBitcoin: (pattern, title, color) => fromBitcoin: (pattern, title, color) =>
fromBitcoin(colors, pattern, title, color), fromBitcoin(colors, pattern, title, color),
/** @type {OmitFirstArg<typeof fromBlockSize>} */
fromBlockSize: (pattern, title, color) => fromBlockSize: (pattern, title, color) =>
fromBlockSize(colors, pattern, title, color), fromBlockSize(colors, pattern, title, color),
/** @type {OmitFirstArg<typeof fromSizePattern>} */
fromSizePattern: (pattern, unit, title) => fromSizePattern: (pattern, unit, title) =>
fromSizePattern(colors, pattern, unit, title), fromSizePattern(colors, pattern, unit, title),
/** @type {OmitFirstArg<typeof fromFullnessPattern>} */
fromFullnessPattern: (pattern, unit, title) => fromFullnessPattern: (pattern, unit, title) =>
fromFullnessPattern(colors, pattern, unit, title), fromFullnessPattern(colors, pattern, unit, title),
/** @type {OmitFirstArg<typeof fromDollarsPattern>} */
fromDollarsPattern: (pattern, unit, title) => fromDollarsPattern: (pattern, unit, title) =>
fromDollarsPattern(colors, pattern, unit, title), fromDollarsPattern(colors, pattern, unit, title),
/** @type {OmitFirstArg<typeof fromFeeRatePattern>} */
fromFeeRatePattern: (pattern, unit, title) => fromFeeRatePattern: (pattern, unit, title) =>
fromFeeRatePattern(colors, pattern, unit, title), fromFeeRatePattern(colors, pattern, unit, title),
/** @type {OmitFirstArg<typeof fromCoinbasePattern>} */
fromCoinbasePattern: (pattern, title) => fromCoinbasePattern: (pattern, title) =>
fromCoinbasePattern(colors, pattern, title), fromCoinbasePattern(colors, pattern, title),
/** @type {OmitFirstArg<typeof fromValuePattern>} */
fromValuePattern: (pattern, title, sumColor, cumulativeColor) => fromValuePattern: (pattern, title, sumColor, cumulativeColor) =>
fromValuePattern(colors, pattern, title, sumColor, cumulativeColor), fromValuePattern(colors, pattern, title, sumColor, cumulativeColor),
/** @type {OmitFirstArg<typeof fromBitcoinPatternWithUnit>} */
fromBitcoinPatternWithUnit: ( fromBitcoinPatternWithUnit: (
pattern, pattern,
title, title,
@@ -59,6 +75,7 @@ export function createContext({ brk }) {
sumColor, sumColor,
cumulativeColor, cumulativeColor,
), ),
/** @type {OmitFirstArg<typeof fromBlockCountWithUnit>} */
fromBlockCountWithUnit: (pattern, unit, title, sumColor, cumulativeColor) => fromBlockCountWithUnit: (pattern, unit, title, sumColor, cumulativeColor) =>
fromBlockCountWithUnit( fromBlockCountWithUnit(
colors, colors,
@@ -68,9 +85,11 @@ export function createContext({ brk }) {
sumColor, sumColor,
cumulativeColor, cumulativeColor,
), ),
/** @type {OmitFirstArg<typeof fromIntervalPattern>} */
fromIntervalPattern: (pattern, unit, title, color) => fromIntervalPattern: (pattern, unit, title, color) =>
fromIntervalPattern(colors, pattern, unit, title, color), fromIntervalPattern(colors, pattern, unit, title, color),
/** @type {fromSupplyPattern} */
fromSupplyPattern: (pattern, title, color) => fromSupplyPattern: (pattern, title, color) =>
fromSupplyPattern(colors, pattern, title, color), fromSupplyPattern(pattern, title, color),
}; };
} }
@@ -51,7 +51,7 @@ export function createAddressCohortFolder(ctx, args) {
{ {
name: "total", name: "total",
title: `Supply ${title}`, title: `Supply ${title}`,
bottom: createGroupedSupplyTotalSeries(ctx, list), bottom: createGroupedSupplyTotalSeries(list),
}, },
{ {
name: "in profit", name: "in profit",
@@ -23,6 +23,12 @@ const entries = (obj) =>
Object.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 * Build all cohort data from brk tree
* @param {Colors} colors * @param {Colors} colors
@@ -31,6 +37,7 @@ const entries = (obj) =>
export function buildCohortData(colors, brk) { export function buildCohortData(colors, brk) {
const utxoCohorts = brk.metrics.distribution.utxoCohorts; const utxoCohorts = brk.metrics.distribution.utxoCohorts;
const addressCohorts = brk.metrics.distribution.addressCohorts; const addressCohorts = brk.metrics.distribution.addressCohorts;
const { addrCount } = brk.metrics.distribution;
const { const {
TERM_NAMES, TERM_NAMES,
EPOCH_NAMES, EPOCH_NAMES,
@@ -51,6 +58,7 @@ export function buildCohortData(colors, brk) {
title: "", title: "",
color: colors.orange, color: colors.orange,
tree: utxoCohorts.all, tree: utxoCohorts.all,
addrCount: addrCount.all,
}; };
// Term cohorts - split because short is CohortFull, long is CohortWithPercentiles // 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) // Spendable type cohorts - split by addressability
/** @type {readonly CohortBasic[]} */ /** @type {readonly CohortAddress[]} */
const type = entries(utxoCohorts.type).map(([key, tree]) => { const typeAddressable = ADDRESSABLE_TYPES.map((key) => {
const names = SPENDABLE_TYPE_NAMES[key]; const names = SPENDABLE_TYPE_NAMES[key];
return { return {
name: names.short, name: names.short,
title: names.long, title: names.long,
color: colors[spendableTypeColors[key]], 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) // Year cohorts - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */ /** @type {readonly CohortBasic[]} */
const year = entries(utxoCohorts.year).map(([key, tree]) => { const year = entries(utxoCohorts.year).map(([key, tree]) => {
@@ -238,7 +260,8 @@ export function buildCohortData(colors, brk) {
addressesUnderAmount, addressesUnderAmount,
utxosAmountRanges, utxosAmountRanges,
addressesAmountRanges, addressesAmountRanges,
type, typeAddressable,
typeOther,
year, year,
}; };
} }
@@ -12,6 +12,7 @@ export {
createCohortFolderWithAdjusted, createCohortFolderWithAdjusted,
createCohortFolderWithPercentiles, createCohortFolderWithPercentiles,
createCohortFolderBasic, createCohortFolderBasic,
createCohortFolderAddress,
} from "./utxo.js"; } from "./utxo.js";
export { createAddressCohortFolder } from "./address.js"; export { createAddressCohortFolder } from "./address.js";
@@ -2,7 +2,7 @@
import { Unit } from "../../utils/units.js"; import { Unit } from "../../utils/units.js";
import { priceLine } from "../constants.js"; import { priceLine } from "../constants.js";
import { line } from "../series.js"; import { baseline, line } from "../series.js";
import { satsBtcUsd } from "../shared.js"; import { satsBtcUsd } from "../shared.js";
/** /**
@@ -74,25 +74,22 @@ export function createSingleSupplySeries(ctx, cohort) {
/** /**
* Create supply total series for grouped cohorts * Create supply total series for grouped cohorts
* @param {PartialContext} ctx
* @param {readonly CohortObject[]} list * @param {readonly CohortObject[]} list
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function createGroupedSupplyTotalSeries(ctx, list) { export function createGroupedSupplyTotalSeries(list) {
const { brk } = ctx;
const constant100 = brk.metrics.constants.constant100;
return list.flatMap(({ color, name, tree }) => [ return list.flatMap(({ color, name, tree }) => [
...satsBtcUsd(tree.supply.total, name, color), ...satsBtcUsd(tree.supply.total, name, color),
line({ ...("supplyRelToCirculatingSupply" in tree.relative
metric: ? [
"supplyRelToCirculatingSupply" in tree.relative line({
? tree.relative.supplyRelToCirculatingSupply metric: tree.relative.supplyRelToCirculatingSupply,
: constant100, name,
name, color,
color, unit: Unit.pctSupply,
unit: Unit.pctSupply, }),
}), ]
: []),
]); ]);
} }
@@ -194,12 +191,12 @@ export function createRealizedPriceSeries(list) {
*/ */
export function createRealizedPriceRatioSeries(ctx, list) { export function createRealizedPriceRatioSeries(ctx, list) {
return [ return [
...list.map(({ color, name, tree }) => ...list.map(({ name, tree }) =>
line({ baseline({
metric: tree.realized.realizedPriceExtra.ratio, metric: tree.realized.realizedPriceExtra.ratio,
name, name,
color,
unit: Unit.ratio, unit: Unit.ratio,
base: 1,
}), }),
), ),
priceLine({ ctx, unit: Unit.ratio, number: 1 }), priceLine({ ctx, unit: Unit.ratio, number: 1 }),
+26 -4
View File
@@ -7,7 +7,8 @@ import {
percentileUsdMap, percentileUsdMap,
percentileMap, percentileMap,
sdPatterns, sdPatterns,
sdBands, sdBandsUsd,
sdBandsRatio,
} from "../shared.js"; } from "../shared.js";
import { periodIdToName } from "./utils.js"; import { periodIdToName } from "./utils.js";
@@ -90,7 +91,6 @@ export function createPriceWithRatioOptions(
metric: ratio.ratio, metric: ratio.ratio,
name: "Ratio", name: "Ratio",
base: 1, base: 1,
color,
unit: Unit.ratio, unit: Unit.ratio,
}), }),
.../** @type {const} */ ([ .../** @type {const} */ ([
@@ -222,7 +222,7 @@ export function createPriceWithRatioOptions(
title: `${title} ${titleAddon} Z-Score`, title: `${title} ${titleAddon} Z-Score`,
top: [ top: [
line({ metric: priceMetric, name: legend, color, unit: Unit.usd }), line({ metric: priceMetric, name: legend, color, unit: Unit.usd }),
...sdBands(colors, sd).map( ...sdBandsUsd(colors, sd).map(
({ name: bandName, prop, color: bandColor }) => ({ name: bandName, prop, color: bandColor }) =>
line({ line({
metric: prop, metric: prop,
@@ -237,9 +237,31 @@ export function createPriceWithRatioOptions(
baseline({ baseline({
metric: sd.zscore, metric: sd.zscore,
name: "Z-Score", name: "Z-Score",
color,
unit: Unit.sd, 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({ priceLine({
ctx, ctx,
unit: Unit.sd, unit: Unit.sd,
+23 -9
View File
@@ -8,8 +8,9 @@ import {
createCohortFolderWithAdjusted, createCohortFolderWithAdjusted,
createCohortFolderWithPercentiles, createCohortFolderWithPercentiles,
createCohortFolderBasic, createCohortFolderBasic,
createCohortFolderAddress,
createAddressCohortFolder, createAddressCohortFolder,
} from "./cohorts/index.js"; } from "./distribution/index.js";
import { createMarketSection } from "./market/index.js"; import { createMarketSection } from "./market/index.js";
import { createChainSection } from "./chain.js"; import { createChainSection } from "./chain.js";
import { createCointimeSection } from "./cointime.js"; import { createCointimeSection } from "./cointime.js";
@@ -17,6 +18,7 @@ import { colors } from "../chart/colors.js";
// Re-export types for external consumers // Re-export types for external consumers
export * from "./types.js"; export * from "./types.js";
export * from "./context.js";
/** /**
* Create partial options tree * Create partial options tree
@@ -43,17 +45,22 @@ export function createPartialOptions({ brk }) {
addressesUnderAmount, addressesUnderAmount,
utxosAmountRanges, utxosAmountRanges,
addressesAmountRanges, addressesAmountRanges,
type, typeAddressable,
typeOther,
year, year,
} = buildCohortData(colors, brk); } = buildCohortData(colors, brk);
// Helpers to map cohorts by capability type // Helpers to map cohorts by capability type
/** @param {CohortWithAdjusted} cohort */ /** @param {CohortWithAdjusted} cohort */
const mapWithAdjusted = (cohort) => createCohortFolderWithAdjusted(ctx, cohort); const mapWithAdjusted = (cohort) =>
createCohortFolderWithAdjusted(ctx, cohort);
/** @param {CohortWithPercentiles} cohort */ /** @param {CohortWithPercentiles} cohort */
const mapWithPercentiles = (cohort) => createCohortFolderWithPercentiles(ctx, cohort); const mapWithPercentiles = (cohort) =>
createCohortFolderWithPercentiles(ctx, cohort);
/** @param {CohortBasic} cohort */ /** @param {CohortBasic} cohort */
const mapBasic = (cohort) => createCohortFolderBasic(ctx, cohort); const mapBasic = (cohort) => createCohortFolderBasic(ctx, cohort);
/** @param {CohortAddress} cohort */
const mapAddress = (cohort) => createCohortFolderAddress(ctx, cohort);
/** @param {AddressCohortObject} cohort */ /** @param {AddressCohortObject} cohort */
const mapAddressCohorts = (cohort) => createAddressCohortFolder(ctx, cohort); const mapAddressCohorts = (cohort) => createAddressCohortFolder(ctx, cohort);
@@ -81,7 +88,7 @@ export function createPartialOptions({ brk }) {
// Cohorts section // Cohorts section
{ {
name: "Cohorts", name: "Distribution",
tree: [ tree: [
// All UTXOs - CohortAll (adjustedSopr + percentiles but no RelToMarketCap) // All UTXOs - CohortAll (adjustedSopr + percentiles but no RelToMarketCap)
createCohortFolderAll(ctx, cohortAll), createCohortFolderAll(ctx, cohortAll),
@@ -90,22 +97,29 @@ export function createPartialOptions({ brk }) {
{ {
name: "Terms", name: "Terms",
tree: [ tree: [
// Compare folder uses WithPercentiles (common capabilities)
createCohortFolderWithPercentiles(ctx, {
name: "Compare",
title: "Term",
list: [termShort, termLong],
}),
// Individual cohorts with their specific capabilities // Individual cohorts with their specific capabilities
createCohortFolderFull(ctx, termShort), createCohortFolderFull(ctx, termShort),
createCohortFolderWithPercentiles(ctx, termLong), createCohortFolderWithPercentiles(ctx, termLong),
], ],
}, },
// Types - CohortBasic // Types - addressable types have addrCount, others don't
{ {
name: "Types", name: "Types",
tree: [ tree: [
createCohortFolderBasic(ctx, { createCohortFolderAddress(ctx, {
name: "Compare", name: "Compare",
title: "Type", title: "Type",
list: type, list: typeAddressable,
}), }),
...type.map(mapBasic), ...typeAddressable.map(mapAddress),
...typeOther.map(mapBasic),
], ],
}, },
+214 -187
View File
@@ -193,8 +193,8 @@ export function fromBlockCount(colors, pattern, title, color) {
{ metric: pattern.sum, title, color: color ?? colors.default }, { metric: pattern.sum, title, color: color ?? colors.default },
{ {
metric: pattern.cumulative, metric: pattern.cumulative,
title: `${title} (cum.)`, title: `${title} cumulative`,
color: colors.cyan, color: colors.stat.cumulative,
defaultActive: false, defaultActive: false,
}, },
]; ];
@@ -209,49 +209,55 @@ export function fromBlockCount(colors, pattern, title, color) {
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromBitcoin(colors, pattern, title, color) { export function fromBitcoin(colors, pattern, title, color) {
const { stat } = colors;
return [ return [
{ metric: pattern.base, title, color: color ?? colors.default }, { 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, metric: pattern.max,
title: "Max", title: `${title} max`,
color: colors.pink, color: stat.max,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.min, metric: pattern.min,
title: "Min", title: `${title} min`,
color: colors.green, color: stat.min,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.median, metric: pattern.median,
title: "Median", title: `${title} median`,
color: colors.amber, color: stat.median,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct75, metric: pattern.pct75,
title: "pct75", title: `${title} pct75`,
color: colors.red, color: stat.pct75,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct25, metric: pattern.pct25,
title: "pct25", title: `${title} pct25`,
color: colors.yellow, color: stat.pct25,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct90, metric: pattern.pct90,
title: "pct90", title: `${title} pct90`,
color: colors.rose, color: stat.pct90,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct10, metric: pattern.pct10,
title: "pct10", title: `${title} pct10`,
color: colors.lime, color: stat.pct10,
defaultActive: false, defaultActive: false,
}, },
]; ];
@@ -266,55 +272,61 @@ export function fromBitcoin(colors, pattern, title, color) {
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromBlockSize(colors, pattern, title, color) { export function fromBlockSize(colors, pattern, title, color) {
const { stat } = colors;
return [ return [
{ metric: pattern.sum, title, color: color ?? colors.default }, { 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, metric: pattern.cumulative,
title: `Cumulative`, title: `${title} cumulative`,
color: colors.cyan, color: stat.cumulative,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.max, metric: pattern.max,
title: "Max", title: `${title} max`,
color: colors.pink, color: stat.max,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.min, metric: pattern.min,
title: "Min", title: `${title} min`,
color: colors.green, color: stat.min,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.median, metric: pattern.median,
title: "Median", title: `${title} median`,
color: colors.amber, color: stat.median,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct75, metric: pattern.pct75,
title: "pct75", title: `${title} pct75`,
color: colors.red, color: stat.pct75,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct25, metric: pattern.pct25,
title: "pct25", title: `${title} pct25`,
color: colors.yellow, color: stat.pct25,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct90, metric: pattern.pct90,
title: "pct90", title: `${title} pct90`,
color: colors.rose, color: stat.pct90,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct10, metric: pattern.pct10,
title: "pct10", title: `${title} pct10`,
color: colors.lime, color: stat.pct10,
defaultActive: false, defaultActive: false,
}, },
]; ];
@@ -329,68 +341,69 @@ export function fromBlockSize(colors, pattern, title, color) {
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromSizePattern(colors, pattern, unit, title = "") { export function fromSizePattern(colors, pattern, unit, title = "") {
const { stat } = colors;
return [ return [
{ metric: pattern.average, title: `${title} avg`.trim(), unit }, { metric: pattern.average, title: `${title} avg`.trim(), unit },
{ {
metric: pattern.sum, metric: pattern.sum,
title: `${title} sum`.trim(), title: `${title} sum`.trim(),
color: colors.blue, color: stat.sum,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.cumulative, metric: pattern.cumulative,
title: `${title} cumulative`.trim(), title: `${title} cumulative`.trim(),
color: colors.indigo, color: stat.cumulative,
unit,
defaultActive: false,
},
{
metric: pattern.min,
title: `${title} min`.trim(),
color: colors.red,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.max, metric: pattern.max,
title: `${title} max`.trim(), title: `${title} max`.trim(),
color: colors.green, color: stat.max,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct10, metric: pattern.min,
title: `${title} pct10`.trim(), title: `${title} min`.trim(),
color: colors.rose, color: stat.min,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: colors.pink,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.median, metric: pattern.median,
title: `${title} median`.trim(), title: `${title} median`.trim(),
color: colors.purple, color: stat.median,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct75, metric: pattern.pct75,
title: `${title} pct75`.trim(), title: `${title} pct75`.trim(),
color: colors.violet, color: stat.pct75,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: stat.pct25,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct90, metric: pattern.pct90,
title: `${title} pct90`.trim(), title: `${title} pct90`.trim(),
color: colors.fuchsia, color: stat.pct90,
unit,
defaultActive: false,
},
{
metric: pattern.pct10,
title: `${title} pct10`.trim(),
color: stat.pct10,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
@@ -406,61 +419,61 @@ export function fromSizePattern(colors, pattern, unit, title = "") {
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromFullnessPattern(colors, pattern, unit, title = "") { export function fromFullnessPattern(colors, pattern, unit, title = "") {
const { stat } = colors;
return [ return [
{ metric: pattern.base, title: title || "base", unit }, { metric: pattern.base, title: title || "base", unit },
{ {
metric: pattern.average, metric: pattern.average,
title: `${title} avg`.trim(), title: `${title} avg`.trim(),
color: colors.purple, color: stat.avg,
unit,
},
{
metric: pattern.max,
title: `${title} max`.trim(),
color: stat.max,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.min, metric: pattern.min,
title: `${title} min`.trim(), title: `${title} min`.trim(),
color: colors.red, color: stat.min,
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,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.median, metric: pattern.median,
title: `${title} median`.trim(), title: `${title} median`.trim(),
color: colors.violet, color: stat.median,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct75, metric: pattern.pct75,
title: `${title} pct75`.trim(), title: `${title} pct75`.trim(),
color: colors.fuchsia, color: stat.pct75,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: stat.pct25,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct90, metric: pattern.pct90,
title: `${title} pct90`.trim(), title: `${title} pct90`.trim(),
color: colors.amber, color: stat.pct90,
unit,
defaultActive: false,
},
{
metric: pattern.pct10,
title: `${title} pct10`.trim(),
color: stat.pct10,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
@@ -476,74 +489,75 @@ export function fromFullnessPattern(colors, pattern, unit, title = "") {
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromDollarsPattern(colors, pattern, unit, title = "") { export function fromDollarsPattern(colors, pattern, unit, title = "") {
const { stat } = colors;
return [ return [
{ metric: pattern.base, title: title || "base", unit }, { metric: pattern.base, title: title || "base", unit },
{ {
metric: pattern.sum, metric: pattern.sum,
title: `${title} sum`.trim(), title: `${title} sum`.trim(),
color: colors.blue, color: stat.sum,
unit, unit,
}, },
{ {
metric: pattern.cumulative, metric: pattern.cumulative,
title: `${title} cumulative`.trim(), title: `${title} cumulative`.trim(),
color: colors.cyan, color: stat.cumulative,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.average, metric: pattern.average,
title: `${title} avg`.trim(), title: `${title} avg`.trim(),
color: colors.purple, color: stat.avg,
unit,
defaultActive: false,
},
{
metric: pattern.min,
title: `${title} min`.trim(),
color: colors.red,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.max, metric: pattern.max,
title: `${title} max`.trim(), title: `${title} max`.trim(),
color: colors.green, color: stat.max,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct10, metric: pattern.min,
title: `${title} pct10`.trim(), title: `${title} min`.trim(),
color: colors.rose, color: stat.min,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: colors.pink,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.median, metric: pattern.median,
title: `${title} median`.trim(), title: `${title} median`.trim(),
color: colors.violet, color: stat.median,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct75, metric: pattern.pct75,
title: `${title} pct75`.trim(), title: `${title} pct75`.trim(),
color: colors.fuchsia, color: stat.pct75,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: stat.pct25,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct90, metric: pattern.pct90,
title: `${title} pct90`.trim(), title: `${title} pct90`.trim(),
color: colors.amber, color: stat.pct90,
unit,
defaultActive: false,
},
{
metric: pattern.pct10,
title: `${title} pct10`.trim(),
color: stat.pct10,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
@@ -559,54 +573,67 @@ export function fromDollarsPattern(colors, pattern, unit, title = "") {
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromFeeRatePattern(colors, pattern, unit, title = "") { export function fromFeeRatePattern(colors, pattern, unit, title = "") {
const { stat } = colors;
return [ return [
{ metric: pattern.average, title: `${title} avg`.trim(), unit },
{ {
metric: pattern.min, type: "Dots",
title: `${title} min`.trim(), metric: pattern.average,
color: colors.red, title: `${title} avg`.trim(),
unit, unit,
defaultActive: false,
}, },
{ {
type: "Dots",
metric: pattern.max, metric: pattern.max,
title: `${title} max`.trim(), title: `${title} max`.trim(),
color: colors.green, color: stat.max,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct10, type: "Dots",
title: `${title} pct10`.trim(), metric: pattern.min,
color: colors.rose, title: `${title} min`.trim(),
unit, color: stat.min,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: colors.pink,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
type: "Dots",
metric: pattern.median, metric: pattern.median,
title: `${title} median`.trim(), title: `${title} median`.trim(),
color: colors.purple, color: stat.median,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
type: "Dots",
metric: pattern.pct75, metric: pattern.pct75,
title: `${title} pct75`.trim(), title: `${title} pct75`.trim(),
color: colors.violet, color: stat.pct75,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
type: "Dots",
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: stat.pct25,
unit,
defaultActive: false,
},
{
type: "Dots",
metric: pattern.pct90, metric: pattern.pct90,
title: `${title} pct90`.trim(), 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, unit,
defaultActive: false, defaultActive: false,
}, },
@@ -617,13 +644,13 @@ export function fromFeeRatePattern(colors, pattern, unit, title = "") {
* Create series from a CoinbasePattern ({ sats, bitcoin, dollars } each as FullnessPattern) * Create series from a CoinbasePattern ({ sats, bitcoin, dollars } each as FullnessPattern)
* @param {Colors} colors * @param {Colors} colors
* @param {CoinbasePattern} pattern * @param {CoinbasePattern} pattern
* @param {string} title * @param {string} [title]
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromCoinbasePattern(colors, pattern, title) { export function fromCoinbasePattern(colors, pattern, title) {
return [ return [
...fromFullnessPattern(colors, pattern.sats, Unit.sats, title),
...fromFullnessPattern(colors, pattern.bitcoin, Unit.btc, title), ...fromFullnessPattern(colors, pattern.bitcoin, Unit.btc, title),
...fromFullnessPattern(colors, pattern.sats, Unit.sats, title),
...fromFullnessPattern(colors, pattern.dollars, Unit.usd, 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) * Create series from a ValuePattern ({ sats, bitcoin, dollars } each as BlockCountPattern with sum + cumulative)
* @param {Colors} colors * @param {Colors} colors
* @param {ValuePattern} pattern * @param {ValuePattern} pattern
* @param {string} title * @param {string} [title]
* @param {Color} [sumColor] * @param {Color} [sumColor]
* @param {Color} [cumulativeColor] * @param {Color} [cumulativeColor]
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
@@ -640,47 +667,47 @@ export function fromCoinbasePattern(colors, pattern, title) {
export function fromValuePattern( export function fromValuePattern(
colors, colors,
pattern, pattern,
title, title = "",
sumColor, sumColor,
cumulativeColor, cumulativeColor,
) { ) {
return [ 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, metric: pattern.bitcoin.sum,
title, title: title || "sum",
color: sumColor, color: sumColor,
unit: Unit.btc, unit: Unit.btc,
}, },
{ {
metric: pattern.bitcoin.cumulative, metric: pattern.bitcoin.cumulative,
title: `${title} cumulative`, title: `${title} cumulative`.trim(),
color: cumulativeColor ?? colors.blue, color: cumulativeColor ?? colors.stat.cumulative,
unit: Unit.btc, unit: Unit.btc,
defaultActive: false, 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, metric: pattern.dollars.sum,
title, title: title || "sum",
color: sumColor, color: sumColor,
unit: Unit.usd, unit: Unit.usd,
}, },
{ {
metric: pattern.dollars.cumulative, metric: pattern.dollars.cumulative,
title: `${title} cumulative`, title: `${title} cumulative`.trim(),
color: cumulativeColor ?? colors.blue, color: cumulativeColor ?? colors.stat.cumulative,
unit: Unit.usd, unit: Unit.usd,
defaultActive: false, defaultActive: false,
}, },
@@ -715,7 +742,7 @@ export function fromBitcoinPatternWithUnit(
{ {
metric: pattern.cumulative, metric: pattern.cumulative,
title: `${title} cumulative`, title: `${title} cumulative`,
color: cumulativeColor ?? colors.blue, color: cumulativeColor ?? colors.stat.cumulative,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
@@ -750,7 +777,7 @@ export function fromBlockCountWithUnit(
{ {
metric: pattern.cumulative, metric: pattern.cumulative,
title: `${title} cumulative`.trim(), title: `${title} cumulative`.trim(),
color: cumulativeColor ?? colors.blue, color: cumulativeColor ?? colors.stat.cumulative,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
@@ -767,61 +794,62 @@ export function fromBlockCountWithUnit(
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromIntervalPattern(colors, pattern, unit, title = "", color) { export function fromIntervalPattern(colors, pattern, unit, title = "", color) {
const { stat } = colors;
return [ return [
{ metric: pattern.base, title: title ?? "base", color, unit }, { metric: pattern.base, title: title ?? "base", color, unit },
{ {
metric: pattern.average, metric: pattern.average,
title: `${title} avg`.trim(), title: `${title} avg`.trim(),
color: colors.cyan, color: stat.avg,
unit,
defaultActive: false,
},
{
metric: pattern.min,
title: `${title} min`.trim(),
color: colors.red,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.max, metric: pattern.max,
title: `${title} max`.trim(), title: `${title} max`.trim(),
color: colors.green, color: stat.max,
unit,
defaultActive: false,
},
{
metric: pattern.min,
title: `${title} min`.trim(),
color: stat.min,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.median, metric: pattern.median,
title: `${title} median`.trim(), title: `${title} median`.trim(),
color: colors.violet, color: stat.median,
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,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct75, metric: pattern.pct75,
title: `${title} pct75`.trim(), title: `${title} pct75`.trim(),
color: colors.fuchsia, color: stat.pct75,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`.trim(),
color: stat.pct25,
unit, unit,
defaultActive: false, defaultActive: false,
}, },
{ {
metric: pattern.pct90, metric: pattern.pct90,
title: `${title} pct90`.trim(), title: `${title} pct90`.trim(),
color: colors.amber, color: stat.pct90,
unit,
defaultActive: false,
},
{
metric: pattern.pct10,
title: `${title} pct10`.trim(),
color: stat.pct10,
unit, unit,
defaultActive: false, 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) * Create series from a SupplyPattern (sats/bitcoin/dollars, no sum/cumulative)
* @param {Colors} colors
* @param {SupplyPattern} pattern * @param {SupplyPattern} pattern
* @param {string} title * @param {string} title
* @param {Color} [color] * @param {Color} [color]
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function fromSupplyPattern(colors, pattern, title, color) { export function fromSupplyPattern(pattern, title, color) {
return [ return [
{
metric: pattern.sats,
title,
color: color ?? colors.default,
unit: Unit.sats,
},
{ {
metric: pattern.bitcoin, metric: pattern.bitcoin,
title, title,
color: color ?? colors.default, color,
unit: Unit.btc, unit: Unit.btc,
}, },
{
metric: pattern.sats,
title,
color,
unit: Unit.sats,
},
{ {
metric: pattern.dollars, metric: pattern.dollars,
title, title,
color: color ?? colors.default, color,
unit: Unit.usd, unit: Unit.usd,
}, },
]; ];
+246 -3
View File
@@ -1,7 +1,8 @@
/** Shared helpers for options */ /** Shared helpers for options */
import { Unit } from "../utils/units.js"; 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 * 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) { export function satsBtcUsd(pattern, name, color, options) {
const { defaultActive } = options || {}; const { defaultActive } = options || {};
return [ return [
line({ metric: pattern.sats, name, color, unit: Unit.sats, defaultActive }),
line({ line({
metric: pattern.bitcoin, metric: pattern.bitcoin,
name, name,
@@ -22,6 +22,7 @@ export function satsBtcUsd(pattern, name, color, options) {
unit: Unit.btc, unit: Unit.btc,
defaultActive, defaultActive,
}), }),
line({ metric: pattern.sats, name, color, unit: Unit.sats, defaultActive }),
line({ line({
metric: pattern.dollars, metric: pattern.dollars,
name, name,
@@ -82,7 +83,7 @@ export function sdPatterns(ratio) {
* @param {Colors} colors * @param {Colors} colors
* @param {Ratio1ySdPattern} sd * @param {Ratio1ySdPattern} sd
*/ */
export function sdBands(colors, sd) { export function sdBandsUsd(colors, sd) {
return /** @type {const} */ ([ return /** @type {const} */ ([
{ name: "0σ", prop: sd._0sdUsd, color: colors.lime }, { name: "0σ", prop: sd._0sdUsd, color: colors.lime },
{ name: "+0.5σ", prop: sd.p05sdUsd, color: colors.yellow }, { 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σ", prop: sd.m2sdUsd, color: colors.blue },
{ name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose }, { name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose },
{ name: "2.5σ", prop: sd.m25sdUsd, color: colors.indigo }, { 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.p3sd, color: colors.pink },
{ name: "3σ", prop: sd.m3sd, color: colors.violet }, { 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,
}),
],
})),
],
};
}
+8 -17
View File
@@ -160,6 +160,7 @@
* @property {string} title * @property {string} title
* @property {Color} color * @property {Color} color
* @property {PatternAll} tree * @property {PatternAll} tree
* @property {Brk.MetricPattern1<Brk.StoredU64>} addrCount
* *
* Full cohort: adjustedSopr + percentiles + RelToMarketCap (term.short) * Full cohort: adjustedSopr + percentiles + RelToMarketCap (term.short)
* @typedef {Object} CohortFull * @typedef {Object} CohortFull
@@ -190,6 +191,13 @@
* @property {PatternBasic} tree * @property {PatternBasic} tree
* *
* ============================================================================ * ============================================================================
* Extended Cohort Types (with address count)
* ============================================================================
*
* Basic cohort with address count (for "type" cohorts)
* @typedef {CohortBasic & { addrCount: Brk.MetricPattern1<Brk.StoredU64> }} CohortAddress
*
* ============================================================================
* Cohort Group Types (by capability) * Cohort Group Types (by capability)
* ============================================================================ * ============================================================================
* *
@@ -233,23 +241,6 @@
* @property {readonly AddressCohortObject[]} list * @property {readonly AddressCohortObject[]} list
* *
* @typedef {UtxoCohortGroupObject | AddressCohortGroupObject} CohortGroupObject * @typedef {UtxoCohortGroupObject | AddressCohortGroupObject} CohortGroupObject
*
* @typedef {Object} PartialContext
* @property {Colors} colors
* @property {BrkClient} brk
* @property {(pattern: BlockCountPattern<any>, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCount
* @property {(pattern: FullnessPattern<any>, 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<any>, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromFullnessPattern
* @property {(pattern: DollarsPattern<any>, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromDollarsPattern
* @property {(pattern: FeeRatePattern<any>, 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<any>, 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 // Re-export for type consumers
+4 -2
View File
@@ -14,7 +14,7 @@
* *
* @import { WebSockets } from "./utils/ws.js" * @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" * @import { UnitObject as Unit } from "./utils/units.js"
@@ -41,7 +41,7 @@
* @typedef {Brk._10yTo12yPattern} AgeRangePattern * @typedef {Brk._10yTo12yPattern} AgeRangePattern
* @typedef {Brk._0satsPattern2} UtxoAmountPattern * @typedef {Brk._0satsPattern2} UtxoAmountPattern
* @typedef {Brk._0satsPattern} AddressAmountPattern * @typedef {Brk._0satsPattern} AddressAmountPattern
* @typedef {Brk._100btcPattern} BasicUtxoPattern * @typedef {Brk._0Pattern} BasicUtxoPattern
* @typedef {Brk._0satsPattern2} EpochPattern * @typedef {Brk._0satsPattern2} EpochPattern
* @typedef {Brk.Ratio1ySdPattern} Ratio1ySdPattern * @typedef {Brk.Ratio1ySdPattern} Ratio1ySdPattern
* @typedef {Brk.Dollars} Dollars * @typedef {Brk.Dollars} Dollars
@@ -53,6 +53,8 @@
* @typedef {Brk.AnyMetricEndpointBuilder} AnyMetricEndpoint * @typedef {Brk.AnyMetricEndpointBuilder} AnyMetricEndpoint
* @typedef {Brk.AnyMetricData} AnyMetricData * @typedef {Brk.AnyMetricData} AnyMetricData
* @typedef {Brk.AddrCountPattern} AddrCountPattern * @typedef {Brk.AddrCountPattern} AddrCountPattern
* @typedef {keyof Brk.MetricsTree_Distribution_UtxoCohorts_Type} SpendableType
* @typedef {keyof Brk.MetricsTree_Distribution_AnyAddressIndexes} AddressableType
* @typedef {FullnessPattern<any>} IntervalPattern * @typedef {FullnessPattern<any>} IntervalPattern
* @typedef {Brk.MetricsTree_Supply_Circulating} SupplyPattern * @typedef {Brk.MetricsTree_Supply_Circulating} SupplyPattern
* @typedef {Brk.RelativePattern} GlobalRelativePattern * @typedef {Brk.RelativePattern} GlobalRelativePattern
+3 -3
View File
@@ -31,7 +31,7 @@ export const numberToPercentage = new Intl.NumberFormat("en-US", {
export function numberToShortUSFormat(value, digits) { export function numberToShortUSFormat(value, digits) {
const absoluteValue = Math.abs(value); const absoluteValue = Math.abs(value);
if (isNaN(value)) { if (isNaN(value) || !isFinite(value)) {
return ""; return "";
} else if (absoluteValue < 10) { } else if (absoluteValue < 10) {
return numberToUSNumber(value, Math.min(3, digits || 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)); return numberToUSNumber(value, Math.min(1, digits || 10));
} else if (absoluteValue < 1_000_000) { } else if (absoluteValue < 1_000_000) {
return numberToUSNumber(value, 0); return numberToUSNumber(value, 0);
} else if (absoluteValue >= 1_000_000_000_000_000_000_000) { } else if (absoluteValue >= 1e27) {
return "Inf."; return "Inf.";
} }
const log = Math.floor(Math.log10(absoluteValue) - 6); 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 letterIndex = Math.floor(log / 3);
const letter = suffices[letterIndex]; const letter = suffices[letterIndex];
+1 -1
View File
@@ -16,7 +16,7 @@ export const Unit = /** @type {const} */ ({
sd: { id: "sd", name: "Std Dev" }, sd: { id: "sd", name: "Std Dev" },
// Relative percentages // 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" }, pctOwn: { id: "pct-own", name: "% of Own Supply" },
pctMcap: { id: "pct-mcap", name: "% of Market Cap" }, pctMcap: { id: "pct-mcap", name: "% of Market Cap" },
pctRcap: { id: "pct-rcap", name: "% of Realized Cap" }, pctRcap: { id: "pct-rcap", name: "% of Realized Cap" },