diff --git a/Cargo.lock b/Cargo.lock index 2e6d5ec52..9017a709e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,7 +211,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -378,7 +378,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.113", + "syn", ] [[package]] @@ -572,20 +572,6 @@ dependencies = [ "plotters", ] -[[package]] -name = "brk_binder" -version = "0.1.0-alpha.2" -dependencies = [ - "brk_cohort", - "brk_query", - "brk_types", - "oas3", - "schemars", - "serde", - "serde_json", - "vecdb", -] - [[package]] name = "brk_bindgen" version = "0.1.0-alpha.2" @@ -682,7 +668,7 @@ dependencies = [ "brk_traversable", "brk_types", "color-eyre", - "derive_deref", + "derive_more", "log", "pco", "rayon", @@ -787,7 +773,7 @@ dependencies = [ "brk_logger", "brk_rpc", "brk_types", - "derive_deref", + "derive_more", "log", "parking_lot", "rustc-hash", @@ -807,7 +793,7 @@ dependencies = [ "brk_rpc", "brk_traversable", "brk_types", - "derive_deref", + "derive_more", "jiff", "quickmatch", "schemars", @@ -826,7 +812,7 @@ dependencies = [ "brk_rpc", "brk_types", "crossbeam", - "derive_deref", + "derive_more", "log", "parking_lot", "rayon", @@ -872,7 +858,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.113", + "syn", ] [[package]] @@ -1271,6 +1257,7 @@ dependencies = [ "brk_rpc", "brk_traversable", "brk_types", + "derive_more", "jiff", "log", "quick_cache", @@ -1325,7 +1312,7 @@ version = "0.1.0-alpha.2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -1335,7 +1322,7 @@ dependencies = [ "bitcoin", "brk_error", "byteview", - "derive_deref", + "derive_more", "itoa", "jiff", "num_enum", @@ -1518,7 +1505,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -1845,7 +1832,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.113", + "syn", ] [[package]] @@ -1856,7 +1843,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -1890,18 +1877,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", -] - -[[package]] -name = "derive_deref" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdbcee2d9941369faba772587a565f4f534e42cb8d17e5295871de730163b2b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -1923,7 +1899,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.113", + "syn", "unicode-xid", ] @@ -1978,7 +1954,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -2041,7 +2017,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -2265,7 +2241,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -2359,7 +2335,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -2851,7 +2827,7 @@ checksum = "b787bebb543f8969132630c51fd0afab173a86c6abae56ff3b9e5e3e3f9f6e58" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -3285,7 +3261,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -3441,7 +3417,7 @@ checksum = "003b4612827f6501183873fb0735da92157e3c7daa71c40921c7d2758fec2229" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -3485,7 +3461,7 @@ dependencies = [ "phf", "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -3995,7 +3971,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -4024,7 +4000,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -4306,8 +4282,6 @@ dependencies = [ [[package]] name = "rawdb" version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63786b0b37f520a26c26787dc0de01a3c2a704706964455d556155a4deed2c6f" dependencies = [ "libc", "log", @@ -4384,7 +4358,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -4595,7 +4569,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.113", + "syn", ] [[package]] @@ -4700,7 +4674,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -4711,7 +4685,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -4932,7 +4906,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -4944,17 +4918,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.113" @@ -4980,7 +4943,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5042,7 +5005,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5053,7 +5016,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5117,7 +5080,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5263,7 +5226,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5353,7 +5316,7 @@ checksum = "ee6ff59666c9cbaec3533964505d39154dc4e0a56151fdea30a09ed0301f62e2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", "termcolor", ] @@ -5500,8 +5463,6 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" [[package]] name = "vecdb" version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c6a6a5e26cf1c7f13e9ea470c94153514ea750e491fb3c5b2846c69db5d17f" dependencies = [ "ctrlc", "log", @@ -5521,11 +5482,9 @@ dependencies = [ [[package]] name = "vecdb_derive" version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b601ba9563eaba6f46b452a905dee8e7cda6b3321f40be99e50cbccb36cd4" dependencies = [ "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5612,7 +5571,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.113", + "syn", "wasm-bindgen-shared", ] @@ -5731,7 +5690,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -5742,7 +5701,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -6016,7 +5975,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", "synstructure", ] @@ -6037,7 +5996,7 @@ checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] @@ -6057,7 +6016,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", "synstructure", ] @@ -6091,7 +6050,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fee554a5c..1f4b99934 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ brk_traversable = { version = "0.1.0-alpha.2", path = "crates/brk_traversable", brk_traversable_derive = { version = "0.1.0-alpha.2", path = "crates/brk_traversable_derive" } byteview = "0.10.0" color-eyre = "0.6.5" -derive_deref = "1.1.1" +derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] } env_logger = "0.11.8" fjall = "3.0.0" jiff = "0.2.17" @@ -81,8 +81,8 @@ serde_derive = "1.0.228" serde_json = { version = "1.0.148", features = ["float_roundtrip"] } smallvec = "1.15.1" tokio = { version = "1.49.0", features = ["rt-multi-thread"] } -vecdb = { version = "0.5.4", features = ["derive", "serde_json", "pco", "schemars"] } -# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } +# vecdb = { version = "0.5.4", features = ["derive", "serde_json", "pco", "schemars"] } +vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } # vecdb = { git = "https://github.com/anydb-rs/anydb", features = ["derive", "serde_json", "pco"] } [workspace.metadata.release] diff --git a/crates/brk_bindgen/src/generators/javascript/api.rs b/crates/brk_bindgen/src/generators/javascript/api.rs index ac583406b..cf462dc90 100644 --- a/crates/brk_bindgen/src/generators/javascript/api.rs +++ b/crates/brk_bindgen/src/generators/javascript/api.rs @@ -2,7 +2,7 @@ use std::fmt::Write; -use crate::{Endpoint, Parameter, to_camel_case}; +use crate::{Endpoint, Parameter, generators::MANUAL_GENERIC_TYPES, to_camel_case}; /// Generate API methods for the BrkClient class. pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { @@ -12,7 +12,7 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { } let method_name = endpoint_to_method_name(endpoint); - let return_type = endpoint.response_type.as_deref().unwrap_or("*"); + let return_type = normalize_return_type(endpoint.response_type.as_deref().unwrap_or("*")); writeln!(output, " /**").unwrap(); if let Some(summary) = &endpoint.summary { @@ -110,3 +110,12 @@ fn build_path_template(path: &str, path_params: &[Parameter]) -> String { } result } + +/// Replace generic types with their Any variants in return types. +fn normalize_return_type(return_type: &str) -> String { + let mut result = return_type.to_string(); + for type_name in MANUAL_GENERIC_TYPES { + result = result.replace(type_name, &format!("Any{}", type_name)); + } + result +} diff --git a/crates/brk_bindgen/src/generators/javascript/client.rs b/crates/brk_bindgen/src/generators/javascript/client.rs index 0c5cef793..e7720358c 100644 --- a/crates/brk_bindgen/src/generators/javascript/client.rs +++ b/crates/brk_bindgen/src/generators/javascript/client.rs @@ -49,6 +49,16 @@ class BrkError extends Error {{ }} }} +/** + * @template T + * @typedef {{Object}} MetricData + * @property {{number}} total - Total number of data points + * @property {{number}} from - Start index (inclusive) + * @property {{number}} to - End index (exclusive) + * @property {{T[]}} data - The metric data + */ +/** @typedef {{MetricData}} AnyMetricData */ + /** * @template T * @typedef {{Object}} MetricEndpoint diff --git a/crates/brk_bindgen/src/generators/javascript/tree.rs b/crates/brk_bindgen/src/generators/javascript/tree.rs index 9fc11d02f..58b531bfe 100644 --- a/crates/brk_bindgen/src/generators/javascript/tree.rs +++ b/crates/brk_bindgen/src/generators/javascript/tree.rs @@ -136,9 +136,56 @@ pub fn generate_main_client( generate_api_methods(output, endpoints); + // Instance method: mergeMetricPatterns + writeln!(output, r#" + /** + * Merge multiple MetricPatterns into a single pattern. + * Throws if any two patterns have overlapping indexes. + * @template T + * @param {{...MetricPattern}} patterns - The patterns to merge + * @returns {{MetricPattern}} A new merged pattern + */ + mergeMetricPatterns(...patterns) {{ + if (patterns.length === 0) {{ + throw new BrkError('mergeMetricPatterns requires at least one pattern'); + }} + if (patterns.length === 1) {{ + return patterns[0]; + }} + + const seenIndexes = /** @type {{Map}} */ (new Map()); + const mergedBy = /** @type {{Partial>>}} */ ({{}}); + + for (const pattern of patterns) {{ + for (const index of pattern.indexes()) {{ + const existing = seenIndexes.get(index); + if (existing !== undefined) {{ + throw new BrkError(`Index '${{index}}' exists in both '${{existing}}' and '${{pattern.name}}'`); + }} + seenIndexes.set(index, pattern.name); + Object.defineProperty(mergedBy, index, {{ + get() {{ return pattern.get(index); }}, + enumerable: true, + configurable: true, + }}); + }} + }} + + const allIndexes = /** @type {{Index[]}} */ ([...seenIndexes.keys()]); + const firstName = patterns[0].name; + + return {{ + name: firstName, + by: mergedBy, + indexes() {{ return allIndexes; }}, + get(index) {{ return mergedBy[index]; }}, + }}; + }} +"#).unwrap(); + writeln!(output, "}}\n").unwrap(); - writeln!(output, "export {{ BrkClient, BrkClientBase, BrkError }};").unwrap(); + writeln!(output, "export {{ BrkClient, BrkError }};").unwrap(); } fn generate_tree_initializer( diff --git a/crates/brk_bindgen/src/generators/javascript/types.rs b/crates/brk_bindgen/src/generators/javascript/types.rs index 84ddba7fb..63a10931a 100644 --- a/crates/brk_bindgen/src/generators/javascript/types.rs +++ b/crates/brk_bindgen/src/generators/javascript/types.rs @@ -4,7 +4,7 @@ use std::fmt::Write; use serde_json::Value; -use crate::{TypeSchemas, ref_to_type_name, to_camel_case}; +use crate::{TypeSchemas, generators::MANUAL_GENERIC_TYPES, ref_to_type_name, to_camel_case}; /// Generate JSDoc type definitions from OpenAPI schemas. pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) { @@ -15,6 +15,10 @@ pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) { writeln!(output, "// Type definitions\n").unwrap(); for (name, schema) in schemas { + if MANUAL_GENERIC_TYPES.contains(&name.as_str()) { + continue; + } + let js_type = schema_to_js_type(schema, Some(name)); if is_primitive_alias(schema) { diff --git a/crates/brk_bindgen/src/generators/mod.rs b/crates/brk_bindgen/src/generators/mod.rs index f1863f4ec..5d8fb6213 100644 --- a/crates/brk_bindgen/src/generators/mod.rs +++ b/crates/brk_bindgen/src/generators/mod.rs @@ -14,3 +14,6 @@ pub mod rust; pub use javascript::generate_javascript_client; pub use python::generate_python_client; pub use rust::generate_rust_client; + +/// Types that are manually defined as generics in client code, not from schema. +pub const MANUAL_GENERIC_TYPES: &[&str] = &["MetricData", "MetricEndpoint"]; diff --git a/crates/brk_bindgen/src/generators/python/api.rs b/crates/brk_bindgen/src/generators/python/api.rs index 616a81639..5e7ac89ad 100644 --- a/crates/brk_bindgen/src/generators/python/api.rs +++ b/crates/brk_bindgen/src/generators/python/api.rs @@ -2,7 +2,7 @@ use std::fmt::Write; -use crate::{Endpoint, Parameter, escape_python_keyword, to_snake_case}; +use crate::{Endpoint, Parameter, escape_python_keyword, generators::MANUAL_GENERIC_TYPES, to_snake_case}; use super::client::generate_class_constants; use super::types::js_type_to_python; @@ -41,11 +41,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { } let method_name = endpoint_to_method_name(endpoint); - let return_type = endpoint - .response_type - .as_deref() - .map(js_type_to_python) - .unwrap_or_else(|| "Any".to_string()); + let return_type = normalize_return_type( + &endpoint + .response_type + .as_deref() + .map(js_type_to_python) + .unwrap_or_else(|| "Any".to_string()), + ); // Build method signature let params = build_method_params(endpoint); @@ -149,3 +151,12 @@ fn build_path_template(path: &str, path_params: &[Parameter]) -> String { } result } + +/// Replace generic types with their Any variants in return types. +fn normalize_return_type(return_type: &str) -> String { + let mut result = return_type.to_string(); + for type_name in MANUAL_GENERIC_TYPES { + result = result.replace(type_name, &format!("Any{}", type_name)); + } + result +} diff --git a/crates/brk_bindgen/src/generators/python/client.rs b/crates/brk_bindgen/src/generators/python/client.rs index 589e8635f..1cbde46b7 100644 --- a/crates/brk_bindgen/src/generators/python/client.rs +++ b/crates/brk_bindgen/src/generators/python/client.rs @@ -118,11 +118,23 @@ def _m(acc: str, s: str) -> str: .unwrap(); } -/// Generate the Endpoint class +/// Generate the MetricData and MetricEndpoint classes pub fn generate_endpoint_class(output: &mut String) { writeln!( output, - r#"class Endpoint(Generic[T]): + r#"class MetricData(TypedDict, Generic[T]): + """Metric data with range information.""" + total: int + from_: int # 'from' is reserved in Python + to: int + data: List[T] + + +# Type alias for non-generic usage +AnyMetricData = MetricData[Any] + + +class MetricEndpoint(Generic[T]): """An endpoint for a specific metric + index combination.""" def __init__(self, client: BrkClientBase, name: str, index: str): @@ -130,11 +142,11 @@ pub fn generate_endpoint_class(output: &mut String) { self._name = name self._index = index - def get(self) -> List[T]: + def get(self) -> MetricData[T]: """Fetch all data points for this metric/index.""" return self._client.get(self.path()) - def range(self, from_val: Optional[int] = None, to_val: Optional[int] = None) -> List[T]: + def range(self, from_val: Optional[int] = None, to_val: Optional[int] = None) -> MetricData[T]: """Fetch data points within a range.""" params = [] if from_val is not None: @@ -150,6 +162,10 @@ pub fn generate_endpoint_class(output: &mut String) { return f"/api/metric/{{self._name}}/{{self._index}}" +# Type alias for non-generic usage +AnyMetricEndpoint = MetricEndpoint[Any] + + class MetricPattern(Protocol[T]): """Protocol for metric patterns with different index sets.""" @@ -162,7 +178,7 @@ class MetricPattern(Protocol[T]): """Get the list of available indexes for this metric.""" ... - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" ... @@ -199,10 +215,10 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern for index in &pattern.indexes { let method_name = index_to_field_name(index); let index_name = index.serialize_long(); - writeln!(output, " def {}(self) -> Endpoint[T]:", method_name).unwrap(); + writeln!(output, " def {}(self) -> MetricEndpoint[T]:", method_name).unwrap(); writeln!( output, - " return Endpoint(self._client, self._name, '{}')", + " return MetricEndpoint(self._client, self._name, '{}')", index_name ) .unwrap(); @@ -250,7 +266,7 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern writeln!(output).unwrap(); // Generate get(index) method - writeln!(output, " def get(self, index: str) -> Optional[Endpoint[T]]:").unwrap(); + writeln!(output, " def get(self, index: str) -> Optional[MetricEndpoint[T]]:").unwrap(); writeln!(output, " \"\"\"Get an endpoint for a specific index, if supported.\"\"\"").unwrap(); for (i, index) in pattern.indexes.iter().enumerate() { let method_name = index_to_field_name(index); diff --git a/crates/brk_bindgen/src/generators/python/types.rs b/crates/brk_bindgen/src/generators/python/types.rs index 8c411e904..2c7816a6b 100644 --- a/crates/brk_bindgen/src/generators/python/types.rs +++ b/crates/brk_bindgen/src/generators/python/types.rs @@ -5,7 +5,7 @@ use std::fmt::Write; use serde_json::Value; -use crate::{TypeSchemas, escape_python_keyword, ref_to_type_name}; +use crate::{TypeSchemas, escape_python_keyword, generators::MANUAL_GENERIC_TYPES, ref_to_type_name}; /// Generate type definitions from schemas. pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) { @@ -18,6 +18,10 @@ pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) { let sorted_names = topological_sort_schemas(schemas); for name in sorted_names { + if MANUAL_GENERIC_TYPES.contains(&name.as_str()) { + continue; + } + let Some(schema) = schemas.get(&name) else { continue; }; diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index ce97d65f6..6fac43329 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -461,12 +461,15 @@ pub struct MetricPattern4By { } impl MetricPattern4By { - pub fn by_dateindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) - } pub fn by_decadeindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) } + pub fn by_difficultyepoch(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) + } + pub fn by_height(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) + } pub fn by_monthindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } @@ -484,7 +487,7 @@ impl MetricPattern4By { } } -/// Index accessor for metrics with 7 indexes. +/// Index accessor for metrics with 8 indexes. pub struct MetricPattern4 { client: Arc, name: Arc, @@ -518,8 +521,9 @@ impl AnyMetricPattern for MetricPattern4 { fn indexes(&self) -> &'static [Index] { &[ - Index::DateIndex, Index::DecadeIndex, + Index::DifficultyEpoch, + Index::Height, Index::MonthIndex, Index::QuarterIndex, Index::SemesterIndex, @@ -532,8 +536,9 @@ impl AnyMetricPattern for MetricPattern4 { impl MetricPattern for MetricPattern4 { fn get(&self, index: Index) -> Option> { match index { - Index::DateIndex => Some(self.by.by_dateindex()), Index::DecadeIndex => Some(self.by.by_decadeindex()), + Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), + Index::Height => Some(self.by.by_height()), Index::MonthIndex => Some(self.by.by_monthindex()), Index::QuarterIndex => Some(self.by.by_quarterindex()), Index::SemesterIndex => Some(self.by.by_semesterindex()), @@ -552,12 +557,12 @@ pub struct MetricPattern5By { } impl MetricPattern5By { + pub fn by_dateindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) + } pub fn by_decadeindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) } - pub fn by_height(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) - } pub fn by_monthindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } @@ -609,8 +614,8 @@ impl AnyMetricPattern for MetricPattern5 { fn indexes(&self) -> &'static [Index] { &[ + Index::DateIndex, Index::DecadeIndex, - Index::Height, Index::MonthIndex, Index::QuarterIndex, Index::SemesterIndex, @@ -623,8 +628,8 @@ impl AnyMetricPattern for MetricPattern5 { impl MetricPattern for MetricPattern5 { fn get(&self, index: Index) -> Option> { match index { + Index::DateIndex => Some(self.by.by_dateindex()), Index::DecadeIndex => Some(self.by.by_decadeindex()), - Index::Height => Some(self.by.by_height()), Index::MonthIndex => Some(self.by.by_monthindex()), Index::QuarterIndex => Some(self.by.by_quarterindex()), Index::SemesterIndex => Some(self.by.by_semesterindex()), @@ -646,6 +651,9 @@ impl MetricPattern6By { pub fn by_decadeindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) } + pub fn by_difficultyepoch(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) + } pub fn by_monthindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } @@ -663,7 +671,7 @@ impl MetricPattern6By { } } -/// Index accessor for metrics with 6 indexes. +/// Index accessor for metrics with 7 indexes. pub struct MetricPattern6 { client: Arc, name: Arc, @@ -698,6 +706,7 @@ impl AnyMetricPattern for MetricPattern6 { fn indexes(&self) -> &'static [Index] { &[ Index::DecadeIndex, + Index::DifficultyEpoch, Index::MonthIndex, Index::QuarterIndex, Index::SemesterIndex, @@ -711,6 +720,7 @@ impl MetricPattern for MetricPattern6 { fn get(&self, index: Index) -> Option> { match index { Index::DecadeIndex => Some(self.by.by_decadeindex()), + Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), Index::MonthIndex => Some(self.by.by_monthindex()), Index::QuarterIndex => Some(self.by.by_quarterindex()), Index::SemesterIndex => Some(self.by.by_semesterindex()), @@ -729,21 +739,27 @@ pub struct MetricPattern7By { } impl MetricPattern7By { - pub fn by_emptyoutputindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::EmptyOutputIndex) + pub fn by_decadeindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) } - pub fn by_opreturnindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::OpReturnIndex) + pub fn by_monthindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } - pub fn by_p2msoutputindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2MSOutputIndex) + pub fn by_quarterindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::QuarterIndex) } - pub fn by_unknownoutputindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::UnknownOutputIndex) + pub fn by_semesterindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::SemesterIndex) + } + pub fn by_weekindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::WeekIndex) + } + pub fn by_yearindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) } } -/// Index accessor for metrics with 4 indexes. +/// Index accessor for metrics with 6 indexes. pub struct MetricPattern7 { client: Arc, name: Arc, @@ -777,10 +793,12 @@ impl AnyMetricPattern for MetricPattern7 { fn indexes(&self) -> &'static [Index] { &[ - Index::EmptyOutputIndex, - Index::OpReturnIndex, - Index::P2MSOutputIndex, - Index::UnknownOutputIndex, + Index::DecadeIndex, + Index::MonthIndex, + Index::QuarterIndex, + Index::SemesterIndex, + Index::WeekIndex, + Index::YearIndex, ] } } @@ -788,10 +806,12 @@ impl AnyMetricPattern for MetricPattern7 { impl MetricPattern for MetricPattern7 { fn get(&self, index: Index) -> Option> { match index { - Index::EmptyOutputIndex => Some(self.by.by_emptyoutputindex()), - Index::OpReturnIndex => Some(self.by.by_opreturnindex()), - Index::P2MSOutputIndex => Some(self.by.by_p2msoutputindex()), - Index::UnknownOutputIndex => Some(self.by.by_unknownoutputindex()), + Index::DecadeIndex => Some(self.by.by_decadeindex()), + Index::MonthIndex => Some(self.by.by_monthindex()), + Index::QuarterIndex => Some(self.by.by_quarterindex()), + Index::SemesterIndex => Some(self.by.by_semesterindex()), + Index::WeekIndex => Some(self.by.by_weekindex()), + Index::YearIndex => Some(self.by.by_yearindex()), _ => None, } } @@ -805,18 +825,21 @@ pub struct MetricPattern8By { } impl MetricPattern8By { - pub fn by_quarterindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::QuarterIndex) + pub fn by_emptyoutputindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::EmptyOutputIndex) } - pub fn by_semesterindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::SemesterIndex) + pub fn by_opreturnindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::OpReturnIndex) } - pub fn by_yearindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) + pub fn by_p2msoutputindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2MSOutputIndex) + } + pub fn by_unknownoutputindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::UnknownOutputIndex) } } -/// Index accessor for metrics with 3 indexes. +/// Index accessor for metrics with 4 indexes. pub struct MetricPattern8 { client: Arc, name: Arc, @@ -850,9 +873,10 @@ impl AnyMetricPattern for MetricPattern8 { fn indexes(&self) -> &'static [Index] { &[ - Index::QuarterIndex, - Index::SemesterIndex, - Index::YearIndex, + Index::EmptyOutputIndex, + Index::OpReturnIndex, + Index::P2MSOutputIndex, + Index::UnknownOutputIndex, ] } } @@ -860,9 +884,10 @@ impl AnyMetricPattern for MetricPattern8 { impl MetricPattern for MetricPattern8 { fn get(&self, index: Index) -> Option> { match index { - Index::QuarterIndex => Some(self.by.by_quarterindex()), - Index::SemesterIndex => Some(self.by.by_semesterindex()), - Index::YearIndex => Some(self.by.by_yearindex()), + Index::EmptyOutputIndex => Some(self.by.by_emptyoutputindex()), + Index::OpReturnIndex => Some(self.by.by_opreturnindex()), + Index::P2MSOutputIndex => Some(self.by.by_p2msoutputindex()), + Index::UnknownOutputIndex => Some(self.by.by_unknownoutputindex()), _ => None, } } @@ -876,15 +901,18 @@ pub struct MetricPattern9By { } impl MetricPattern9By { - pub fn by_dateindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) + pub fn by_quarterindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::QuarterIndex) } - pub fn by_height(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) + pub fn by_semesterindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::SemesterIndex) + } + pub fn by_yearindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) } } -/// Index accessor for metrics with 2 indexes. +/// Index accessor for metrics with 3 indexes. pub struct MetricPattern9 { client: Arc, name: Arc, @@ -918,8 +946,9 @@ impl AnyMetricPattern for MetricPattern9 { fn indexes(&self) -> &'static [Index] { &[ - Index::DateIndex, - Index::Height, + Index::QuarterIndex, + Index::SemesterIndex, + Index::YearIndex, ] } } @@ -927,8 +956,9 @@ impl AnyMetricPattern for MetricPattern9 { impl MetricPattern for MetricPattern9 { fn get(&self, index: Index) -> Option> { match index { - Index::DateIndex => Some(self.by.by_dateindex()), - Index::Height => Some(self.by.by_height()), + Index::QuarterIndex => Some(self.by.by_quarterindex()), + Index::SemesterIndex => Some(self.by.by_semesterindex()), + Index::YearIndex => Some(self.by.by_yearindex()), _ => None, } } @@ -945,8 +975,8 @@ impl MetricPattern10By { pub fn by_dateindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) } - pub fn by_monthindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) + pub fn by_height(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) } } @@ -985,7 +1015,7 @@ impl AnyMetricPattern for MetricPattern10 { fn indexes(&self) -> &'static [Index] { &[ Index::DateIndex, - Index::MonthIndex, + Index::Height, ] } } @@ -994,7 +1024,7 @@ impl MetricPattern for MetricPattern10 { fn get(&self, index: Index) -> Option> { match index { Index::DateIndex => Some(self.by.by_dateindex()), - Index::MonthIndex => Some(self.by.by_monthindex()), + Index::Height => Some(self.by.by_height()), _ => None, } } @@ -1011,8 +1041,8 @@ impl MetricPattern11By { pub fn by_dateindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) } - pub fn by_weekindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::WeekIndex) + pub fn by_monthindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } } @@ -1051,7 +1081,7 @@ impl AnyMetricPattern for MetricPattern11 { fn indexes(&self) -> &'static [Index] { &[ Index::DateIndex, - Index::WeekIndex, + Index::MonthIndex, ] } } @@ -1060,7 +1090,7 @@ impl MetricPattern for MetricPattern11 { fn get(&self, index: Index) -> Option> { match index { Index::DateIndex => Some(self.by.by_dateindex()), - Index::WeekIndex => Some(self.by.by_weekindex()), + Index::MonthIndex => Some(self.by.by_monthindex()), _ => None, } } @@ -1074,11 +1104,11 @@ pub struct MetricPattern12By { } impl MetricPattern12By { - pub fn by_decadeindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) + pub fn by_dateindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) } - pub fn by_yearindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) + pub fn by_weekindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::WeekIndex) } } @@ -1116,8 +1146,8 @@ impl AnyMetricPattern for MetricPattern12 { fn indexes(&self) -> &'static [Index] { &[ - Index::DecadeIndex, - Index::YearIndex, + Index::DateIndex, + Index::WeekIndex, ] } } @@ -1125,8 +1155,8 @@ impl AnyMetricPattern for MetricPattern12 { impl MetricPattern for MetricPattern12 { fn get(&self, index: Index) -> Option> { match index { - Index::DecadeIndex => Some(self.by.by_decadeindex()), - Index::YearIndex => Some(self.by.by_yearindex()), + Index::DateIndex => Some(self.by.by_dateindex()), + Index::WeekIndex => Some(self.by.by_weekindex()), _ => None, } } @@ -1140,11 +1170,11 @@ pub struct MetricPattern13By { } impl MetricPattern13By { - pub fn by_difficultyepoch(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) + pub fn by_decadeindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) } - pub fn by_halvingepoch(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::HalvingEpoch) + pub fn by_yearindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) } } @@ -1182,8 +1212,8 @@ impl AnyMetricPattern for MetricPattern13 { fn indexes(&self) -> &'static [Index] { &[ - Index::DifficultyEpoch, - Index::HalvingEpoch, + Index::DecadeIndex, + Index::YearIndex, ] } } @@ -1191,8 +1221,8 @@ impl AnyMetricPattern for MetricPattern13 { impl MetricPattern for MetricPattern13 { fn get(&self, index: Index) -> Option> { match index { - Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), - Index::HalvingEpoch => Some(self.by.by_halvingepoch()), + Index::DecadeIndex => Some(self.by.by_decadeindex()), + Index::YearIndex => Some(self.by.by_yearindex()), _ => None, } } @@ -1209,8 +1239,8 @@ impl MetricPattern14By { pub fn by_difficultyepoch(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) } - pub fn by_height(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) + pub fn by_halvingepoch(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::HalvingEpoch) } } @@ -1249,7 +1279,7 @@ impl AnyMetricPattern for MetricPattern14 { fn indexes(&self) -> &'static [Index] { &[ Index::DifficultyEpoch, - Index::Height, + Index::HalvingEpoch, ] } } @@ -1258,7 +1288,7 @@ impl MetricPattern for MetricPattern14 { fn get(&self, index: Index) -> Option> { match index { Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), - Index::Height => Some(self.by.by_height()), + Index::HalvingEpoch => Some(self.by.by_halvingepoch()), _ => None, } } @@ -1272,8 +1302,8 @@ pub struct MetricPattern15By { } impl MetricPattern15By { - pub fn by_halvingepoch(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::HalvingEpoch) + pub fn by_difficultyepoch(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) } pub fn by_height(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) @@ -1314,7 +1344,7 @@ impl AnyMetricPattern for MetricPattern15 { fn indexes(&self) -> &'static [Index] { &[ - Index::HalvingEpoch, + Index::DifficultyEpoch, Index::Height, ] } @@ -1323,7 +1353,7 @@ impl AnyMetricPattern for MetricPattern15 { impl MetricPattern for MetricPattern15 { fn get(&self, index: Index) -> Option> { match index { - Index::HalvingEpoch => Some(self.by.by_halvingepoch()), + Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), Index::Height => Some(self.by.by_height()), _ => None, } @@ -1338,12 +1368,12 @@ pub struct MetricPattern16By { } impl MetricPattern16By { + pub fn by_halvingepoch(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::HalvingEpoch) + } pub fn by_height(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) } - pub fn by_txindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::TxIndex) - } } /// Index accessor for metrics with 2 indexes. @@ -1380,8 +1410,8 @@ impl AnyMetricPattern for MetricPattern16 { fn indexes(&self) -> &'static [Index] { &[ + Index::HalvingEpoch, Index::Height, - Index::TxIndex, ] } } @@ -1389,8 +1419,8 @@ impl AnyMetricPattern for MetricPattern16 { impl MetricPattern for MetricPattern16 { fn get(&self, index: Index) -> Option> { match index { + Index::HalvingEpoch => Some(self.by.by_halvingepoch()), Index::Height => Some(self.by.by_height()), - Index::TxIndex => Some(self.by.by_txindex()), _ => None, } } @@ -1404,11 +1434,11 @@ pub struct MetricPattern17By { } impl MetricPattern17By { - pub fn by_monthindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) + pub fn by_height(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) } - pub fn by_quarterindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::QuarterIndex) + pub fn by_txindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::TxIndex) } } @@ -1446,8 +1476,8 @@ impl AnyMetricPattern for MetricPattern17 { fn indexes(&self) -> &'static [Index] { &[ - Index::MonthIndex, - Index::QuarterIndex, + Index::Height, + Index::TxIndex, ] } } @@ -1455,8 +1485,8 @@ impl AnyMetricPattern for MetricPattern17 { impl MetricPattern for MetricPattern17 { fn get(&self, index: Index) -> Option> { match index { - Index::MonthIndex => Some(self.by.by_monthindex()), - Index::QuarterIndex => Some(self.by.by_quarterindex()), + Index::Height => Some(self.by.by_height()), + Index::TxIndex => Some(self.by.by_txindex()), _ => None, } } @@ -1473,8 +1503,8 @@ impl MetricPattern18By { pub fn by_monthindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } - pub fn by_semesterindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::SemesterIndex) + pub fn by_quarterindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::QuarterIndex) } } @@ -1513,7 +1543,7 @@ impl AnyMetricPattern for MetricPattern18 { fn indexes(&self) -> &'static [Index] { &[ Index::MonthIndex, - Index::SemesterIndex, + Index::QuarterIndex, ] } } @@ -1522,7 +1552,7 @@ impl MetricPattern for MetricPattern18 { fn get(&self, index: Index) -> Option> { match index { Index::MonthIndex => Some(self.by.by_monthindex()), - Index::SemesterIndex => Some(self.by.by_semesterindex()), + Index::QuarterIndex => Some(self.by.by_quarterindex()), _ => None, } } @@ -1539,8 +1569,8 @@ impl MetricPattern19By { pub fn by_monthindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } - pub fn by_weekindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::WeekIndex) + pub fn by_semesterindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::SemesterIndex) } } @@ -1579,7 +1609,7 @@ impl AnyMetricPattern for MetricPattern19 { fn indexes(&self) -> &'static [Index] { &[ Index::MonthIndex, - Index::WeekIndex, + Index::SemesterIndex, ] } } @@ -1588,7 +1618,7 @@ impl MetricPattern for MetricPattern19 { fn get(&self, index: Index) -> Option> { match index { Index::MonthIndex => Some(self.by.by_monthindex()), - Index::WeekIndex => Some(self.by.by_weekindex()), + Index::SemesterIndex => Some(self.by.by_semesterindex()), _ => None, } } @@ -1605,8 +1635,8 @@ impl MetricPattern20By { pub fn by_monthindex(&self) -> Endpoint { Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) } - pub fn by_yearindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) + pub fn by_weekindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::WeekIndex) } } @@ -1645,7 +1675,7 @@ impl AnyMetricPattern for MetricPattern20 { fn indexes(&self) -> &'static [Index] { &[ Index::MonthIndex, - Index::YearIndex, + Index::WeekIndex, ] } } @@ -1654,7 +1684,7 @@ impl MetricPattern for MetricPattern20 { fn get(&self, index: Index) -> Option> { match index { Index::MonthIndex => Some(self.by.by_monthindex()), - Index::YearIndex => Some(self.by.by_yearindex()), + Index::WeekIndex => Some(self.by.by_weekindex()), _ => None, } } @@ -1668,12 +1698,15 @@ pub struct MetricPattern21By { } impl MetricPattern21By { - pub fn by_dateindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) + pub fn by_monthindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::MonthIndex) + } + pub fn by_yearindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::YearIndex) } } -/// Index accessor for metrics with 1 indexes. +/// Index accessor for metrics with 2 indexes. pub struct MetricPattern21 { client: Arc, name: Arc, @@ -1707,7 +1740,8 @@ impl AnyMetricPattern for MetricPattern21 { fn indexes(&self) -> &'static [Index] { &[ - Index::DateIndex, + Index::MonthIndex, + Index::YearIndex, ] } } @@ -1715,7 +1749,8 @@ impl AnyMetricPattern for MetricPattern21 { impl MetricPattern for MetricPattern21 { fn get(&self, index: Index) -> Option> { match index { - Index::DateIndex => Some(self.by.by_dateindex()), + Index::MonthIndex => Some(self.by.by_monthindex()), + Index::YearIndex => Some(self.by.by_yearindex()), _ => None, } } @@ -1729,8 +1764,8 @@ pub struct MetricPattern22By { } impl MetricPattern22By { - pub fn by_decadeindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) + pub fn by_dateindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DateIndex) } } @@ -1768,7 +1803,7 @@ impl AnyMetricPattern for MetricPattern22 { fn indexes(&self) -> &'static [Index] { &[ - Index::DecadeIndex, + Index::DateIndex, ] } } @@ -1776,7 +1811,7 @@ impl AnyMetricPattern for MetricPattern22 { impl MetricPattern for MetricPattern22 { fn get(&self, index: Index) -> Option> { match index { - Index::DecadeIndex => Some(self.by.by_decadeindex()), + Index::DateIndex => Some(self.by.by_dateindex()), _ => None, } } @@ -1790,8 +1825,8 @@ pub struct MetricPattern23By { } impl MetricPattern23By { - pub fn by_difficultyepoch(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) + pub fn by_decadeindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DecadeIndex) } } @@ -1829,7 +1864,7 @@ impl AnyMetricPattern for MetricPattern23 { fn indexes(&self) -> &'static [Index] { &[ - Index::DifficultyEpoch, + Index::DecadeIndex, ] } } @@ -1837,7 +1872,7 @@ impl AnyMetricPattern for MetricPattern23 { impl MetricPattern for MetricPattern23 { fn get(&self, index: Index) -> Option> { match index { - Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), + Index::DecadeIndex => Some(self.by.by_decadeindex()), _ => None, } } @@ -1851,8 +1886,8 @@ pub struct MetricPattern24By { } impl MetricPattern24By { - pub fn by_emptyoutputindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::EmptyOutputIndex) + pub fn by_difficultyepoch(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::DifficultyEpoch) } } @@ -1890,7 +1925,7 @@ impl AnyMetricPattern for MetricPattern24 { fn indexes(&self) -> &'static [Index] { &[ - Index::EmptyOutputIndex, + Index::DifficultyEpoch, ] } } @@ -1898,7 +1933,7 @@ impl AnyMetricPattern for MetricPattern24 { impl MetricPattern for MetricPattern24 { fn get(&self, index: Index) -> Option> { match index { - Index::EmptyOutputIndex => Some(self.by.by_emptyoutputindex()), + Index::DifficultyEpoch => Some(self.by.by_difficultyepoch()), _ => None, } } @@ -1912,8 +1947,8 @@ pub struct MetricPattern25By { } impl MetricPattern25By { - pub fn by_height(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) + pub fn by_emptyoutputindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::EmptyOutputIndex) } } @@ -1951,7 +1986,7 @@ impl AnyMetricPattern for MetricPattern25 { fn indexes(&self) -> &'static [Index] { &[ - Index::Height, + Index::EmptyOutputIndex, ] } } @@ -1959,7 +1994,7 @@ impl AnyMetricPattern for MetricPattern25 { impl MetricPattern for MetricPattern25 { fn get(&self, index: Index) -> Option> { match index { - Index::Height => Some(self.by.by_height()), + Index::EmptyOutputIndex => Some(self.by.by_emptyoutputindex()), _ => None, } } @@ -1973,8 +2008,8 @@ pub struct MetricPattern26By { } impl MetricPattern26By { - pub fn by_txinindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::TxInIndex) + pub fn by_height(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::Height) } } @@ -2012,7 +2047,7 @@ impl AnyMetricPattern for MetricPattern26 { fn indexes(&self) -> &'static [Index] { &[ - Index::TxInIndex, + Index::Height, ] } } @@ -2020,7 +2055,7 @@ impl AnyMetricPattern for MetricPattern26 { impl MetricPattern for MetricPattern26 { fn get(&self, index: Index) -> Option> { match index { - Index::TxInIndex => Some(self.by.by_txinindex()), + Index::Height => Some(self.by.by_height()), _ => None, } } @@ -2034,8 +2069,8 @@ pub struct MetricPattern27By { } impl MetricPattern27By { - pub fn by_opreturnindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::OpReturnIndex) + pub fn by_txinindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::TxInIndex) } } @@ -2073,7 +2108,7 @@ impl AnyMetricPattern for MetricPattern27 { fn indexes(&self) -> &'static [Index] { &[ - Index::OpReturnIndex, + Index::TxInIndex, ] } } @@ -2081,7 +2116,7 @@ impl AnyMetricPattern for MetricPattern27 { impl MetricPattern for MetricPattern27 { fn get(&self, index: Index) -> Option> { match index { - Index::OpReturnIndex => Some(self.by.by_opreturnindex()), + Index::TxInIndex => Some(self.by.by_txinindex()), _ => None, } } @@ -2095,8 +2130,8 @@ pub struct MetricPattern28By { } impl MetricPattern28By { - pub fn by_txoutindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::TxOutIndex) + pub fn by_opreturnindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::OpReturnIndex) } } @@ -2134,7 +2169,7 @@ impl AnyMetricPattern for MetricPattern28 { fn indexes(&self) -> &'static [Index] { &[ - Index::TxOutIndex, + Index::OpReturnIndex, ] } } @@ -2142,7 +2177,7 @@ impl AnyMetricPattern for MetricPattern28 { impl MetricPattern for MetricPattern28 { fn get(&self, index: Index) -> Option> { match index { - Index::TxOutIndex => Some(self.by.by_txoutindex()), + Index::OpReturnIndex => Some(self.by.by_opreturnindex()), _ => None, } } @@ -2156,8 +2191,8 @@ pub struct MetricPattern29By { } impl MetricPattern29By { - pub fn by_p2aaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2AAddressIndex) + pub fn by_txoutindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::TxOutIndex) } } @@ -2195,7 +2230,7 @@ impl AnyMetricPattern for MetricPattern29 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2AAddressIndex, + Index::TxOutIndex, ] } } @@ -2203,7 +2238,7 @@ impl AnyMetricPattern for MetricPattern29 { impl MetricPattern for MetricPattern29 { fn get(&self, index: Index) -> Option> { match index { - Index::P2AAddressIndex => Some(self.by.by_p2aaddressindex()), + Index::TxOutIndex => Some(self.by.by_txoutindex()), _ => None, } } @@ -2217,8 +2252,8 @@ pub struct MetricPattern30By { } impl MetricPattern30By { - pub fn by_p2msoutputindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2MSOutputIndex) + pub fn by_p2aaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2AAddressIndex) } } @@ -2256,7 +2291,7 @@ impl AnyMetricPattern for MetricPattern30 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2MSOutputIndex, + Index::P2AAddressIndex, ] } } @@ -2264,7 +2299,7 @@ impl AnyMetricPattern for MetricPattern30 { impl MetricPattern for MetricPattern30 { fn get(&self, index: Index) -> Option> { match index { - Index::P2MSOutputIndex => Some(self.by.by_p2msoutputindex()), + Index::P2AAddressIndex => Some(self.by.by_p2aaddressindex()), _ => None, } } @@ -2278,8 +2313,8 @@ pub struct MetricPattern31By { } impl MetricPattern31By { - pub fn by_p2pk33addressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2PK33AddressIndex) + pub fn by_p2msoutputindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2MSOutputIndex) } } @@ -2317,7 +2352,7 @@ impl AnyMetricPattern for MetricPattern31 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2PK33AddressIndex, + Index::P2MSOutputIndex, ] } } @@ -2325,7 +2360,7 @@ impl AnyMetricPattern for MetricPattern31 { impl MetricPattern for MetricPattern31 { fn get(&self, index: Index) -> Option> { match index { - Index::P2PK33AddressIndex => Some(self.by.by_p2pk33addressindex()), + Index::P2MSOutputIndex => Some(self.by.by_p2msoutputindex()), _ => None, } } @@ -2339,8 +2374,8 @@ pub struct MetricPattern32By { } impl MetricPattern32By { - pub fn by_p2pk65addressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2PK65AddressIndex) + pub fn by_p2pk33addressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2PK33AddressIndex) } } @@ -2378,7 +2413,7 @@ impl AnyMetricPattern for MetricPattern32 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2PK65AddressIndex, + Index::P2PK33AddressIndex, ] } } @@ -2386,7 +2421,7 @@ impl AnyMetricPattern for MetricPattern32 { impl MetricPattern for MetricPattern32 { fn get(&self, index: Index) -> Option> { match index { - Index::P2PK65AddressIndex => Some(self.by.by_p2pk65addressindex()), + Index::P2PK33AddressIndex => Some(self.by.by_p2pk33addressindex()), _ => None, } } @@ -2400,8 +2435,8 @@ pub struct MetricPattern33By { } impl MetricPattern33By { - pub fn by_p2pkhaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2PKHAddressIndex) + pub fn by_p2pk65addressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2PK65AddressIndex) } } @@ -2439,7 +2474,7 @@ impl AnyMetricPattern for MetricPattern33 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2PKHAddressIndex, + Index::P2PK65AddressIndex, ] } } @@ -2447,7 +2482,7 @@ impl AnyMetricPattern for MetricPattern33 { impl MetricPattern for MetricPattern33 { fn get(&self, index: Index) -> Option> { match index { - Index::P2PKHAddressIndex => Some(self.by.by_p2pkhaddressindex()), + Index::P2PK65AddressIndex => Some(self.by.by_p2pk65addressindex()), _ => None, } } @@ -2461,8 +2496,8 @@ pub struct MetricPattern34By { } impl MetricPattern34By { - pub fn by_p2shaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2SHAddressIndex) + pub fn by_p2pkhaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2PKHAddressIndex) } } @@ -2500,7 +2535,7 @@ impl AnyMetricPattern for MetricPattern34 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2SHAddressIndex, + Index::P2PKHAddressIndex, ] } } @@ -2508,7 +2543,7 @@ impl AnyMetricPattern for MetricPattern34 { impl MetricPattern for MetricPattern34 { fn get(&self, index: Index) -> Option> { match index { - Index::P2SHAddressIndex => Some(self.by.by_p2shaddressindex()), + Index::P2PKHAddressIndex => Some(self.by.by_p2pkhaddressindex()), _ => None, } } @@ -2522,8 +2557,8 @@ pub struct MetricPattern35By { } impl MetricPattern35By { - pub fn by_p2traddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2TRAddressIndex) + pub fn by_p2shaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2SHAddressIndex) } } @@ -2561,7 +2596,7 @@ impl AnyMetricPattern for MetricPattern35 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2TRAddressIndex, + Index::P2SHAddressIndex, ] } } @@ -2569,7 +2604,7 @@ impl AnyMetricPattern for MetricPattern35 { impl MetricPattern for MetricPattern35 { fn get(&self, index: Index) -> Option> { match index { - Index::P2TRAddressIndex => Some(self.by.by_p2traddressindex()), + Index::P2SHAddressIndex => Some(self.by.by_p2shaddressindex()), _ => None, } } @@ -2583,8 +2618,8 @@ pub struct MetricPattern36By { } impl MetricPattern36By { - pub fn by_p2wpkhaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2WPKHAddressIndex) + pub fn by_p2traddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2TRAddressIndex) } } @@ -2622,7 +2657,7 @@ impl AnyMetricPattern for MetricPattern36 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2WPKHAddressIndex, + Index::P2TRAddressIndex, ] } } @@ -2630,7 +2665,7 @@ impl AnyMetricPattern for MetricPattern36 { impl MetricPattern for MetricPattern36 { fn get(&self, index: Index) -> Option> { match index { - Index::P2WPKHAddressIndex => Some(self.by.by_p2wpkhaddressindex()), + Index::P2TRAddressIndex => Some(self.by.by_p2traddressindex()), _ => None, } } @@ -2644,8 +2679,8 @@ pub struct MetricPattern37By { } impl MetricPattern37By { - pub fn by_p2wshaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::P2WSHAddressIndex) + pub fn by_p2wpkhaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2WPKHAddressIndex) } } @@ -2683,7 +2718,7 @@ impl AnyMetricPattern for MetricPattern37 { fn indexes(&self) -> &'static [Index] { &[ - Index::P2WSHAddressIndex, + Index::P2WPKHAddressIndex, ] } } @@ -2691,7 +2726,7 @@ impl AnyMetricPattern for MetricPattern37 { impl MetricPattern for MetricPattern37 { fn get(&self, index: Index) -> Option> { match index { - Index::P2WSHAddressIndex => Some(self.by.by_p2wshaddressindex()), + Index::P2WPKHAddressIndex => Some(self.by.by_p2wpkhaddressindex()), _ => None, } } @@ -2705,8 +2740,8 @@ pub struct MetricPattern38By { } impl MetricPattern38By { - pub fn by_txindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::TxIndex) + pub fn by_p2wshaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::P2WSHAddressIndex) } } @@ -2744,7 +2779,7 @@ impl AnyMetricPattern for MetricPattern38 { fn indexes(&self) -> &'static [Index] { &[ - Index::TxIndex, + Index::P2WSHAddressIndex, ] } } @@ -2752,7 +2787,7 @@ impl AnyMetricPattern for MetricPattern38 { impl MetricPattern for MetricPattern38 { fn get(&self, index: Index) -> Option> { match index { - Index::TxIndex => Some(self.by.by_txindex()), + Index::P2WSHAddressIndex => Some(self.by.by_p2wshaddressindex()), _ => None, } } @@ -2766,8 +2801,8 @@ pub struct MetricPattern39By { } impl MetricPattern39By { - pub fn by_unknownoutputindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::UnknownOutputIndex) + pub fn by_txindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::TxIndex) } } @@ -2805,7 +2840,7 @@ impl AnyMetricPattern for MetricPattern39 { fn indexes(&self) -> &'static [Index] { &[ - Index::UnknownOutputIndex, + Index::TxIndex, ] } } @@ -2813,7 +2848,7 @@ impl AnyMetricPattern for MetricPattern39 { impl MetricPattern for MetricPattern39 { fn get(&self, index: Index) -> Option> { match index { - Index::UnknownOutputIndex => Some(self.by.by_unknownoutputindex()), + Index::TxIndex => Some(self.by.by_txindex()), _ => None, } } @@ -2827,8 +2862,8 @@ pub struct MetricPattern40By { } impl MetricPattern40By { - pub fn by_loadedaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::LoadedAddressIndex) + pub fn by_unknownoutputindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::UnknownOutputIndex) } } @@ -2866,7 +2901,7 @@ impl AnyMetricPattern for MetricPattern40 { fn indexes(&self) -> &'static [Index] { &[ - Index::LoadedAddressIndex, + Index::UnknownOutputIndex, ] } } @@ -2874,7 +2909,7 @@ impl AnyMetricPattern for MetricPattern40 { impl MetricPattern for MetricPattern40 { fn get(&self, index: Index) -> Option> { match index { - Index::LoadedAddressIndex => Some(self.by.by_loadedaddressindex()), + Index::UnknownOutputIndex => Some(self.by.by_unknownoutputindex()), _ => None, } } @@ -2888,8 +2923,8 @@ pub struct MetricPattern41By { } impl MetricPattern41By { - pub fn by_emptyaddressindex(&self) -> Endpoint { - Endpoint::new(self.client.clone(), self.name.clone(), Index::EmptyAddressIndex) + pub fn by_loadedaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::LoadedAddressIndex) } } @@ -2927,12 +2962,73 @@ impl AnyMetricPattern for MetricPattern41 { fn indexes(&self) -> &'static [Index] { &[ - Index::EmptyAddressIndex, + Index::LoadedAddressIndex, ] } } impl MetricPattern for MetricPattern41 { + fn get(&self, index: Index) -> Option> { + match index { + Index::LoadedAddressIndex => Some(self.by.by_loadedaddressindex()), + _ => None, + } + } +} + +/// Container for index endpoint methods. +pub struct MetricPattern42By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} + +impl MetricPattern42By { + pub fn by_emptyaddressindex(&self) -> Endpoint { + Endpoint::new(self.client.clone(), self.name.clone(), Index::EmptyAddressIndex) + } +} + +/// Index accessor for metrics with 1 indexes. +pub struct MetricPattern42 { + client: Arc, + name: Arc, + pub by: MetricPattern42By, +} + +impl MetricPattern42 { + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + client: client.clone(), + name: name.clone(), + by: MetricPattern42By { + client, + name, + _marker: std::marker::PhantomData, + } + } + } + + /// Get the metric name. + pub fn name(&self) -> &str { + &self.name + } +} + +impl AnyMetricPattern for MetricPattern42 { + fn name(&self) -> &str { + &self.name + } + + fn indexes(&self) -> &'static [Index] { + &[ + Index::EmptyAddressIndex, + ] + } +} + +impl MetricPattern for MetricPattern42 { fn get(&self, index: Index) -> Option> { match index { Index::EmptyAddressIndex => Some(self.by.by_emptyaddressindex()), @@ -2945,369 +3041,385 @@ impl MetricPattern for MetricPattern41 { /// Pattern struct for repeated tree structure. pub struct RealizedPattern3 { - pub adjusted_sopr: MetricPattern21, - pub adjusted_sopr_30d_ema: MetricPattern21, - pub adjusted_sopr_7d_ema: MetricPattern21, - pub adjusted_value_created: TotalRealizedPnlPattern, - pub adjusted_value_destroyed: TotalRealizedPnlPattern, - pub mvrv: MetricPattern4, + pub adjusted_sopr: MetricPattern22, + pub adjusted_sopr_30d_ema: MetricPattern22, + pub adjusted_sopr_7d_ema: MetricPattern22, + pub adjusted_value_created: MetricPattern1, + pub adjusted_value_destroyed: MetricPattern1, + pub mvrv: MetricPattern5, pub neg_realized_loss: BlockCountPattern, pub net_realized_pnl: BlockCountPattern, - pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, - pub net_realized_pnl_rel_to_realized_cap: MetricPattern25, + pub net_realized_pnl_cumulative_30d_delta: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5, + pub net_realized_pnl_rel_to_realized_cap: BlockCountPattern, pub realized_cap: MetricPattern1, - pub realized_cap_30d_delta: MetricPattern4, + pub realized_cap_30d_delta: MetricPattern5, pub realized_cap_rel_to_own_market_cap: MetricPattern1, pub realized_loss: BlockCountPattern, - pub realized_loss_rel_to_realized_cap: MetricPattern25, + pub realized_loss_rel_to_realized_cap: BlockCountPattern, pub realized_price: MetricPattern1, pub realized_price_extra: ActivePriceRatioPattern, pub realized_profit: BlockCountPattern, - pub realized_profit_rel_to_realized_cap: MetricPattern25, - pub realized_profit_to_loss_ratio: MetricPattern21, - pub realized_value: MetricPattern1, - pub sell_side_risk_ratio: MetricPattern21, - pub sell_side_risk_ratio_30d_ema: MetricPattern21, - pub sell_side_risk_ratio_7d_ema: MetricPattern21, - pub sopr: MetricPattern21, - pub sopr_30d_ema: MetricPattern21, - pub sopr_7d_ema: MetricPattern21, - pub total_realized_pnl: TotalRealizedPnlPattern, - pub value_created: MetricPattern1, - pub value_destroyed: MetricPattern1, + pub realized_profit_rel_to_realized_cap: BlockCountPattern, + pub realized_profit_to_loss_ratio: MetricPattern22, + pub realized_value: DifficultyAdjustmentPattern, + pub sell_side_risk_ratio: MetricPattern22, + pub sell_side_risk_ratio_30d_ema: MetricPattern22, + pub sell_side_risk_ratio_7d_ema: MetricPattern22, + pub sopr: MetricPattern22, + pub sopr_30d_ema: MetricPattern22, + pub sopr_7d_ema: MetricPattern22, + pub total_realized_pnl: MetricPattern1, + pub value_created: MetricPattern26, + pub value_created_sum: MetricPattern2, + pub value_destroyed: MetricPattern26, + pub value_destroyed_sum: MetricPattern2, } impl RealizedPattern3 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - adjusted_sopr: MetricPattern21::new(client.clone(), _m(&acc, "adjusted_sopr")), - adjusted_sopr_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "adjusted_sopr_30d_ema")), - adjusted_sopr_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "adjusted_sopr_7d_ema")), - adjusted_value_created: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "adjusted_value_created")), - adjusted_value_destroyed: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), - mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), + adjusted_sopr: MetricPattern22::new(client.clone(), _m(&acc, "adjusted_sopr")), + adjusted_sopr_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "adjusted_sopr_30d_ema")), + adjusted_sopr_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "adjusted_sopr_7d_ema")), + adjusted_value_created: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_created")), + adjusted_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), + mvrv: MetricPattern5::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), - net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), - net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), - net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), - net_realized_pnl_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + net_realized_pnl_cumulative_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), + net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), + net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), + net_realized_pnl_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap")), - realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), + realized_cap_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_cap_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), - realized_loss_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), + realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: ActivePriceRatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), - realized_profit_to_loss_ratio: MetricPattern21::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), - realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), - sell_side_risk_ratio: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), - sell_side_risk_ratio_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), - sell_side_risk_ratio_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), - sopr: MetricPattern21::new(client.clone(), _m(&acc, "sopr")), - sopr_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_30d_ema")), - sopr_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_7d_ema")), - total_realized_pnl: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "total_realized_pnl")), - value_created: MetricPattern1::new(client.clone(), _m(&acc, "value_created")), - value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "value_destroyed")), + realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), + realized_profit_to_loss_ratio: MetricPattern22::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), + realized_value: DifficultyAdjustmentPattern::new(client.clone(), _m(&acc, "realized_value")), + sell_side_risk_ratio: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), + sell_side_risk_ratio_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), + sell_side_risk_ratio_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sopr: MetricPattern22::new(client.clone(), _m(&acc, "sopr")), + sopr_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_30d_ema")), + sopr_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_7d_ema")), + total_realized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_realized_pnl")), + value_created: MetricPattern26::new(client.clone(), _m(&acc, "value_created")), + value_created_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_created_sum")), + value_destroyed: MetricPattern26::new(client.clone(), _m(&acc, "value_destroyed")), + value_destroyed_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_destroyed_sum")), } } } /// Pattern struct for repeated tree structure. pub struct RealizedPattern4 { - pub adjusted_sopr: MetricPattern21, - pub adjusted_sopr_30d_ema: MetricPattern21, - pub adjusted_sopr_7d_ema: MetricPattern21, - pub adjusted_value_created: TotalRealizedPnlPattern, - pub adjusted_value_destroyed: TotalRealizedPnlPattern, - pub mvrv: MetricPattern4, + pub adjusted_sopr: MetricPattern22, + pub adjusted_sopr_30d_ema: MetricPattern22, + pub adjusted_sopr_7d_ema: MetricPattern22, + pub adjusted_value_created: MetricPattern1, + pub adjusted_value_destroyed: MetricPattern1, + pub mvrv: MetricPattern5, pub neg_realized_loss: BlockCountPattern, pub net_realized_pnl: BlockCountPattern, - pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, - pub net_realized_pnl_rel_to_realized_cap: MetricPattern25, + pub net_realized_pnl_cumulative_30d_delta: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5, + pub net_realized_pnl_rel_to_realized_cap: BlockCountPattern, pub realized_cap: MetricPattern1, - pub realized_cap_30d_delta: MetricPattern4, + pub realized_cap_30d_delta: MetricPattern5, pub realized_loss: BlockCountPattern, - pub realized_loss_rel_to_realized_cap: MetricPattern25, + pub realized_loss_rel_to_realized_cap: BlockCountPattern, pub realized_price: MetricPattern1, pub realized_price_extra: RealizedPriceExtraPattern, pub realized_profit: BlockCountPattern, - pub realized_profit_rel_to_realized_cap: MetricPattern25, - pub realized_value: MetricPattern1, - pub sell_side_risk_ratio: MetricPattern21, - pub sell_side_risk_ratio_30d_ema: MetricPattern21, - pub sell_side_risk_ratio_7d_ema: MetricPattern21, - pub sopr: MetricPattern21, - pub sopr_30d_ema: MetricPattern21, - pub sopr_7d_ema: MetricPattern21, - pub total_realized_pnl: TotalRealizedPnlPattern, - pub value_created: MetricPattern1, - pub value_destroyed: MetricPattern1, + pub realized_profit_rel_to_realized_cap: BlockCountPattern, + pub realized_value: DifficultyAdjustmentPattern, + pub sell_side_risk_ratio: MetricPattern22, + pub sell_side_risk_ratio_30d_ema: MetricPattern22, + pub sell_side_risk_ratio_7d_ema: MetricPattern22, + pub sopr: MetricPattern22, + pub sopr_30d_ema: MetricPattern22, + pub sopr_7d_ema: MetricPattern22, + pub total_realized_pnl: MetricPattern1, + pub value_created: MetricPattern26, + pub value_created_sum: MetricPattern2, + pub value_destroyed: MetricPattern26, + pub value_destroyed_sum: MetricPattern2, } impl RealizedPattern4 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - adjusted_sopr: MetricPattern21::new(client.clone(), _m(&acc, "adjusted_sopr")), - adjusted_sopr_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "adjusted_sopr_30d_ema")), - adjusted_sopr_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "adjusted_sopr_7d_ema")), - adjusted_value_created: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "adjusted_value_created")), - adjusted_value_destroyed: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), - mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), + adjusted_sopr: MetricPattern22::new(client.clone(), _m(&acc, "adjusted_sopr")), + adjusted_sopr_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "adjusted_sopr_30d_ema")), + adjusted_sopr_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "adjusted_sopr_7d_ema")), + adjusted_value_created: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_created")), + adjusted_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "adjusted_value_destroyed")), + mvrv: MetricPattern5::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), - net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), - net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), - net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), - net_realized_pnl_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + net_realized_pnl_cumulative_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), + net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), + net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), + net_realized_pnl_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap")), - realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), + realized_cap_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), - realized_loss_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), + realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RealizedPriceExtraPattern::new(client.clone(), _m(&acc, "realized_price")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), - realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), - sell_side_risk_ratio: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), - sell_side_risk_ratio_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), - sell_side_risk_ratio_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), - sopr: MetricPattern21::new(client.clone(), _m(&acc, "sopr")), - sopr_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_30d_ema")), - sopr_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_7d_ema")), - total_realized_pnl: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "total_realized_pnl")), - value_created: MetricPattern1::new(client.clone(), _m(&acc, "value_created")), - value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "value_destroyed")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct Ratio1ySdPattern { - pub _0sd_usd: MetricPattern4, - pub m0_5sd: MetricPattern4, - pub m0_5sd_usd: MetricPattern4, - pub m1_5sd: MetricPattern4, - pub m1_5sd_usd: MetricPattern4, - pub m1sd: MetricPattern4, - pub m1sd_usd: MetricPattern4, - pub m2_5sd: MetricPattern4, - pub m2_5sd_usd: MetricPattern4, - pub m2sd: MetricPattern4, - pub m2sd_usd: MetricPattern4, - pub m3sd: MetricPattern4, - pub m3sd_usd: MetricPattern4, - pub p0_5sd: MetricPattern4, - pub p0_5sd_usd: MetricPattern4, - pub p1_5sd: MetricPattern4, - pub p1_5sd_usd: MetricPattern4, - pub p1sd: MetricPattern4, - pub p1sd_usd: MetricPattern4, - pub p2_5sd: MetricPattern4, - pub p2_5sd_usd: MetricPattern4, - pub p2sd: MetricPattern4, - pub p2sd_usd: MetricPattern4, - pub p3sd: MetricPattern4, - pub p3sd_usd: MetricPattern4, - pub sd: MetricPattern4, - pub sma: MetricPattern4, - pub zscore: MetricPattern4, -} - -impl Ratio1ySdPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - _0sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "0sd_usd")), - m0_5sd: MetricPattern4::new(client.clone(), _m(&acc, "m0_5sd")), - m0_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m0_5sd_usd")), - m1_5sd: MetricPattern4::new(client.clone(), _m(&acc, "m1_5sd")), - m1_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m1_5sd_usd")), - m1sd: MetricPattern4::new(client.clone(), _m(&acc, "m1sd")), - m1sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m1sd_usd")), - m2_5sd: MetricPattern4::new(client.clone(), _m(&acc, "m2_5sd")), - m2_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m2_5sd_usd")), - m2sd: MetricPattern4::new(client.clone(), _m(&acc, "m2sd")), - m2sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m2sd_usd")), - m3sd: MetricPattern4::new(client.clone(), _m(&acc, "m3sd")), - m3sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m3sd_usd")), - p0_5sd: MetricPattern4::new(client.clone(), _m(&acc, "p0_5sd")), - p0_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p0_5sd_usd")), - p1_5sd: MetricPattern4::new(client.clone(), _m(&acc, "p1_5sd")), - p1_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p1_5sd_usd")), - p1sd: MetricPattern4::new(client.clone(), _m(&acc, "p1sd")), - p1sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p1sd_usd")), - p2_5sd: MetricPattern4::new(client.clone(), _m(&acc, "p2_5sd")), - p2_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p2_5sd_usd")), - p2sd: MetricPattern4::new(client.clone(), _m(&acc, "p2sd")), - p2sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p2sd_usd")), - p3sd: MetricPattern4::new(client.clone(), _m(&acc, "p3sd")), - p3sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p3sd_usd")), - sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), - sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), - zscore: MetricPattern4::new(client.clone(), _m(&acc, "zscore")), + realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), + realized_value: DifficultyAdjustmentPattern::new(client.clone(), _m(&acc, "realized_value")), + sell_side_risk_ratio: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), + sell_side_risk_ratio_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), + sell_side_risk_ratio_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sopr: MetricPattern22::new(client.clone(), _m(&acc, "sopr")), + sopr_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_30d_ema")), + sopr_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_7d_ema")), + total_realized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_realized_pnl")), + value_created: MetricPattern26::new(client.clone(), _m(&acc, "value_created")), + value_created_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_created_sum")), + value_destroyed: MetricPattern26::new(client.clone(), _m(&acc, "value_destroyed")), + value_destroyed_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_destroyed_sum")), } } } /// Pattern struct for repeated tree structure. pub struct RealizedPattern2 { - pub mvrv: MetricPattern4, + pub mvrv: MetricPattern5, pub neg_realized_loss: BlockCountPattern, pub net_realized_pnl: BlockCountPattern, - pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, - pub net_realized_pnl_rel_to_realized_cap: MetricPattern25, + pub net_realized_pnl_cumulative_30d_delta: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5, + pub net_realized_pnl_rel_to_realized_cap: BlockCountPattern, pub realized_cap: MetricPattern1, - pub realized_cap_30d_delta: MetricPattern4, + pub realized_cap_30d_delta: MetricPattern5, pub realized_cap_rel_to_own_market_cap: MetricPattern1, pub realized_loss: BlockCountPattern, - pub realized_loss_rel_to_realized_cap: MetricPattern25, + pub realized_loss_rel_to_realized_cap: BlockCountPattern, pub realized_price: MetricPattern1, pub realized_price_extra: ActivePriceRatioPattern, pub realized_profit: BlockCountPattern, - pub realized_profit_rel_to_realized_cap: MetricPattern25, - pub realized_profit_to_loss_ratio: MetricPattern21, - pub realized_value: MetricPattern1, - pub sell_side_risk_ratio: MetricPattern21, - pub sell_side_risk_ratio_30d_ema: MetricPattern21, - pub sell_side_risk_ratio_7d_ema: MetricPattern21, - pub sopr: MetricPattern21, - pub sopr_30d_ema: MetricPattern21, - pub sopr_7d_ema: MetricPattern21, - pub total_realized_pnl: TotalRealizedPnlPattern, - pub value_created: MetricPattern1, - pub value_destroyed: MetricPattern1, + pub realized_profit_rel_to_realized_cap: BlockCountPattern, + pub realized_profit_to_loss_ratio: MetricPattern22, + pub realized_value: DifficultyAdjustmentPattern, + pub sell_side_risk_ratio: MetricPattern22, + pub sell_side_risk_ratio_30d_ema: MetricPattern22, + pub sell_side_risk_ratio_7d_ema: MetricPattern22, + pub sopr: MetricPattern22, + pub sopr_30d_ema: MetricPattern22, + pub sopr_7d_ema: MetricPattern22, + pub total_realized_pnl: MetricPattern1, + pub value_created: MetricPattern26, + pub value_created_sum: MetricPattern2, + pub value_destroyed: MetricPattern26, + pub value_destroyed_sum: MetricPattern2, } impl RealizedPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), + mvrv: MetricPattern5::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), - net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), - net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), - net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), - net_realized_pnl_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + net_realized_pnl_cumulative_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), + net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), + net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), + net_realized_pnl_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap")), - realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), + realized_cap_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_cap_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), - realized_loss_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), + realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: ActivePriceRatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), - realized_profit_to_loss_ratio: MetricPattern21::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), - realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), - sell_side_risk_ratio: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), - sell_side_risk_ratio_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), - sell_side_risk_ratio_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), - sopr: MetricPattern21::new(client.clone(), _m(&acc, "sopr")), - sopr_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_30d_ema")), - sopr_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_7d_ema")), - total_realized_pnl: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "total_realized_pnl")), - value_created: MetricPattern1::new(client.clone(), _m(&acc, "value_created")), - value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "value_destroyed")), + realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), + realized_profit_to_loss_ratio: MetricPattern22::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), + realized_value: DifficultyAdjustmentPattern::new(client.clone(), _m(&acc, "realized_value")), + sell_side_risk_ratio: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), + sell_side_risk_ratio_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), + sell_side_risk_ratio_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sopr: MetricPattern22::new(client.clone(), _m(&acc, "sopr")), + sopr_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_30d_ema")), + sopr_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_7d_ema")), + total_realized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_realized_pnl")), + value_created: MetricPattern26::new(client.clone(), _m(&acc, "value_created")), + value_created_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_created_sum")), + value_destroyed: MetricPattern26::new(client.clone(), _m(&acc, "value_destroyed")), + value_destroyed_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_destroyed_sum")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct Ratio1ySdPattern { + pub _0sd_usd: MetricPattern5, + pub m0_5sd: MetricPattern5, + pub m0_5sd_usd: MetricPattern5, + pub m1_5sd: MetricPattern5, + pub m1_5sd_usd: MetricPattern5, + pub m1sd: MetricPattern5, + pub m1sd_usd: MetricPattern5, + pub m2_5sd: MetricPattern5, + pub m2_5sd_usd: MetricPattern5, + pub m2sd: MetricPattern5, + pub m2sd_usd: MetricPattern5, + pub m3sd: MetricPattern5, + pub m3sd_usd: MetricPattern5, + pub p0_5sd: MetricPattern5, + pub p0_5sd_usd: MetricPattern5, + pub p1_5sd: MetricPattern5, + pub p1_5sd_usd: MetricPattern5, + pub p1sd: MetricPattern5, + pub p1sd_usd: MetricPattern5, + pub p2_5sd: MetricPattern5, + pub p2_5sd_usd: MetricPattern5, + pub p2sd: MetricPattern5, + pub p2sd_usd: MetricPattern5, + pub p3sd: MetricPattern5, + pub p3sd_usd: MetricPattern5, + pub sd: MetricPattern5, + pub sma: MetricPattern5, + pub zscore: MetricPattern5, +} + +impl Ratio1ySdPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + _0sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "0sd_usd")), + m0_5sd: MetricPattern5::new(client.clone(), _m(&acc, "m0_5sd")), + m0_5sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "m0_5sd_usd")), + m1_5sd: MetricPattern5::new(client.clone(), _m(&acc, "m1_5sd")), + m1_5sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "m1_5sd_usd")), + m1sd: MetricPattern5::new(client.clone(), _m(&acc, "m1sd")), + m1sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "m1sd_usd")), + m2_5sd: MetricPattern5::new(client.clone(), _m(&acc, "m2_5sd")), + m2_5sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "m2_5sd_usd")), + m2sd: MetricPattern5::new(client.clone(), _m(&acc, "m2sd")), + m2sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "m2sd_usd")), + m3sd: MetricPattern5::new(client.clone(), _m(&acc, "m3sd")), + m3sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "m3sd_usd")), + p0_5sd: MetricPattern5::new(client.clone(), _m(&acc, "p0_5sd")), + p0_5sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "p0_5sd_usd")), + p1_5sd: MetricPattern5::new(client.clone(), _m(&acc, "p1_5sd")), + p1_5sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "p1_5sd_usd")), + p1sd: MetricPattern5::new(client.clone(), _m(&acc, "p1sd")), + p1sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "p1sd_usd")), + p2_5sd: MetricPattern5::new(client.clone(), _m(&acc, "p2_5sd")), + p2_5sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "p2_5sd_usd")), + p2sd: MetricPattern5::new(client.clone(), _m(&acc, "p2sd")), + p2sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "p2sd_usd")), + p3sd: MetricPattern5::new(client.clone(), _m(&acc, "p3sd")), + p3sd_usd: MetricPattern5::new(client.clone(), _m(&acc, "p3sd_usd")), + sd: MetricPattern5::new(client.clone(), _m(&acc, "sd")), + sma: MetricPattern5::new(client.clone(), _m(&acc, "sma")), + zscore: MetricPattern5::new(client.clone(), _m(&acc, "zscore")), } } } /// Pattern struct for repeated tree structure. pub struct RealizedPattern { - pub mvrv: MetricPattern4, + pub mvrv: MetricPattern5, pub neg_realized_loss: BlockCountPattern, pub net_realized_pnl: BlockCountPattern, - pub net_realized_pnl_cumulative_30d_delta: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4, - pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4, - pub net_realized_pnl_rel_to_realized_cap: MetricPattern25, + pub net_realized_pnl_cumulative_30d_delta: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5, + pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5, + pub net_realized_pnl_rel_to_realized_cap: BlockCountPattern, pub realized_cap: MetricPattern1, - pub realized_cap_30d_delta: MetricPattern4, + pub realized_cap_30d_delta: MetricPattern5, pub realized_loss: BlockCountPattern, - pub realized_loss_rel_to_realized_cap: MetricPattern25, + pub realized_loss_rel_to_realized_cap: BlockCountPattern, pub realized_price: MetricPattern1, pub realized_price_extra: RealizedPriceExtraPattern, pub realized_profit: BlockCountPattern, - pub realized_profit_rel_to_realized_cap: MetricPattern25, - pub realized_value: MetricPattern1, - pub sell_side_risk_ratio: MetricPattern21, - pub sell_side_risk_ratio_30d_ema: MetricPattern21, - pub sell_side_risk_ratio_7d_ema: MetricPattern21, - pub sopr: MetricPattern21, - pub sopr_30d_ema: MetricPattern21, - pub sopr_7d_ema: MetricPattern21, - pub total_realized_pnl: TotalRealizedPnlPattern, - pub value_created: MetricPattern1, - pub value_destroyed: MetricPattern1, + pub realized_profit_rel_to_realized_cap: BlockCountPattern, + pub realized_value: DifficultyAdjustmentPattern, + pub sell_side_risk_ratio: MetricPattern22, + pub sell_side_risk_ratio_30d_ema: MetricPattern22, + pub sell_side_risk_ratio_7d_ema: MetricPattern22, + pub sopr: MetricPattern22, + pub sopr_30d_ema: MetricPattern22, + pub sopr_7d_ema: MetricPattern22, + pub total_realized_pnl: MetricPattern1, + pub value_created: MetricPattern26, + pub value_created_sum: MetricPattern2, + pub value_destroyed: MetricPattern26, + pub value_destroyed_sum: MetricPattern2, } impl RealizedPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - mvrv: MetricPattern4::new(client.clone(), _m(&acc, "mvrv")), + mvrv: MetricPattern5::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "neg_realized_loss")), net_realized_pnl: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), - net_realized_pnl_cumulative_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), - net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), - net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), - net_realized_pnl_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), + net_realized_pnl_cumulative_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta")), + net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_market_cap")), + net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5::new(client.clone(), _m(&acc, "net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap")), + net_realized_pnl_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap")), - realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), + realized_cap_30d_delta: MetricPattern5::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), - realized_loss_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), + realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RealizedPriceExtraPattern::new(client.clone(), _m(&acc, "realized_price")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_rel_to_realized_cap: MetricPattern25::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), - realized_value: MetricPattern1::new(client.clone(), _m(&acc, "realized_value")), - sell_side_risk_ratio: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), - sell_side_risk_ratio_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), - sell_side_risk_ratio_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), - sopr: MetricPattern21::new(client.clone(), _m(&acc, "sopr")), - sopr_30d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_30d_ema")), - sopr_7d_ema: MetricPattern21::new(client.clone(), _m(&acc, "sopr_7d_ema")), - total_realized_pnl: TotalRealizedPnlPattern::new(client.clone(), _m(&acc, "total_realized_pnl")), - value_created: MetricPattern1::new(client.clone(), _m(&acc, "value_created")), - value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "value_destroyed")), + realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), + realized_value: DifficultyAdjustmentPattern::new(client.clone(), _m(&acc, "realized_value")), + sell_side_risk_ratio: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), + sell_side_risk_ratio_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_30d_ema")), + sell_side_risk_ratio_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sell_side_risk_ratio_7d_ema")), + sopr: MetricPattern22::new(client.clone(), _m(&acc, "sopr")), + sopr_30d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_30d_ema")), + sopr_7d_ema: MetricPattern22::new(client.clone(), _m(&acc, "sopr_7d_ema")), + total_realized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_realized_pnl")), + value_created: MetricPattern26::new(client.clone(), _m(&acc, "value_created")), + value_created_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_created_sum")), + value_destroyed: MetricPattern26::new(client.clone(), _m(&acc, "value_destroyed")), + value_destroyed_sum: MetricPattern2::new(client.clone(), _m(&acc, "value_destroyed_sum")), } } } /// Pattern struct for repeated tree structure. pub struct Price111dSmaPattern { - pub price: MetricPattern4, - pub ratio: MetricPattern4, - pub ratio_1m_sma: MetricPattern4, - pub ratio_1w_sma: MetricPattern4, + pub price: MetricPattern5, + pub ratio: MetricPattern5, + pub ratio_1m_sma: MetricPattern5, + pub ratio_1w_sma: MetricPattern5, pub ratio_1y_sd: Ratio1ySdPattern, pub ratio_2y_sd: Ratio1ySdPattern, pub ratio_4y_sd: Ratio1ySdPattern, - pub ratio_pct1: MetricPattern4, - pub ratio_pct1_usd: MetricPattern4, - pub ratio_pct2: MetricPattern4, - pub ratio_pct2_usd: MetricPattern4, - pub ratio_pct5: MetricPattern4, - pub ratio_pct5_usd: MetricPattern4, - pub ratio_pct95: MetricPattern4, - pub ratio_pct95_usd: MetricPattern4, - pub ratio_pct98: MetricPattern4, - pub ratio_pct98_usd: MetricPattern4, - pub ratio_pct99: MetricPattern4, - pub ratio_pct99_usd: MetricPattern4, + pub ratio_pct1: MetricPattern5, + pub ratio_pct1_usd: MetricPattern5, + pub ratio_pct2: MetricPattern5, + pub ratio_pct2_usd: MetricPattern5, + pub ratio_pct5: MetricPattern5, + pub ratio_pct5_usd: MetricPattern5, + pub ratio_pct95: MetricPattern5, + pub ratio_pct95_usd: MetricPattern5, + pub ratio_pct98: MetricPattern5, + pub ratio_pct98_usd: MetricPattern5, + pub ratio_pct99: MetricPattern5, + pub ratio_pct99_usd: MetricPattern5, pub ratio_sd: Ratio1ySdPattern, } @@ -3315,100 +3427,100 @@ impl Price111dSmaPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - price: MetricPattern4::new(client.clone(), acc.clone()), - ratio: MetricPattern4::new(client.clone(), _m(&acc, "ratio")), - ratio_1m_sma: MetricPattern4::new(client.clone(), _m(&acc, "ratio_1m_sma")), - ratio_1w_sma: MetricPattern4::new(client.clone(), _m(&acc, "ratio_1w_sma")), + price: MetricPattern5::new(client.clone(), acc.clone()), + ratio: MetricPattern5::new(client.clone(), _m(&acc, "ratio")), + ratio_1m_sma: MetricPattern5::new(client.clone(), _m(&acc, "ratio_1m_sma")), + ratio_1w_sma: MetricPattern5::new(client.clone(), _m(&acc, "ratio_1w_sma")), ratio_1y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio_1y")), ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio_2y")), ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio_4y")), - ratio_pct1: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct1")), - ratio_pct1_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct1_usd")), - ratio_pct2: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct2")), - ratio_pct2_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct2_usd")), - ratio_pct5: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct5")), - ratio_pct5_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct5_usd")), - ratio_pct95: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct95")), - ratio_pct95_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct95_usd")), - ratio_pct98: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct98")), - ratio_pct98_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct98_usd")), - ratio_pct99: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct99")), - ratio_pct99_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct99_usd")), + ratio_pct1: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct1")), + ratio_pct1_usd: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct1_usd")), + ratio_pct2: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct2")), + ratio_pct2_usd: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct2_usd")), + ratio_pct5: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct5")), + ratio_pct5_usd: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct5_usd")), + ratio_pct95: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct95")), + ratio_pct95_usd: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct95_usd")), + ratio_pct98: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct98")), + ratio_pct98_usd: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct98_usd")), + ratio_pct99: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct99")), + ratio_pct99_usd: MetricPattern5::new(client.clone(), _m(&acc, "ratio_pct99_usd")), ratio_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio")), } } } /// Pattern struct for repeated tree structure. -pub struct PercentilesPattern { - pub cost_basis_pct05: MetricPattern4, - pub cost_basis_pct10: MetricPattern4, - pub cost_basis_pct15: MetricPattern4, - pub cost_basis_pct20: MetricPattern4, - pub cost_basis_pct25: MetricPattern4, - pub cost_basis_pct30: MetricPattern4, - pub cost_basis_pct35: MetricPattern4, - pub cost_basis_pct40: MetricPattern4, - pub cost_basis_pct45: MetricPattern4, - pub cost_basis_pct50: MetricPattern4, - pub cost_basis_pct55: MetricPattern4, - pub cost_basis_pct60: MetricPattern4, - pub cost_basis_pct65: MetricPattern4, - pub cost_basis_pct70: MetricPattern4, - pub cost_basis_pct75: MetricPattern4, - pub cost_basis_pct80: MetricPattern4, - pub cost_basis_pct85: MetricPattern4, - pub cost_basis_pct90: MetricPattern4, - pub cost_basis_pct95: MetricPattern4, +pub struct PercentilesPattern2 { + pub cost_basis_pct05: MetricPattern5, + pub cost_basis_pct10: MetricPattern5, + pub cost_basis_pct15: MetricPattern5, + pub cost_basis_pct20: MetricPattern5, + pub cost_basis_pct25: MetricPattern5, + pub cost_basis_pct30: MetricPattern5, + pub cost_basis_pct35: MetricPattern5, + pub cost_basis_pct40: MetricPattern5, + pub cost_basis_pct45: MetricPattern5, + pub cost_basis_pct50: MetricPattern5, + pub cost_basis_pct55: MetricPattern5, + pub cost_basis_pct60: MetricPattern5, + pub cost_basis_pct65: MetricPattern5, + pub cost_basis_pct70: MetricPattern5, + pub cost_basis_pct75: MetricPattern5, + pub cost_basis_pct80: MetricPattern5, + pub cost_basis_pct85: MetricPattern5, + pub cost_basis_pct90: MetricPattern5, + pub cost_basis_pct95: MetricPattern5, } -impl PercentilesPattern { +impl PercentilesPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - cost_basis_pct05: MetricPattern4::new(client.clone(), _m(&acc, "pct05")), - cost_basis_pct10: MetricPattern4::new(client.clone(), _m(&acc, "pct10")), - cost_basis_pct15: MetricPattern4::new(client.clone(), _m(&acc, "pct15")), - cost_basis_pct20: MetricPattern4::new(client.clone(), _m(&acc, "pct20")), - cost_basis_pct25: MetricPattern4::new(client.clone(), _m(&acc, "pct25")), - cost_basis_pct30: MetricPattern4::new(client.clone(), _m(&acc, "pct30")), - cost_basis_pct35: MetricPattern4::new(client.clone(), _m(&acc, "pct35")), - cost_basis_pct40: MetricPattern4::new(client.clone(), _m(&acc, "pct40")), - cost_basis_pct45: MetricPattern4::new(client.clone(), _m(&acc, "pct45")), - cost_basis_pct50: MetricPattern4::new(client.clone(), _m(&acc, "pct50")), - cost_basis_pct55: MetricPattern4::new(client.clone(), _m(&acc, "pct55")), - cost_basis_pct60: MetricPattern4::new(client.clone(), _m(&acc, "pct60")), - cost_basis_pct65: MetricPattern4::new(client.clone(), _m(&acc, "pct65")), - cost_basis_pct70: MetricPattern4::new(client.clone(), _m(&acc, "pct70")), - cost_basis_pct75: MetricPattern4::new(client.clone(), _m(&acc, "pct75")), - cost_basis_pct80: MetricPattern4::new(client.clone(), _m(&acc, "pct80")), - cost_basis_pct85: MetricPattern4::new(client.clone(), _m(&acc, "pct85")), - cost_basis_pct90: MetricPattern4::new(client.clone(), _m(&acc, "pct90")), - cost_basis_pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")), + cost_basis_pct05: MetricPattern5::new(client.clone(), _m(&acc, "pct05")), + cost_basis_pct10: MetricPattern5::new(client.clone(), _m(&acc, "pct10")), + cost_basis_pct15: MetricPattern5::new(client.clone(), _m(&acc, "pct15")), + cost_basis_pct20: MetricPattern5::new(client.clone(), _m(&acc, "pct20")), + cost_basis_pct25: MetricPattern5::new(client.clone(), _m(&acc, "pct25")), + cost_basis_pct30: MetricPattern5::new(client.clone(), _m(&acc, "pct30")), + cost_basis_pct35: MetricPattern5::new(client.clone(), _m(&acc, "pct35")), + cost_basis_pct40: MetricPattern5::new(client.clone(), _m(&acc, "pct40")), + cost_basis_pct45: MetricPattern5::new(client.clone(), _m(&acc, "pct45")), + cost_basis_pct50: MetricPattern5::new(client.clone(), _m(&acc, "pct50")), + cost_basis_pct55: MetricPattern5::new(client.clone(), _m(&acc, "pct55")), + cost_basis_pct60: MetricPattern5::new(client.clone(), _m(&acc, "pct60")), + cost_basis_pct65: MetricPattern5::new(client.clone(), _m(&acc, "pct65")), + cost_basis_pct70: MetricPattern5::new(client.clone(), _m(&acc, "pct70")), + cost_basis_pct75: MetricPattern5::new(client.clone(), _m(&acc, "pct75")), + cost_basis_pct80: MetricPattern5::new(client.clone(), _m(&acc, "pct80")), + cost_basis_pct85: MetricPattern5::new(client.clone(), _m(&acc, "pct85")), + cost_basis_pct90: MetricPattern5::new(client.clone(), _m(&acc, "pct90")), + cost_basis_pct95: MetricPattern5::new(client.clone(), _m(&acc, "pct95")), } } } /// Pattern struct for repeated tree structure. pub struct ActivePriceRatioPattern { - pub ratio: MetricPattern4, - pub ratio_1m_sma: MetricPattern4, - pub ratio_1w_sma: MetricPattern4, + pub ratio: MetricPattern5, + pub ratio_1m_sma: MetricPattern5, + pub ratio_1w_sma: MetricPattern5, pub ratio_1y_sd: Ratio1ySdPattern, pub ratio_2y_sd: Ratio1ySdPattern, pub ratio_4y_sd: Ratio1ySdPattern, - pub ratio_pct1: MetricPattern4, - pub ratio_pct1_usd: MetricPattern4, - pub ratio_pct2: MetricPattern4, - pub ratio_pct2_usd: MetricPattern4, - pub ratio_pct5: MetricPattern4, - pub ratio_pct5_usd: MetricPattern4, - pub ratio_pct95: MetricPattern4, - pub ratio_pct95_usd: MetricPattern4, - pub ratio_pct98: MetricPattern4, - pub ratio_pct98_usd: MetricPattern4, - pub ratio_pct99: MetricPattern4, - pub ratio_pct99_usd: MetricPattern4, + pub ratio_pct1: MetricPattern5, + pub ratio_pct1_usd: MetricPattern5, + pub ratio_pct2: MetricPattern5, + pub ratio_pct2_usd: MetricPattern5, + pub ratio_pct5: MetricPattern5, + pub ratio_pct5_usd: MetricPattern5, + pub ratio_pct95: MetricPattern5, + pub ratio_pct95_usd: MetricPattern5, + pub ratio_pct98: MetricPattern5, + pub ratio_pct98_usd: MetricPattern5, + pub ratio_pct99: MetricPattern5, + pub ratio_pct99_usd: MetricPattern5, pub ratio_sd: Ratio1ySdPattern, } @@ -3416,24 +3528,24 @@ impl ActivePriceRatioPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - ratio: MetricPattern4::new(client.clone(), acc.clone()), - ratio_1m_sma: MetricPattern4::new(client.clone(), _m(&acc, "1m_sma")), - ratio_1w_sma: MetricPattern4::new(client.clone(), _m(&acc, "1w_sma")), + ratio: MetricPattern5::new(client.clone(), acc.clone()), + ratio_1m_sma: MetricPattern5::new(client.clone(), _m(&acc, "1m_sma")), + ratio_1w_sma: MetricPattern5::new(client.clone(), _m(&acc, "1w_sma")), ratio_1y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "1y")), ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "2y")), ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "4y")), - ratio_pct1: MetricPattern4::new(client.clone(), _m(&acc, "pct1")), - ratio_pct1_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct1_usd")), - ratio_pct2: MetricPattern4::new(client.clone(), _m(&acc, "pct2")), - ratio_pct2_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct2_usd")), - ratio_pct5: MetricPattern4::new(client.clone(), _m(&acc, "pct5")), - ratio_pct5_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct5_usd")), - ratio_pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")), - ratio_pct95_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct95_usd")), - ratio_pct98: MetricPattern4::new(client.clone(), _m(&acc, "pct98")), - ratio_pct98_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct98_usd")), - ratio_pct99: MetricPattern4::new(client.clone(), _m(&acc, "pct99")), - ratio_pct99_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct99_usd")), + ratio_pct1: MetricPattern5::new(client.clone(), _m(&acc, "pct1")), + ratio_pct1_usd: MetricPattern5::new(client.clone(), _m(&acc, "pct1_usd")), + ratio_pct2: MetricPattern5::new(client.clone(), _m(&acc, "pct2")), + ratio_pct2_usd: MetricPattern5::new(client.clone(), _m(&acc, "pct2_usd")), + ratio_pct5: MetricPattern5::new(client.clone(), _m(&acc, "pct5")), + ratio_pct5_usd: MetricPattern5::new(client.clone(), _m(&acc, "pct5_usd")), + ratio_pct95: MetricPattern5::new(client.clone(), _m(&acc, "pct95")), + ratio_pct95_usd: MetricPattern5::new(client.clone(), _m(&acc, "pct95_usd")), + ratio_pct98: MetricPattern5::new(client.clone(), _m(&acc, "pct98")), + ratio_pct98_usd: MetricPattern5::new(client.clone(), _m(&acc, "pct98_usd")), + ratio_pct99: MetricPattern5::new(client.clone(), _m(&acc, "pct99")), + ratio_pct99_usd: MetricPattern5::new(client.clone(), _m(&acc, "pct99_usd")), ratio_sd: Ratio1ySdPattern::new(client.clone(), acc.clone()), } } @@ -3441,48 +3553,48 @@ impl ActivePriceRatioPattern { /// Pattern struct for repeated tree structure. pub struct RelativePattern5 { - pub neg_unrealized_loss_rel_to_market_cap: MetricPattern5, - pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern5, - pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5, + pub neg_unrealized_loss_rel_to_market_cap: MetricPattern3, + pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern3, + pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3, pub net_unrealized_pnl_rel_to_market_cap: MetricPattern3, pub net_unrealized_pnl_rel_to_own_market_cap: MetricPattern3, pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3, - pub nupl: MetricPattern4, - pub supply_in_loss_rel_to_circulating_supply: MetricPattern5, - pub supply_in_loss_rel_to_own_supply: MetricPattern5, - pub supply_in_profit_rel_to_circulating_supply: MetricPattern5, - pub supply_in_profit_rel_to_own_supply: MetricPattern5, - pub supply_rel_to_circulating_supply: MetricPattern4, - pub unrealized_loss_rel_to_market_cap: MetricPattern5, - pub unrealized_loss_rel_to_own_market_cap: MetricPattern5, - pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5, - pub unrealized_profit_rel_to_market_cap: MetricPattern5, - pub unrealized_profit_rel_to_own_market_cap: MetricPattern5, - pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5, + pub nupl: MetricPattern5, + pub supply_in_loss_rel_to_circulating_supply: MetricPattern3, + pub supply_in_loss_rel_to_own_supply: MetricPattern3, + pub supply_in_profit_rel_to_circulating_supply: MetricPattern3, + pub supply_in_profit_rel_to_own_supply: MetricPattern3, + pub supply_rel_to_circulating_supply: MetricPattern5, + pub unrealized_loss_rel_to_market_cap: MetricPattern3, + pub unrealized_loss_rel_to_own_market_cap: MetricPattern3, + pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3, + pub unrealized_profit_rel_to_market_cap: MetricPattern3, + pub unrealized_profit_rel_to_own_market_cap: MetricPattern3, + pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3, } impl RelativePattern5 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - neg_unrealized_loss_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), - neg_unrealized_loss_rel_to_own_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), - neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), + neg_unrealized_loss_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), + neg_unrealized_loss_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), + neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), net_unrealized_pnl_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")), net_unrealized_pnl_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), - nupl: MetricPattern4::new(client.clone(), _m(&acc, "nupl")), - supply_in_loss_rel_to_circulating_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), - supply_in_loss_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_circulating_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), - unrealized_loss_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), - unrealized_loss_rel_to_own_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), - unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), - unrealized_profit_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), - unrealized_profit_rel_to_own_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), - unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), + nupl: MetricPattern5::new(client.clone(), _m(&acc, "nupl")), + supply_in_loss_rel_to_circulating_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), + supply_in_loss_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_circulating_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), + supply_rel_to_circulating_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), + unrealized_loss_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), + unrealized_loss_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), + unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), + unrealized_profit_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), + unrealized_profit_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), + unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), } } } @@ -3490,15 +3602,15 @@ impl RelativePattern5 { /// Pattern struct for repeated tree structure. pub struct AXbtPattern { pub _1d_dominance: BlockCountPattern, - pub _1m_blocks_mined: MetricPattern4, - pub _1m_dominance: MetricPattern4, - pub _1w_blocks_mined: MetricPattern4, - pub _1w_dominance: MetricPattern4, - pub _1y_blocks_mined: MetricPattern4, - pub _1y_dominance: MetricPattern4, + pub _1m_blocks_mined: MetricPattern5, + pub _1m_dominance: MetricPattern5, + pub _1w_blocks_mined: MetricPattern5, + pub _1w_dominance: MetricPattern5, + pub _1y_blocks_mined: MetricPattern5, + pub _1y_dominance: MetricPattern5, pub blocks_mined: BlockCountPattern, pub coinbase: UnclaimedRewardsPattern, - pub days_since_block: MetricPattern4, + pub days_since_block: MetricPattern5, pub dominance: BlockCountPattern, pub fee: SentPattern, pub subsidy: SentPattern, @@ -3509,56 +3621,56 @@ impl AXbtPattern { pub fn new(client: Arc, acc: String) -> Self { Self { _1d_dominance: BlockCountPattern::new(client.clone(), _m(&acc, "1d_dominance")), - _1m_blocks_mined: MetricPattern4::new(client.clone(), _m(&acc, "1m_blocks_mined")), - _1m_dominance: MetricPattern4::new(client.clone(), _m(&acc, "1m_dominance")), - _1w_blocks_mined: MetricPattern4::new(client.clone(), _m(&acc, "1w_blocks_mined")), - _1w_dominance: MetricPattern4::new(client.clone(), _m(&acc, "1w_dominance")), - _1y_blocks_mined: MetricPattern4::new(client.clone(), _m(&acc, "1y_blocks_mined")), - _1y_dominance: MetricPattern4::new(client.clone(), _m(&acc, "1y_dominance")), + _1m_blocks_mined: MetricPattern5::new(client.clone(), _m(&acc, "1m_blocks_mined")), + _1m_dominance: MetricPattern5::new(client.clone(), _m(&acc, "1m_dominance")), + _1w_blocks_mined: MetricPattern5::new(client.clone(), _m(&acc, "1w_blocks_mined")), + _1w_dominance: MetricPattern5::new(client.clone(), _m(&acc, "1w_dominance")), + _1y_blocks_mined: MetricPattern5::new(client.clone(), _m(&acc, "1y_blocks_mined")), + _1y_dominance: MetricPattern5::new(client.clone(), _m(&acc, "1y_dominance")), blocks_mined: BlockCountPattern::new(client.clone(), _m(&acc, "blocks_mined")), coinbase: UnclaimedRewardsPattern::new(client.clone(), _m(&acc, "coinbase")), - days_since_block: MetricPattern4::new(client.clone(), _m(&acc, "days_since_block")), + days_since_block: MetricPattern5::new(client.clone(), _m(&acc, "days_since_block")), dominance: BlockCountPattern::new(client.clone(), _m(&acc, "dominance")), - fee: SentPattern::new(client.clone(), _m(&acc, "fee")), - subsidy: SentPattern::new(client.clone(), _m(&acc, "subsidy")), + fee: SentPattern::new(client.clone(), acc.clone()), + subsidy: SentPattern::new(client.clone(), acc.clone()), } } } /// Pattern struct for repeated tree structure. pub struct PriceAgoPattern { - pub _10y: MetricPattern4, - pub _1d: MetricPattern4, - pub _1m: MetricPattern4, - pub _1w: MetricPattern4, - pub _1y: MetricPattern4, - pub _2y: MetricPattern4, - pub _3m: MetricPattern4, - pub _3y: MetricPattern4, - pub _4y: MetricPattern4, - pub _5y: MetricPattern4, - pub _6m: MetricPattern4, - pub _6y: MetricPattern4, - pub _8y: MetricPattern4, + pub _10y: MetricPattern5, + pub _1d: MetricPattern5, + pub _1m: MetricPattern5, + pub _1w: MetricPattern5, + pub _1y: MetricPattern5, + pub _2y: MetricPattern5, + pub _3m: MetricPattern5, + pub _3y: MetricPattern5, + pub _4y: MetricPattern5, + pub _5y: MetricPattern5, + pub _6m: MetricPattern5, + pub _6y: MetricPattern5, + pub _8y: MetricPattern5, } impl PriceAgoPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _10y: MetricPattern4::new(client.clone(), _m(&acc, "10y_ago")), - _1d: MetricPattern4::new(client.clone(), _m(&acc, "1d_ago")), - _1m: MetricPattern4::new(client.clone(), _m(&acc, "1m_ago")), - _1w: MetricPattern4::new(client.clone(), _m(&acc, "1w_ago")), - _1y: MetricPattern4::new(client.clone(), _m(&acc, "1y_ago")), - _2y: MetricPattern4::new(client.clone(), _m(&acc, "2y_ago")), - _3m: MetricPattern4::new(client.clone(), _m(&acc, "3m_ago")), - _3y: MetricPattern4::new(client.clone(), _m(&acc, "3y_ago")), - _4y: MetricPattern4::new(client.clone(), _m(&acc, "4y_ago")), - _5y: MetricPattern4::new(client.clone(), _m(&acc, "5y_ago")), - _6m: MetricPattern4::new(client.clone(), _m(&acc, "6m_ago")), - _6y: MetricPattern4::new(client.clone(), _m(&acc, "6y_ago")), - _8y: MetricPattern4::new(client.clone(), _m(&acc, "8y_ago")), + _10y: MetricPattern5::new(client.clone(), _m(&acc, "10y_ago")), + _1d: MetricPattern5::new(client.clone(), _m(&acc, "1d_ago")), + _1m: MetricPattern5::new(client.clone(), _m(&acc, "1m_ago")), + _1w: MetricPattern5::new(client.clone(), _m(&acc, "1w_ago")), + _1y: MetricPattern5::new(client.clone(), _m(&acc, "1y_ago")), + _2y: MetricPattern5::new(client.clone(), _m(&acc, "2y_ago")), + _3m: MetricPattern5::new(client.clone(), _m(&acc, "3m_ago")), + _3y: MetricPattern5::new(client.clone(), _m(&acc, "3y_ago")), + _4y: MetricPattern5::new(client.clone(), _m(&acc, "4y_ago")), + _5y: MetricPattern5::new(client.clone(), _m(&acc, "5y_ago")), + _6m: MetricPattern5::new(client.clone(), _m(&acc, "6m_ago")), + _6y: MetricPattern5::new(client.clone(), _m(&acc, "6y_ago")), + _8y: MetricPattern5::new(client.clone(), _m(&acc, "8y_ago")), } } } @@ -3600,201 +3712,135 @@ impl PeriodLumpSumStackPattern { } /// Pattern struct for repeated tree structure. -pub struct PeriodAvgPricePattern { - pub _10y: MetricPattern4, - pub _1m: MetricPattern4, - pub _1w: MetricPattern4, - pub _1y: MetricPattern4, - pub _2y: MetricPattern4, - pub _3m: MetricPattern4, - pub _3y: MetricPattern4, - pub _4y: MetricPattern4, - pub _5y: MetricPattern4, - pub _6m: MetricPattern4, - pub _6y: MetricPattern4, - pub _8y: MetricPattern4, +pub struct PeriodAveragePricePattern { + pub _10y: MetricPattern5, + pub _1m: MetricPattern5, + pub _1w: MetricPattern5, + pub _1y: MetricPattern5, + pub _2y: MetricPattern5, + pub _3m: MetricPattern5, + pub _3y: MetricPattern5, + pub _4y: MetricPattern5, + pub _5y: MetricPattern5, + pub _6m: MetricPattern5, + pub _6y: MetricPattern5, + pub _8y: MetricPattern5, } -impl PeriodAvgPricePattern { +impl PeriodAveragePricePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _10y: MetricPattern4::new(client.clone(), if acc.is_empty() { "10y".to_string() } else { format!("10y_{acc}") }), - _1m: MetricPattern4::new(client.clone(), if acc.is_empty() { "1m".to_string() } else { format!("1m_{acc}") }), - _1w: MetricPattern4::new(client.clone(), if acc.is_empty() { "1w".to_string() } else { format!("1w_{acc}") }), - _1y: MetricPattern4::new(client.clone(), if acc.is_empty() { "1y".to_string() } else { format!("1y_{acc}") }), - _2y: MetricPattern4::new(client.clone(), if acc.is_empty() { "2y".to_string() } else { format!("2y_{acc}") }), - _3m: MetricPattern4::new(client.clone(), if acc.is_empty() { "3m".to_string() } else { format!("3m_{acc}") }), - _3y: MetricPattern4::new(client.clone(), if acc.is_empty() { "3y".to_string() } else { format!("3y_{acc}") }), - _4y: MetricPattern4::new(client.clone(), if acc.is_empty() { "4y".to_string() } else { format!("4y_{acc}") }), - _5y: MetricPattern4::new(client.clone(), if acc.is_empty() { "5y".to_string() } else { format!("5y_{acc}") }), - _6m: MetricPattern4::new(client.clone(), if acc.is_empty() { "6m".to_string() } else { format!("6m_{acc}") }), - _6y: MetricPattern4::new(client.clone(), if acc.is_empty() { "6y".to_string() } else { format!("6y_{acc}") }), - _8y: MetricPattern4::new(client.clone(), if acc.is_empty() { "8y".to_string() } else { format!("8y_{acc}") }), + _10y: MetricPattern5::new(client.clone(), if acc.is_empty() { "10y".to_string() } else { format!("10y_{acc}") }), + _1m: MetricPattern5::new(client.clone(), if acc.is_empty() { "1m".to_string() } else { format!("1m_{acc}") }), + _1w: MetricPattern5::new(client.clone(), if acc.is_empty() { "1w".to_string() } else { format!("1w_{acc}") }), + _1y: MetricPattern5::new(client.clone(), if acc.is_empty() { "1y".to_string() } else { format!("1y_{acc}") }), + _2y: MetricPattern5::new(client.clone(), if acc.is_empty() { "2y".to_string() } else { format!("2y_{acc}") }), + _3m: MetricPattern5::new(client.clone(), if acc.is_empty() { "3m".to_string() } else { format!("3m_{acc}") }), + _3y: MetricPattern5::new(client.clone(), if acc.is_empty() { "3y".to_string() } else { format!("3y_{acc}") }), + _4y: MetricPattern5::new(client.clone(), if acc.is_empty() { "4y".to_string() } else { format!("4y_{acc}") }), + _5y: MetricPattern5::new(client.clone(), if acc.is_empty() { "5y".to_string() } else { format!("5y_{acc}") }), + _6m: MetricPattern5::new(client.clone(), if acc.is_empty() { "6m".to_string() } else { format!("6m_{acc}") }), + _6y: MetricPattern5::new(client.clone(), if acc.is_empty() { "6y".to_string() } else { format!("6y_{acc}") }), + _8y: MetricPattern5::new(client.clone(), if acc.is_empty() { "8y".to_string() } else { format!("8y_{acc}") }), } } } /// Pattern struct for repeated tree structure. -pub struct BitcoinPattern { - pub average: MetricPattern2, - pub base: MetricPattern25, - pub cumulative: MetricPattern1, - pub max: MetricPattern2, - pub median: MetricPattern21, - pub min: MetricPattern2, - pub pct10: MetricPattern21, - pub pct25: MetricPattern21, - pub pct75: MetricPattern21, - pub pct90: MetricPattern21, - pub sum: MetricPattern2, +pub struct ClassAveragePricePattern { + pub _2015: MetricPattern5, + pub _2016: MetricPattern5, + pub _2017: MetricPattern5, + pub _2018: MetricPattern5, + pub _2019: MetricPattern5, + pub _2020: MetricPattern5, + pub _2021: MetricPattern5, + pub _2022: MetricPattern5, + pub _2023: MetricPattern5, + pub _2024: MetricPattern5, + pub _2025: MetricPattern5, } -impl BitcoinPattern { +impl ClassAveragePricePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - average: MetricPattern2::new(client.clone(), _m(&acc, "avg")), - base: MetricPattern25::new(client.clone(), acc.clone()), - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), - max: MetricPattern2::new(client.clone(), _m(&acc, "max")), - median: MetricPattern21::new(client.clone(), _m(&acc, "median")), - min: MetricPattern2::new(client.clone(), _m(&acc, "min")), - pct10: MetricPattern21::new(client.clone(), _m(&acc, "pct10")), - pct25: MetricPattern21::new(client.clone(), _m(&acc, "pct25")), - pct75: MetricPattern21::new(client.clone(), _m(&acc, "pct75")), - pct90: MetricPattern21::new(client.clone(), _m(&acc, "pct90")), - sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct ClassAvgPricePattern { - pub _2015: MetricPattern4, - pub _2016: MetricPattern4, - pub _2017: MetricPattern4, - pub _2018: MetricPattern4, - pub _2019: MetricPattern4, - pub _2020: MetricPattern4, - pub _2021: MetricPattern4, - pub _2022: MetricPattern4, - pub _2023: MetricPattern4, - pub _2024: MetricPattern4, - pub _2025: MetricPattern4, -} - -impl ClassAvgPricePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_avg_price")), - _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_avg_price")), - _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_avg_price")), - _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_avg_price")), - _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_avg_price")), - _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_avg_price")), - _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_avg_price")), - _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_avg_price")), - _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_avg_price")), - _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_avg_price")), - _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_avg_price")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct RelativePattern { - pub neg_unrealized_loss_rel_to_market_cap: MetricPattern5, - pub net_unrealized_pnl_rel_to_market_cap: MetricPattern3, - pub nupl: MetricPattern4, - pub supply_in_loss_rel_to_circulating_supply: MetricPattern5, - pub supply_in_loss_rel_to_own_supply: MetricPattern5, - pub supply_in_profit_rel_to_circulating_supply: MetricPattern5, - pub supply_in_profit_rel_to_own_supply: MetricPattern5, - pub supply_rel_to_circulating_supply: MetricPattern4, - pub unrealized_loss_rel_to_market_cap: MetricPattern5, - pub unrealized_profit_rel_to_market_cap: MetricPattern5, -} - -impl RelativePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - neg_unrealized_loss_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), - net_unrealized_pnl_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")), - nupl: MetricPattern4::new(client.clone(), _m(&acc, "nupl")), - supply_in_loss_rel_to_circulating_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), - supply_in_loss_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_circulating_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), - unrealized_loss_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), - unrealized_profit_rel_to_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), + _2015: MetricPattern5::new(client.clone(), _m(&acc, "2015_average_price")), + _2016: MetricPattern5::new(client.clone(), _m(&acc, "2016_average_price")), + _2017: MetricPattern5::new(client.clone(), _m(&acc, "2017_average_price")), + _2018: MetricPattern5::new(client.clone(), _m(&acc, "2018_average_price")), + _2019: MetricPattern5::new(client.clone(), _m(&acc, "2019_average_price")), + _2020: MetricPattern5::new(client.clone(), _m(&acc, "2020_average_price")), + _2021: MetricPattern5::new(client.clone(), _m(&acc, "2021_average_price")), + _2022: MetricPattern5::new(client.clone(), _m(&acc, "2022_average_price")), + _2023: MetricPattern5::new(client.clone(), _m(&acc, "2023_average_price")), + _2024: MetricPattern5::new(client.clone(), _m(&acc, "2024_average_price")), + _2025: MetricPattern5::new(client.clone(), _m(&acc, "2025_average_price")), } } } /// Pattern struct for repeated tree structure. pub struct RelativePattern2 { - pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern5, - pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5, + pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern3, + pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3, pub net_unrealized_pnl_rel_to_own_market_cap: MetricPattern3, pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3, - pub supply_in_loss_rel_to_own_supply: MetricPattern5, - pub supply_in_profit_rel_to_own_supply: MetricPattern5, - pub unrealized_loss_rel_to_own_market_cap: MetricPattern5, - pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5, - pub unrealized_profit_rel_to_own_market_cap: MetricPattern5, - pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5, + pub supply_in_loss_rel_to_own_supply: MetricPattern3, + pub supply_in_profit_rel_to_own_supply: MetricPattern3, + pub unrealized_loss_rel_to_own_market_cap: MetricPattern3, + pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3, + pub unrealized_profit_rel_to_own_market_cap: MetricPattern3, + pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3, } impl RelativePattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - neg_unrealized_loss_rel_to_own_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), - neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), + neg_unrealized_loss_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), + neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), net_unrealized_pnl_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), - supply_in_loss_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - unrealized_loss_rel_to_own_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), - unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), - unrealized_profit_rel_to_own_market_cap: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), - unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), + supply_in_loss_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), + unrealized_loss_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), + unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), + unrealized_profit_rel_to_own_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), + unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), } } } /// Pattern struct for repeated tree structure. -pub struct BlockSizePattern { - pub average: MetricPattern1, - pub cumulative: MetricPattern1, - pub max: MetricPattern1, - pub median: MetricPattern25, - pub min: MetricPattern1, - pub pct10: MetricPattern25, - pub pct25: MetricPattern25, - pub pct75: MetricPattern25, - pub pct90: MetricPattern25, - pub sum: MetricPattern1, +pub struct RelativePattern { + pub neg_unrealized_loss_rel_to_market_cap: MetricPattern3, + pub net_unrealized_pnl_rel_to_market_cap: MetricPattern3, + pub nupl: MetricPattern5, + pub supply_in_loss_rel_to_circulating_supply: MetricPattern3, + pub supply_in_loss_rel_to_own_supply: MetricPattern3, + pub supply_in_profit_rel_to_circulating_supply: MetricPattern3, + pub supply_in_profit_rel_to_own_supply: MetricPattern3, + pub supply_rel_to_circulating_supply: MetricPattern5, + pub unrealized_loss_rel_to_market_cap: MetricPattern3, + pub unrealized_profit_rel_to_market_cap: MetricPattern3, } -impl BlockSizePattern { +impl RelativePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - average: MetricPattern1::new(client.clone(), _m(&acc, "avg")), - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), - max: MetricPattern1::new(client.clone(), _m(&acc, "max")), - median: MetricPattern25::new(client.clone(), _m(&acc, "median")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min")), - pct10: MetricPattern25::new(client.clone(), _m(&acc, "pct10")), - pct25: MetricPattern25::new(client.clone(), _m(&acc, "pct25")), - pct75: MetricPattern25::new(client.clone(), _m(&acc, "pct75")), - pct90: MetricPattern25::new(client.clone(), _m(&acc, "pct90")), - sum: MetricPattern1::new(client.clone(), _m(&acc, "sum")), + neg_unrealized_loss_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), + net_unrealized_pnl_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")), + nupl: MetricPattern5::new(client.clone(), _m(&acc, "nupl")), + supply_in_loss_rel_to_circulating_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), + supply_in_loss_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_circulating_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), + supply_rel_to_circulating_supply: MetricPattern5::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), + unrealized_loss_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), + unrealized_profit_rel_to_market_cap: MetricPattern3::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), } } } @@ -3829,84 +3875,58 @@ impl UnrealizedPattern { } } -/// Pattern struct for repeated tree structure. -pub struct BlockIntervalPattern { - pub average: MetricPattern2, - pub max: MetricPattern2, - pub median: MetricPattern21, - pub min: MetricPattern2, - pub pct10: MetricPattern21, - pub pct25: MetricPattern21, - pub pct75: MetricPattern21, - pub pct90: MetricPattern21, -} - -impl BlockIntervalPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - average: MetricPattern2::new(client.clone(), _m(&acc, "avg")), - max: MetricPattern2::new(client.clone(), _m(&acc, "max")), - median: MetricPattern21::new(client.clone(), _m(&acc, "median")), - min: MetricPattern2::new(client.clone(), _m(&acc, "min")), - pct10: MetricPattern21::new(client.clone(), _m(&acc, "pct10")), - pct25: MetricPattern21::new(client.clone(), _m(&acc, "pct25")), - pct75: MetricPattern21::new(client.clone(), _m(&acc, "pct75")), - pct90: MetricPattern21::new(client.clone(), _m(&acc, "pct90")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct AddresstypeToHeightToAddrCountPattern { - pub p2a: MetricPattern29, - pub p2pk33: MetricPattern31, - pub p2pk65: MetricPattern32, - pub p2pkh: MetricPattern33, - pub p2sh: MetricPattern34, - pub p2tr: MetricPattern35, - pub p2wpkh: MetricPattern36, - pub p2wsh: MetricPattern37, + pub p2a: MetricPattern26, + pub p2pk33: MetricPattern26, + pub p2pk65: MetricPattern26, + pub p2pkh: MetricPattern26, + pub p2sh: MetricPattern26, + pub p2tr: MetricPattern26, + pub p2wpkh: MetricPattern26, + pub p2wsh: MetricPattern26, } impl AddresstypeToHeightToAddrCountPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - p2a: MetricPattern29::new(client.clone(), if acc.is_empty() { "p2a".to_string() } else { format!("p2a_{acc}") }), - p2pk33: MetricPattern31::new(client.clone(), if acc.is_empty() { "p2pk33".to_string() } else { format!("p2pk33_{acc}") }), - p2pk65: MetricPattern32::new(client.clone(), if acc.is_empty() { "p2pk65".to_string() } else { format!("p2pk65_{acc}") }), - p2pkh: MetricPattern33::new(client.clone(), if acc.is_empty() { "p2pkh".to_string() } else { format!("p2pkh_{acc}") }), - p2sh: MetricPattern34::new(client.clone(), if acc.is_empty() { "p2sh".to_string() } else { format!("p2sh_{acc}") }), - p2tr: MetricPattern35::new(client.clone(), if acc.is_empty() { "p2tr".to_string() } else { format!("p2tr_{acc}") }), - p2wpkh: MetricPattern36::new(client.clone(), if acc.is_empty() { "p2wpkh".to_string() } else { format!("p2wpkh_{acc}") }), - p2wsh: MetricPattern37::new(client.clone(), if acc.is_empty() { "p2wsh".to_string() } else { format!("p2wsh_{acc}") }), + p2a: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2a".to_string() } else { format!("p2a_{acc}") }), + p2pk33: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2pk33".to_string() } else { format!("p2pk33_{acc}") }), + p2pk65: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2pk65".to_string() } else { format!("p2pk65_{acc}") }), + p2pkh: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2pkh".to_string() } else { format!("p2pkh_{acc}") }), + p2sh: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2sh".to_string() } else { format!("p2sh_{acc}") }), + p2tr: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2tr".to_string() } else { format!("p2tr_{acc}") }), + p2wpkh: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2wpkh".to_string() } else { format!("p2wpkh_{acc}") }), + p2wsh: MetricPattern26::new(client.clone(), if acc.is_empty() { "p2wsh".to_string() } else { format!("p2wsh_{acc}") }), } } } /// Pattern struct for repeated tree structure. -pub struct PeriodCagrPattern { - pub _10y: MetricPattern4, - pub _2y: MetricPattern4, - pub _3y: MetricPattern4, - pub _4y: MetricPattern4, - pub _5y: MetricPattern4, - pub _6y: MetricPattern4, - pub _8y: MetricPattern4, +pub struct CountPattern2 { + pub average: MetricPattern2, + pub cumulative: MetricPattern6, + pub distribution: BlockIntervalPattern, + pub max: MetricPattern6, + pub min: MetricPattern6, + pub minmax: MinmaxPattern, + pub sum: MetricPattern6, + pub sum_cum: SumCumPattern, } -impl PeriodCagrPattern { +impl CountPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _10y: MetricPattern4::new(client.clone(), if acc.is_empty() { "10y".to_string() } else { format!("10y_{acc}") }), - _2y: MetricPattern4::new(client.clone(), if acc.is_empty() { "2y".to_string() } else { format!("2y_{acc}") }), - _3y: MetricPattern4::new(client.clone(), if acc.is_empty() { "3y".to_string() } else { format!("3y_{acc}") }), - _4y: MetricPattern4::new(client.clone(), if acc.is_empty() { "4y".to_string() } else { format!("4y_{acc}") }), - _5y: MetricPattern4::new(client.clone(), if acc.is_empty() { "5y".to_string() } else { format!("5y_{acc}") }), - _6y: MetricPattern4::new(client.clone(), if acc.is_empty() { "6y".to_string() } else { format!("6y_{acc}") }), - _8y: MetricPattern4::new(client.clone(), if acc.is_empty() { "8y".to_string() } else { format!("8y_{acc}") }), + average: MetricPattern2::new(client.clone(), _m(&acc, "average")), + cumulative: MetricPattern6::new(client.clone(), _m(&acc, "cumulative")), + distribution: BlockIntervalPattern::new(client.clone(), acc.clone()), + max: MetricPattern6::new(client.clone(), _m(&acc, "max")), + min: MetricPattern6::new(client.clone(), _m(&acc, "min")), + minmax: MinmaxPattern::new(client.clone(), acc.clone()), + sum: MetricPattern6::new(client.clone(), _m(&acc, "sum")), + sum_cum: SumCumPattern::new(client.clone(), acc.clone()), } } } @@ -3937,6 +3957,108 @@ impl _0satsPattern { } } +/// Pattern struct for repeated tree structure. +pub struct PeriodCagrPattern { + pub _10y: MetricPattern5, + pub _2y: MetricPattern5, + pub _3y: MetricPattern5, + pub _4y: MetricPattern5, + pub _5y: MetricPattern5, + pub _6y: MetricPattern5, + pub _8y: MetricPattern5, +} + +impl PeriodCagrPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + _10y: MetricPattern5::new(client.clone(), if acc.is_empty() { "10y".to_string() } else { format!("10y_{acc}") }), + _2y: MetricPattern5::new(client.clone(), if acc.is_empty() { "2y".to_string() } else { format!("2y_{acc}") }), + _3y: MetricPattern5::new(client.clone(), if acc.is_empty() { "3y".to_string() } else { format!("3y_{acc}") }), + _4y: MetricPattern5::new(client.clone(), if acc.is_empty() { "4y".to_string() } else { format!("4y_{acc}") }), + _5y: MetricPattern5::new(client.clone(), if acc.is_empty() { "5y".to_string() } else { format!("5y_{acc}") }), + _6y: MetricPattern5::new(client.clone(), if acc.is_empty() { "6y".to_string() } else { format!("6y_{acc}") }), + _8y: MetricPattern5::new(client.clone(), if acc.is_empty() { "8y".to_string() } else { format!("8y_{acc}") }), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct BlockSizePattern { + pub average: MetricPattern6, + pub cumulative: MetricPattern4, + pub distribution: BlockIntervalPattern, + pub max: MetricPattern6, + pub min: MetricPattern6, + pub sum: MetricPattern6, + pub sum_cum: SumCumPattern, +} + +impl BlockSizePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + average: MetricPattern6::new(client.clone(), _m(&acc, "average")), + cumulative: MetricPattern4::new(client.clone(), _m(&acc, "cumulative")), + distribution: BlockIntervalPattern::new(client.clone(), acc.clone()), + max: MetricPattern6::new(client.clone(), _m(&acc, "max")), + min: MetricPattern6::new(client.clone(), _m(&acc, "min")), + sum: MetricPattern6::new(client.clone(), _m(&acc, "sum")), + sum_cum: SumCumPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct DollarsPattern { + pub average: MetricPattern2, + pub base: MetricPattern26, + pub cumulative: MetricPattern1, + pub max: MetricPattern2, + pub min: MetricPattern2, + pub percentiles: PercentilesPattern, + pub sum: MetricPattern2, +} + +impl DollarsPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + average: MetricPattern2::new(client.clone(), _m(&acc, "average")), + base: MetricPattern26::new(client.clone(), acc.clone()), + cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), + max: MetricPattern2::new(client.clone(), _m(&acc, "max")), + min: MetricPattern2::new(client.clone(), _m(&acc, "min")), + percentiles: PercentilesPattern::new(client.clone(), acc.clone()), + sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _10yPattern { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern, + pub realized: RealizedPattern4, + pub relative: RelativePattern, + pub supply: SupplyPattern3, + pub unrealized: UnrealizedPattern, +} + +impl _10yPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), + realized: RealizedPattern4::new(client.clone(), acc.clone()), + relative: RelativePattern::new(client.clone(), acc.clone()), + supply: SupplyPattern3::new(client.clone(), acc.clone()), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _10yTo12yPattern { pub activity: ActivityPattern2, @@ -3962,22 +4084,22 @@ impl _10yTo12yPattern { } /// Pattern struct for repeated tree structure. -pub struct _10yPattern { +pub struct _100btcPattern { pub activity: ActivityPattern2, pub cost_basis: CostBasisPattern, - pub realized: RealizedPattern4, + pub realized: RealizedPattern, pub relative: RelativePattern, pub supply: SupplyPattern3, pub unrealized: UnrealizedPattern, } -impl _10yPattern { +impl _100btcPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { activity: ActivityPattern2::new(client.clone(), acc.clone()), cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), - realized: RealizedPattern4::new(client.clone(), acc.clone()), + realized: RealizedPattern::new(client.clone(), acc.clone()), relative: RelativePattern::new(client.clone(), acc.clone()), supply: SupplyPattern3::new(client.clone(), acc.clone()), unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), @@ -4010,46 +4132,22 @@ impl _0satsPattern2 { } /// Pattern struct for repeated tree structure. -pub struct _100btcPattern { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern, - pub realized: RealizedPattern, - pub relative: RelativePattern, - pub supply: SupplyPattern3, - pub unrealized: UnrealizedPattern, -} - -impl _100btcPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), - realized: RealizedPattern::new(client.clone(), acc.clone()), - relative: RelativePattern::new(client.clone(), acc.clone()), - supply: SupplyPattern3::new(client.clone(), acc.clone()), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct SegwitAdoptionPattern { +pub struct BitcoinPattern { pub average: MetricPattern2, - pub base: MetricPattern25, - pub cumulative: MetricPattern1, + pub base: MetricPattern26, + pub cumulative: MetricPattern2, pub max: MetricPattern2, pub min: MetricPattern2, pub sum: MetricPattern2, } -impl SegwitAdoptionPattern { +impl BitcoinPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - average: MetricPattern2::new(client.clone(), _m(&acc, "avg")), - base: MetricPattern25::new(client.clone(), acc.clone()), - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), + average: MetricPattern2::new(client.clone(), _m(&acc, "average")), + base: MetricPattern26::new(client.clone(), acc.clone()), + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cum")), max: MetricPattern2::new(client.clone(), _m(&acc, "max")), min: MetricPattern2::new(client.clone(), _m(&acc, "min")), sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), @@ -4057,6 +4155,50 @@ impl SegwitAdoptionPattern { } } +/// Pattern struct for repeated tree structure. +pub struct ActivityPattern2 { + pub coinblocks_destroyed: BlockCountPattern, + pub coindays_destroyed: BlockCountPattern, + pub satblocks_destroyed: MetricPattern26, + pub satdays_destroyed: MetricPattern26, + pub sent: SentPattern, +} + +impl ActivityPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + coinblocks_destroyed: BlockCountPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")), + coindays_destroyed: BlockCountPattern::new(client.clone(), _m(&acc, "coindays_destroyed")), + satblocks_destroyed: MetricPattern26::new(client.clone(), _m(&acc, "satblocks_destroyed")), + satdays_destroyed: MetricPattern26::new(client.clone(), _m(&acc, "satdays_destroyed")), + sent: SentPattern::new(client.clone(), _m(&acc, "sent")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct SentPattern { + pub base: MetricPattern26, + pub bitcoin: BlockCountPattern, + pub dollars: SumCumPattern, + pub dollars_source: MetricPattern26, + pub sats: SumCumPattern, +} + +impl SentPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + base: MetricPattern26::new(client.clone(), _m(&acc, "height_fee")), + bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), + dollars: SumCumPattern::new(client.clone(), _m(&acc, "usd")), + dollars_source: MetricPattern26::new(client.clone(), _m(&acc, "usd")), + sats: SumCumPattern::new(client.clone(), _m(&acc, "fee")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct SupplyPattern3 { pub supply: SupplyPattern2, @@ -4080,101 +4222,103 @@ impl SupplyPattern3 { } /// Pattern struct for repeated tree structure. -pub struct ActivityPattern2 { - pub coinblocks_destroyed: BlockCountPattern, - pub coindays_destroyed: BlockCountPattern, - pub satblocks_destroyed: MetricPattern25, - pub satdays_destroyed: MetricPattern25, - pub sent: SentPattern, +pub struct PercentilesPattern { + pub median: MetricPattern22, + pub pct10: MetricPattern22, + pub pct25: MetricPattern22, + pub pct75: MetricPattern22, + pub pct90: MetricPattern22, } -impl ActivityPattern2 { +impl PercentilesPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - coinblocks_destroyed: BlockCountPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")), - coindays_destroyed: BlockCountPattern::new(client.clone(), _m(&acc, "coindays_destroyed")), - satblocks_destroyed: MetricPattern25::new(client.clone(), _m(&acc, "satblocks_destroyed")), - satdays_destroyed: MetricPattern25::new(client.clone(), _m(&acc, "satdays_destroyed")), - sent: SentPattern::new(client.clone(), _m(&acc, "sent")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct OpreturnPattern { - pub base: MetricPattern25, - pub bitcoin: BitcoinPattern2, - pub dollars: BitcoinPattern2, - pub sats: SatsPattern4, -} - -impl OpreturnPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - base: MetricPattern25::new(client.clone(), acc.clone()), - bitcoin: BitcoinPattern2::new(client.clone(), _m(&acc, "btc")), - dollars: BitcoinPattern2::new(client.clone(), _m(&acc, "usd")), - sats: SatsPattern4::new(client.clone(), acc.clone()), + median: MetricPattern22::new(client.clone(), _m(&acc, "median")), + pct10: MetricPattern22::new(client.clone(), _m(&acc, "pct10")), + pct25: MetricPattern22::new(client.clone(), _m(&acc, "pct25")), + pct75: MetricPattern22::new(client.clone(), _m(&acc, "pct75")), + pct90: MetricPattern22::new(client.clone(), _m(&acc, "pct90")), } } } /// Pattern struct for repeated tree structure. pub struct SupplyPattern2 { - pub base: MetricPattern25, - pub bitcoin: MetricPattern4, - pub dollars: MetricPattern4, - pub sats: MetricPattern4, + pub base: MetricPattern26, + pub bitcoin: MetricPattern5, + pub dollars: MetricPattern5, + pub sats: MetricPattern7, } impl SupplyPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - base: MetricPattern25::new(client.clone(), acc.clone()), - bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")), - dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")), - sats: MetricPattern4::new(client.clone(), acc.clone()), + base: MetricPattern26::new(client.clone(), acc.clone()), + bitcoin: MetricPattern5::new(client.clone(), _m(&acc, "btc")), + dollars: MetricPattern5::new(client.clone(), _m(&acc, "usd")), + sats: MetricPattern7::new(client.clone(), acc.clone()), } } } /// Pattern struct for repeated tree structure. -pub struct SentPattern { - pub base: MetricPattern25, - pub bitcoin: BlockCountPattern, - pub dollars: BlockCountPattern, - pub sats: SatsPattern, +pub struct PriceHighInSatsPattern { + pub dateindex: MetricPattern22, + pub height: MetricPattern26, + pub max: MetricPattern24, + pub rest: MetricPattern7, } -impl SentPattern { +impl PriceHighInSatsPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - base: MetricPattern25::new(client.clone(), acc.clone()), - bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), - dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), - sats: SatsPattern::new(client.clone(), acc.clone()), + dateindex: MetricPattern22::new(client.clone(), acc.clone()), + height: MetricPattern26::new(client.clone(), acc.clone()), + max: MetricPattern24::new(client.clone(), _m(&acc, "max")), + rest: MetricPattern7::new(client.clone(), _m(&acc, "max")), } } } /// Pattern struct for repeated tree structure. -pub struct UnclaimedRewardsPattern { - pub bitcoin: BlockCountPattern, - pub dollars: BlockCountPattern, - pub sats: BlockCountPattern, +pub struct PriceLowInSatsPattern { + pub dateindex: MetricPattern22, + pub height: MetricPattern26, + pub min: MetricPattern24, + pub rest: MetricPattern7, } -impl UnclaimedRewardsPattern { +impl PriceLowInSatsPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), - dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), - sats: BlockCountPattern::new(client.clone(), acc.clone()), + dateindex: MetricPattern22::new(client.clone(), acc.clone()), + height: MetricPattern26::new(client.clone(), acc.clone()), + min: MetricPattern24::new(client.clone(), _m(&acc, "min")), + rest: MetricPattern7::new(client.clone(), _m(&acc, "min")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct BlockIntervalPattern { + pub average: MetricPattern22, + pub max: MetricPattern22, + pub min: MetricPattern22, + pub percentiles: PercentilesPattern, +} + +impl BlockIntervalPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + average: MetricPattern22::new(client.clone(), _m(&acc, "average")), + max: MetricPattern22::new(client.clone(), _m(&acc, "max")), + min: MetricPattern22::new(client.clone(), _m(&acc, "min")), + percentiles: PercentilesPattern::new(client.clone(), acc.clone()), } } } @@ -4201,7 +4345,7 @@ impl ActiveSupplyPattern { pub struct CostBasisPattern2 { pub max_cost_basis: MetricPattern1, pub min_cost_basis: MetricPattern1, - pub percentiles: PercentilesPattern, + pub percentiles: PercentilesPattern2, } impl CostBasisPattern2 { @@ -4210,7 +4354,7 @@ impl CostBasisPattern2 { Self { max_cost_basis: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), min_cost_basis: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), - percentiles: PercentilesPattern::new(client.clone(), _m(&acc, "cost_basis")), + percentiles: PercentilesPattern2::new(client.clone(), _m(&acc, "cost_basis")), } } } @@ -4218,8 +4362,8 @@ impl CostBasisPattern2 { /// Pattern struct for repeated tree structure. pub struct CoinbasePattern { pub bitcoin: BitcoinPattern, - pub dollars: BitcoinPattern, - pub sats: BitcoinPattern, + pub dollars: DollarsPattern, + pub sats: DollarsPattern, } impl CoinbasePattern { @@ -4227,34 +4371,34 @@ impl CoinbasePattern { pub fn new(client: Arc, acc: String) -> Self { Self { bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")), - dollars: BitcoinPattern::new(client.clone(), _m(&acc, "usd")), - sats: BitcoinPattern::new(client.clone(), acc.clone()), + dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")), + sats: DollarsPattern::new(client.clone(), acc.clone()), } } } /// Pattern struct for repeated tree structure. -pub struct BitcoinPattern2 { - pub base: MetricPattern25, - pub cumulative: MetricPattern1, - pub last: MetricPattern2, +pub struct UnclaimedRewardsPattern { + pub bitcoin: BlockCountPattern, + pub dollars: BlockCountPattern, + pub sats: BlockCountPattern, } -impl BitcoinPattern2 { +impl UnclaimedRewardsPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - base: MetricPattern25::new(client.clone(), acc.clone()), - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), - last: MetricPattern2::new(client.clone(), acc.clone()), + bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), + dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), + sats: BlockCountPattern::new(client.clone(), acc.clone()), } } } /// Pattern struct for repeated tree structure. pub struct BlockCountPattern { - pub base: MetricPattern25, - pub cumulative: MetricPattern1, + pub base: MetricPattern26, + pub cumulative: MetricPattern2, pub sum: MetricPattern2, } @@ -4262,73 +4406,41 @@ impl BlockCountPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - base: MetricPattern25::new(client.clone(), acc.clone()), - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), + base: MetricPattern26::new(client.clone(), acc.clone()), + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), } } } -/// Pattern struct for repeated tree structure. -pub struct RelativePattern4 { - pub supply_in_loss_rel_to_own_supply: MetricPattern5, - pub supply_in_profit_rel_to_own_supply: MetricPattern5, -} - -impl RelativePattern4 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - supply_in_loss_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern5::new(client.clone(), _m(&acc, "profit_rel_to_own_supply")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct SupplyValuePattern { - pub bitcoin: MetricPattern25, - pub dollars: MetricPattern25, + pub bitcoin: MetricPattern26, + pub dollars: MetricPattern26, } impl SupplyValuePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - bitcoin: MetricPattern25::new(client.clone(), _m(&acc, "btc")), - dollars: MetricPattern25::new(client.clone(), _m(&acc, "usd")), + bitcoin: MetricPattern26::new(client.clone(), _m(&acc, "btc")), + dollars: MetricPattern26::new(client.clone(), _m(&acc, "usd")), } } } /// Pattern struct for repeated tree structure. -pub struct _1dReturns1mSdPattern { - pub sd: MetricPattern4, - pub sma: MetricPattern4, +pub struct RelativePattern4 { + pub supply_in_loss_rel_to_own_supply: MetricPattern3, + pub supply_in_profit_rel_to_own_supply: MetricPattern3, } -impl _1dReturns1mSdPattern { +impl RelativePattern4 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), - sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct SatsPattern { - pub cumulative: MetricPattern1, - pub sum: MetricPattern2, -} - -impl SatsPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), - sum: MetricPattern2::new(client.clone(), acc.clone()), + supply_in_loss_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "loss_rel_to_own_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern3::new(client.clone(), _m(&acc, "profit_rel_to_own_supply")), } } } @@ -4350,47 +4462,95 @@ impl CostBasisPattern { } /// Pattern struct for repeated tree structure. -pub struct SatsPattern4 { - pub cumulative: MetricPattern1, - pub last: MetricPattern2, +pub struct _1dReturns1mSdPattern { + pub sd: MetricPattern5, + pub sma: MetricPattern5, } -impl SatsPattern4 { +impl _1dReturns1mSdPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), - last: MetricPattern2::new(client.clone(), acc.clone()), + sd: MetricPattern5::new(client.clone(), _m(&acc, "sd")), + sma: MetricPattern5::new(client.clone(), _m(&acc, "sma")), } } } /// Pattern struct for repeated tree structure. -pub struct TotalRealizedPnlPattern { - pub base: MetricPattern25, - pub sum: MetricPattern2, +pub struct MinmaxPattern { + pub max: MetricPattern22, + pub min: MetricPattern22, } -impl TotalRealizedPnlPattern { +impl MinmaxPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - base: MetricPattern25::new(client.clone(), acc.clone()), + max: MetricPattern22::new(client.clone(), _m(&acc, "max")), + min: MetricPattern22::new(client.clone(), _m(&acc, "min")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct SumCumPattern { + pub cumulative: MetricPattern1, + pub sum: MetricPattern2, +} + +impl SumCumPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")), sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), } } } +/// Pattern struct for repeated tree structure. +pub struct IndexesPattern2 { + pub dateindex: MetricPattern22, + pub rest: MetricPattern7, +} + +impl IndexesPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + dateindex: MetricPattern22::new(client.clone(), acc.clone()), + rest: MetricPattern7::new(client.clone(), _m(&acc, "average")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct DifficultyAdjustmentPattern { + pub base: MetricPattern26, + pub rest: MetricPattern2, +} + +impl DifficultyAdjustmentPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + base: MetricPattern26::new(client.clone(), acc.clone()), + rest: MetricPattern2::new(client.clone(), _m(&acc, "sum")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct RealizedPriceExtraPattern { - pub ratio: MetricPattern4, + pub ratio: MetricPattern5, } impl RealizedPriceExtraPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - ratio: MetricPattern4::new(client.clone(), _m(&acc, "ratio")), + ratio: MetricPattern5::new(client.clone(), _m(&acc, "ratio")), } } } @@ -4482,23 +4642,23 @@ impl CatalogTree_Computed_Blocks { /// Catalog tree node. pub struct CatalogTree_Computed_Blocks_Count { - pub _1m_block_count: MetricPattern4, - pub _1w_block_count: MetricPattern4, - pub _1y_block_count: MetricPattern4, - pub _24h_block_count: MetricPattern25, + pub _1m_block_count: MetricPattern5, + pub _1w_block_count: MetricPattern5, + pub _1y_block_count: MetricPattern5, + pub _24h_block_count: MetricPattern26, pub block_count: BlockCountPattern, - pub block_count_target: MetricPattern4, + pub block_count_target: MetricPattern5, } impl CatalogTree_Computed_Blocks_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - _1m_block_count: MetricPattern4::new(client.clone(), format!("{base_path}_1m_block_count")), - _1w_block_count: MetricPattern4::new(client.clone(), format!("{base_path}_1w_block_count")), - _1y_block_count: MetricPattern4::new(client.clone(), format!("{base_path}_1y_block_count")), - _24h_block_count: MetricPattern25::new(client.clone(), format!("{base_path}_24h_block_count")), + _1m_block_count: MetricPattern5::new(client.clone(), format!("{base_path}_1m_block_count")), + _1w_block_count: MetricPattern5::new(client.clone(), format!("{base_path}_1w_block_count")), + _1y_block_count: MetricPattern5::new(client.clone(), format!("{base_path}_1y_block_count")), + _24h_block_count: MetricPattern26::new(client.clone(), format!("{base_path}_24h_block_count")), block_count: BlockCountPattern::new(client.clone(), "block_count".to_string()), - block_count_target: MetricPattern4::new(client.clone(), format!("{base_path}_block_count_target")), + block_count_target: MetricPattern5::new(client.clone(), format!("{base_path}_block_count_target")), } } } @@ -4507,7 +4667,7 @@ impl CatalogTree_Computed_Blocks_Count { pub struct CatalogTree_Computed_Blocks_Difficulty { pub blocks_before_next_difficulty_adjustment: MetricPattern1, pub days_before_next_difficulty_adjustment: MetricPattern1, - pub difficultyepoch: MetricPattern4, + pub difficultyepoch: MetricPattern5, } impl CatalogTree_Computed_Blocks_Difficulty { @@ -4515,7 +4675,7 @@ impl CatalogTree_Computed_Blocks_Difficulty { Self { blocks_before_next_difficulty_adjustment: MetricPattern1::new(client.clone(), format!("{base_path}_blocks_before_next_difficulty_adjustment")), days_before_next_difficulty_adjustment: MetricPattern1::new(client.clone(), format!("{base_path}_days_before_next_difficulty_adjustment")), - difficultyepoch: MetricPattern4::new(client.clone(), format!("{base_path}_difficultyepoch")), + difficultyepoch: MetricPattern5::new(client.clone(), format!("{base_path}_difficultyepoch")), } } } @@ -4524,7 +4684,7 @@ impl CatalogTree_Computed_Blocks_Difficulty { pub struct CatalogTree_Computed_Blocks_Halving { pub blocks_before_next_halving: MetricPattern1, pub days_before_next_halving: MetricPattern1, - pub halvingepoch: MetricPattern4, + pub halvingepoch: MetricPattern5, } impl CatalogTree_Computed_Blocks_Halving { @@ -4532,7 +4692,7 @@ impl CatalogTree_Computed_Blocks_Halving { Self { blocks_before_next_halving: MetricPattern1::new(client.clone(), format!("{base_path}_blocks_before_next_halving")), days_before_next_halving: MetricPattern1::new(client.clone(), format!("{base_path}_days_before_next_halving")), - halvingepoch: MetricPattern4::new(client.clone(), format!("{base_path}_halvingepoch")), + halvingepoch: MetricPattern5::new(client.clone(), format!("{base_path}_halvingepoch")), } } } @@ -4540,14 +4700,14 @@ impl CatalogTree_Computed_Blocks_Halving { /// Catalog tree node. pub struct CatalogTree_Computed_Blocks_Interval { pub block_interval: BlockIntervalPattern, - pub interval: MetricPattern25, + pub interval: MetricPattern26, } impl CatalogTree_Computed_Blocks_Interval { pub fn new(client: Arc, base_path: String) -> Self { Self { block_interval: BlockIntervalPattern::new(client.clone(), "block_interval".to_string()), - interval: MetricPattern25::new(client.clone(), format!("{base_path}_interval")), + interval: MetricPattern26::new(client.clone(), format!("{base_path}_interval")), } } } @@ -4555,7 +4715,7 @@ impl CatalogTree_Computed_Blocks_Interval { /// Catalog tree node. pub struct CatalogTree_Computed_Blocks_Mining { pub difficulty: MetricPattern2, - pub difficulty_adjustment: MetricPattern1, + pub difficulty_adjustment: DifficultyAdjustmentPattern, pub difficulty_as_hash: MetricPattern1, pub hash_price_phs: MetricPattern1, pub hash_price_phs_min: MetricPattern1, @@ -4563,10 +4723,10 @@ pub struct CatalogTree_Computed_Blocks_Mining { pub hash_price_ths: MetricPattern1, pub hash_price_ths_min: MetricPattern1, pub hash_rate: MetricPattern1, - pub hash_rate_1m_sma: MetricPattern4, - pub hash_rate_1w_sma: MetricPattern4, - pub hash_rate_1y_sma: MetricPattern4, - pub hash_rate_2m_sma: MetricPattern4, + pub hash_rate_1m_sma: MetricPattern5, + pub hash_rate_1w_sma: MetricPattern5, + pub hash_rate_1y_sma: MetricPattern5, + pub hash_rate_2m_sma: MetricPattern5, pub hash_value_phs: MetricPattern1, pub hash_value_phs_min: MetricPattern1, pub hash_value_rebound: MetricPattern1, @@ -4578,7 +4738,7 @@ impl CatalogTree_Computed_Blocks_Mining { pub fn new(client: Arc, base_path: String) -> Self { Self { difficulty: MetricPattern2::new(client.clone(), format!("{base_path}_difficulty")), - difficulty_adjustment: MetricPattern1::new(client.clone(), format!("{base_path}_difficulty_adjustment")), + difficulty_adjustment: DifficultyAdjustmentPattern::new(client.clone(), "difficulty_adjustment".to_string()), difficulty_as_hash: MetricPattern1::new(client.clone(), format!("{base_path}_difficulty_as_hash")), hash_price_phs: MetricPattern1::new(client.clone(), format!("{base_path}_hash_price_phs")), hash_price_phs_min: MetricPattern1::new(client.clone(), format!("{base_path}_hash_price_phs_min")), @@ -4586,10 +4746,10 @@ impl CatalogTree_Computed_Blocks_Mining { hash_price_ths: MetricPattern1::new(client.clone(), format!("{base_path}_hash_price_ths")), hash_price_ths_min: MetricPattern1::new(client.clone(), format!("{base_path}_hash_price_ths_min")), hash_rate: MetricPattern1::new(client.clone(), format!("{base_path}_hash_rate")), - hash_rate_1m_sma: MetricPattern4::new(client.clone(), format!("{base_path}_hash_rate_1m_sma")), - hash_rate_1w_sma: MetricPattern4::new(client.clone(), format!("{base_path}_hash_rate_1w_sma")), - hash_rate_1y_sma: MetricPattern4::new(client.clone(), format!("{base_path}_hash_rate_1y_sma")), - hash_rate_2m_sma: MetricPattern4::new(client.clone(), format!("{base_path}_hash_rate_2m_sma")), + hash_rate_1m_sma: MetricPattern5::new(client.clone(), format!("{base_path}_hash_rate_1m_sma")), + hash_rate_1w_sma: MetricPattern5::new(client.clone(), format!("{base_path}_hash_rate_1w_sma")), + hash_rate_1y_sma: MetricPattern5::new(client.clone(), format!("{base_path}_hash_rate_1y_sma")), + hash_rate_2m_sma: MetricPattern5::new(client.clone(), format!("{base_path}_hash_rate_2m_sma")), hash_value_phs: MetricPattern1::new(client.clone(), format!("{base_path}_hash_value_phs")), hash_value_phs_min: MetricPattern1::new(client.clone(), format!("{base_path}_hash_value_phs_min")), hash_value_rebound: MetricPattern1::new(client.clone(), format!("{base_path}_hash_value_rebound")), @@ -4601,26 +4761,26 @@ impl CatalogTree_Computed_Blocks_Mining { /// Catalog tree node. pub struct CatalogTree_Computed_Blocks_Rewards { - pub _24h_coinbase_sum: MetricPattern25, - pub _24h_coinbase_usd_sum: MetricPattern25, + pub _24h_coinbase_sum: MetricPattern26, + pub _24h_coinbase_usd_sum: MetricPattern26, pub coinbase: CoinbasePattern, - pub fee_dominance: MetricPattern21, + pub fee_dominance: MetricPattern22, pub subsidy: CoinbasePattern, - pub subsidy_dominance: MetricPattern21, - pub subsidy_usd_1y_sma: MetricPattern4, + pub subsidy_dominance: MetricPattern22, + pub subsidy_usd_1y_sma: MetricPattern5, pub unclaimed_rewards: UnclaimedRewardsPattern, } impl CatalogTree_Computed_Blocks_Rewards { pub fn new(client: Arc, base_path: String) -> Self { Self { - _24h_coinbase_sum: MetricPattern25::new(client.clone(), format!("{base_path}_24h_coinbase_sum")), - _24h_coinbase_usd_sum: MetricPattern25::new(client.clone(), format!("{base_path}_24h_coinbase_usd_sum")), + _24h_coinbase_sum: MetricPattern26::new(client.clone(), format!("{base_path}_24h_coinbase_sum")), + _24h_coinbase_usd_sum: MetricPattern26::new(client.clone(), format!("{base_path}_24h_coinbase_usd_sum")), coinbase: CoinbasePattern::new(client.clone(), "coinbase".to_string()), - fee_dominance: MetricPattern21::new(client.clone(), format!("{base_path}_fee_dominance")), + fee_dominance: MetricPattern22::new(client.clone(), format!("{base_path}_fee_dominance")), subsidy: CoinbasePattern::new(client.clone(), "subsidy".to_string()), - subsidy_dominance: MetricPattern21::new(client.clone(), format!("{base_path}_subsidy_dominance")), - subsidy_usd_1y_sma: MetricPattern4::new(client.clone(), format!("{base_path}_subsidy_usd_1y_sma")), + subsidy_dominance: MetricPattern22::new(client.clone(), format!("{base_path}_subsidy_dominance")), + subsidy_usd_1y_sma: MetricPattern5::new(client.clone(), format!("{base_path}_subsidy_usd_1y_sma")), unclaimed_rewards: UnclaimedRewardsPattern::new(client.clone(), "unclaimed_rewards".to_string()), } } @@ -4630,7 +4790,7 @@ impl CatalogTree_Computed_Blocks_Rewards { pub struct CatalogTree_Computed_Blocks_Size { pub block_size: BlockSizePattern, pub block_vbytes: BlockSizePattern, - pub vbytes: MetricPattern25, + pub vbytes: MetricPattern26, } impl CatalogTree_Computed_Blocks_Size { @@ -4638,26 +4798,26 @@ impl CatalogTree_Computed_Blocks_Size { Self { block_size: BlockSizePattern::new(client.clone(), "block_size".to_string()), block_vbytes: BlockSizePattern::new(client.clone(), "block_vbytes".to_string()), - vbytes: MetricPattern25::new(client.clone(), format!("{base_path}_vbytes")), + vbytes: MetricPattern26::new(client.clone(), format!("{base_path}_vbytes")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Blocks_Time { - pub date: MetricPattern25, - pub date_fixed: MetricPattern25, + pub date: MetricPattern26, + pub date_fixed: MetricPattern26, pub timestamp: MetricPattern2, - pub timestamp_fixed: MetricPattern25, + pub timestamp_fixed: MetricPattern26, } impl CatalogTree_Computed_Blocks_Time { pub fn new(client: Arc, base_path: String) -> Self { Self { - date: MetricPattern25::new(client.clone(), format!("{base_path}_date")), - date_fixed: MetricPattern25::new(client.clone(), format!("{base_path}_date_fixed")), + date: MetricPattern26::new(client.clone(), format!("{base_path}_date")), + date_fixed: MetricPattern26::new(client.clone(), format!("{base_path}_date_fixed")), timestamp: MetricPattern2::new(client.clone(), format!("{base_path}_timestamp")), - timestamp_fixed: MetricPattern25::new(client.clone(), format!("{base_path}_timestamp_fixed")), + timestamp_fixed: MetricPattern26::new(client.clone(), format!("{base_path}_timestamp_fixed")), } } } @@ -4723,17 +4883,17 @@ impl CatalogTree_Computed_Cointime_Activity { /// Catalog tree node. pub struct CatalogTree_Computed_Cointime_Adjusted { - pub cointime_adj_inflation_rate: MetricPattern4, - pub cointime_adj_tx_btc_velocity: MetricPattern4, - pub cointime_adj_tx_usd_velocity: MetricPattern4, + pub cointime_adj_inflation_rate: MetricPattern5, + pub cointime_adj_tx_btc_velocity: MetricPattern5, + pub cointime_adj_tx_usd_velocity: MetricPattern5, } impl CatalogTree_Computed_Cointime_Adjusted { pub fn new(client: Arc, base_path: String) -> Self { Self { - cointime_adj_inflation_rate: MetricPattern4::new(client.clone(), format!("{base_path}_cointime_adj_inflation_rate")), - cointime_adj_tx_btc_velocity: MetricPattern4::new(client.clone(), format!("{base_path}_cointime_adj_tx_btc_velocity")), - cointime_adj_tx_usd_velocity: MetricPattern4::new(client.clone(), format!("{base_path}_cointime_adj_tx_usd_velocity")), + cointime_adj_inflation_rate: MetricPattern5::new(client.clone(), format!("{base_path}_cointime_adj_inflation_rate")), + cointime_adj_tx_btc_velocity: MetricPattern5::new(client.clone(), format!("{base_path}_cointime_adj_tx_btc_velocity")), + cointime_adj_tx_usd_velocity: MetricPattern5::new(client.clone(), format!("{base_path}_cointime_adj_tx_usd_velocity")), } } } @@ -4875,10 +5035,10 @@ pub struct CatalogTree_Computed_Distribution { pub addresstype_to_indexes_to_addr_count: AddresstypeToHeightToAddrCountPattern, pub addresstype_to_indexes_to_empty_addr_count: AddresstypeToHeightToAddrCountPattern, pub any_address_indexes: AddresstypeToHeightToAddrCountPattern, - pub chain_state: MetricPattern25, + pub chain_state: MetricPattern26, pub empty_addr_count: MetricPattern1, - pub emptyaddressindex: MetricPattern41, - pub loadedaddressindex: MetricPattern40, + pub emptyaddressindex: MetricPattern42, + pub loadedaddressindex: MetricPattern41, pub utxo_cohorts: CatalogTree_Computed_Distribution_UtxoCohorts, } @@ -4893,10 +5053,10 @@ impl CatalogTree_Computed_Distribution { addresstype_to_indexes_to_addr_count: AddresstypeToHeightToAddrCountPattern::new(client.clone(), "addr_count".to_string()), addresstype_to_indexes_to_empty_addr_count: AddresstypeToHeightToAddrCountPattern::new(client.clone(), "empty_addr_count".to_string()), any_address_indexes: AddresstypeToHeightToAddrCountPattern::new(client.clone(), "anyaddressindex".to_string()), - chain_state: MetricPattern25::new(client.clone(), format!("{base_path}_chain_state")), + chain_state: MetricPattern26::new(client.clone(), format!("{base_path}_chain_state")), empty_addr_count: MetricPattern1::new(client.clone(), format!("{base_path}_empty_addr_count")), - emptyaddressindex: MetricPattern41::new(client.clone(), format!("{base_path}_emptyaddressindex")), - loadedaddressindex: MetricPattern40::new(client.clone(), format!("{base_path}_loadedaddressindex")), + emptyaddressindex: MetricPattern42::new(client.clone(), format!("{base_path}_emptyaddressindex")), + loadedaddressindex: MetricPattern41::new(client.clone(), format!("{base_path}_loadedaddressindex")), utxo_cohorts: CatalogTree_Computed_Distribution_UtxoCohorts::new(client.clone(), format!("{base_path}_utxo_cohorts")), } } @@ -5036,15 +5196,15 @@ impl CatalogTree_Computed_Distribution_AddressCohorts_LtAmount { /// Catalog tree node. pub struct CatalogTree_Computed_Distribution_AddressesData { - pub empty: MetricPattern41, - pub loaded: MetricPattern40, + pub empty: MetricPattern42, + pub loaded: MetricPattern41, } impl CatalogTree_Computed_Distribution_AddressesData { pub fn new(client: Arc, base_path: String) -> Self { Self { - empty: MetricPattern41::new(client.clone(), format!("{base_path}_empty")), - loaded: MetricPattern40::new(client.clone(), format!("{base_path}_loaded")), + empty: MetricPattern42::new(client.clone(), format!("{base_path}_empty")), + loaded: MetricPattern41::new(client.clone(), format!("{base_path}_loaded")), } } } @@ -5160,23 +5320,23 @@ impl CatalogTree_Computed_Distribution_UtxoCohorts_All { /// Catalog tree node. pub struct CatalogTree_Computed_Distribution_UtxoCohorts_All_Relative { - pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5, + pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3, pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3, - pub supply_in_loss_rel_to_own_supply: MetricPattern5, - pub supply_in_profit_rel_to_own_supply: MetricPattern5, - pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5, - pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5, + pub supply_in_loss_rel_to_own_supply: MetricPattern3, + pub supply_in_profit_rel_to_own_supply: MetricPattern3, + pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3, + pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3, } impl CatalogTree_Computed_Distribution_UtxoCohorts_All_Relative { pub fn new(client: Arc, base_path: String) -> Self { Self { - neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), format!("{base_path}_neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), + neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), format!("{base_path}_neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), format!("{base_path}_net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), - supply_in_loss_rel_to_own_supply: MetricPattern5::new(client.clone(), format!("{base_path}_supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern5::new(client.clone(), format!("{base_path}_supply_in_profit_rel_to_own_supply")), - unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), format!("{base_path}_unrealized_loss_rel_to_own_total_unrealized_pnl")), - unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5::new(client.clone(), format!("{base_path}_unrealized_profit_rel_to_own_total_unrealized_pnl")), + supply_in_loss_rel_to_own_supply: MetricPattern3::new(client.clone(), format!("{base_path}_supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern3::new(client.clone(), format!("{base_path}_supply_in_profit_rel_to_own_supply")), + unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), format!("{base_path}_unrealized_loss_rel_to_own_total_unrealized_pnl")), + unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3::new(client.clone(), format!("{base_path}_unrealized_profit_rel_to_own_total_unrealized_pnl")), } } } @@ -5573,124 +5733,124 @@ impl CatalogTree_Computed_Indexes { /// Catalog tree node. pub struct CatalogTree_Computed_Indexes_Address { - pub emptyoutputindex: MetricPattern24, - pub opreturnindex: MetricPattern27, - pub p2aaddressindex: MetricPattern29, - pub p2msoutputindex: MetricPattern30, - pub p2pk33addressindex: MetricPattern31, - pub p2pk65addressindex: MetricPattern32, - pub p2pkhaddressindex: MetricPattern33, - pub p2shaddressindex: MetricPattern34, - pub p2traddressindex: MetricPattern35, - pub p2wpkhaddressindex: MetricPattern36, - pub p2wshaddressindex: MetricPattern37, - pub unknownoutputindex: MetricPattern39, + pub emptyoutputindex: MetricPattern25, + pub opreturnindex: MetricPattern28, + pub p2aaddressindex: MetricPattern30, + pub p2msoutputindex: MetricPattern31, + pub p2pk33addressindex: MetricPattern32, + pub p2pk65addressindex: MetricPattern33, + pub p2pkhaddressindex: MetricPattern34, + pub p2shaddressindex: MetricPattern35, + pub p2traddressindex: MetricPattern36, + pub p2wpkhaddressindex: MetricPattern37, + pub p2wshaddressindex: MetricPattern38, + pub unknownoutputindex: MetricPattern40, } impl CatalogTree_Computed_Indexes_Address { pub fn new(client: Arc, base_path: String) -> Self { Self { - emptyoutputindex: MetricPattern24::new(client.clone(), format!("{base_path}_emptyoutputindex")), - opreturnindex: MetricPattern27::new(client.clone(), format!("{base_path}_opreturnindex")), - p2aaddressindex: MetricPattern29::new(client.clone(), format!("{base_path}_p2aaddressindex")), - p2msoutputindex: MetricPattern30::new(client.clone(), format!("{base_path}_p2msoutputindex")), - p2pk33addressindex: MetricPattern31::new(client.clone(), format!("{base_path}_p2pk33addressindex")), - p2pk65addressindex: MetricPattern32::new(client.clone(), format!("{base_path}_p2pk65addressindex")), - p2pkhaddressindex: MetricPattern33::new(client.clone(), format!("{base_path}_p2pkhaddressindex")), - p2shaddressindex: MetricPattern34::new(client.clone(), format!("{base_path}_p2shaddressindex")), - p2traddressindex: MetricPattern35::new(client.clone(), format!("{base_path}_p2traddressindex")), - p2wpkhaddressindex: MetricPattern36::new(client.clone(), format!("{base_path}_p2wpkhaddressindex")), - p2wshaddressindex: MetricPattern37::new(client.clone(), format!("{base_path}_p2wshaddressindex")), - unknownoutputindex: MetricPattern39::new(client.clone(), format!("{base_path}_unknownoutputindex")), + emptyoutputindex: MetricPattern25::new(client.clone(), format!("{base_path}_emptyoutputindex")), + opreturnindex: MetricPattern28::new(client.clone(), format!("{base_path}_opreturnindex")), + p2aaddressindex: MetricPattern30::new(client.clone(), format!("{base_path}_p2aaddressindex")), + p2msoutputindex: MetricPattern31::new(client.clone(), format!("{base_path}_p2msoutputindex")), + p2pk33addressindex: MetricPattern32::new(client.clone(), format!("{base_path}_p2pk33addressindex")), + p2pk65addressindex: MetricPattern33::new(client.clone(), format!("{base_path}_p2pk65addressindex")), + p2pkhaddressindex: MetricPattern34::new(client.clone(), format!("{base_path}_p2pkhaddressindex")), + p2shaddressindex: MetricPattern35::new(client.clone(), format!("{base_path}_p2shaddressindex")), + p2traddressindex: MetricPattern36::new(client.clone(), format!("{base_path}_p2traddressindex")), + p2wpkhaddressindex: MetricPattern37::new(client.clone(), format!("{base_path}_p2wpkhaddressindex")), + p2wshaddressindex: MetricPattern38::new(client.clone(), format!("{base_path}_p2wshaddressindex")), + unknownoutputindex: MetricPattern40::new(client.clone(), format!("{base_path}_unknownoutputindex")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Indexes_Block { - pub dateindex: MetricPattern25, - pub difficultyepoch: MetricPattern14, - pub first_height: MetricPattern13, - pub halvingepoch: MetricPattern15, - pub height: MetricPattern25, - pub height_count: MetricPattern23, - pub txindex_count: MetricPattern25, + pub dateindex: MetricPattern26, + pub difficultyepoch: MetricPattern15, + pub first_height: MetricPattern14, + pub halvingepoch: MetricPattern16, + pub height: MetricPattern26, + pub height_count: MetricPattern24, + pub txindex_count: MetricPattern26, } impl CatalogTree_Computed_Indexes_Block { pub fn new(client: Arc, base_path: String) -> Self { Self { - dateindex: MetricPattern25::new(client.clone(), format!("{base_path}_dateindex")), - difficultyepoch: MetricPattern14::new(client.clone(), format!("{base_path}_difficultyepoch")), - first_height: MetricPattern13::new(client.clone(), format!("{base_path}_first_height")), - halvingepoch: MetricPattern15::new(client.clone(), format!("{base_path}_halvingepoch")), - height: MetricPattern25::new(client.clone(), format!("{base_path}_height")), - height_count: MetricPattern23::new(client.clone(), format!("{base_path}_height_count")), - txindex_count: MetricPattern25::new(client.clone(), format!("{base_path}_txindex_count")), + dateindex: MetricPattern26::new(client.clone(), format!("{base_path}_dateindex")), + difficultyepoch: MetricPattern15::new(client.clone(), format!("{base_path}_difficultyepoch")), + first_height: MetricPattern14::new(client.clone(), format!("{base_path}_first_height")), + halvingepoch: MetricPattern16::new(client.clone(), format!("{base_path}_halvingepoch")), + height: MetricPattern26::new(client.clone(), format!("{base_path}_height")), + height_count: MetricPattern24::new(client.clone(), format!("{base_path}_height_count")), + txindex_count: MetricPattern26::new(client.clone(), format!("{base_path}_txindex_count")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Indexes_Time { - pub date: MetricPattern21, - pub dateindex: MetricPattern21, - pub dateindex_count: MetricPattern19, - pub decadeindex: MetricPattern12, - pub first_dateindex: MetricPattern19, - pub first_height: MetricPattern21, - pub first_monthindex: MetricPattern8, - pub first_yearindex: MetricPattern22, - pub height_count: MetricPattern21, - pub monthindex: MetricPattern10, - pub monthindex_count: MetricPattern8, - pub quarterindex: MetricPattern17, - pub semesterindex: MetricPattern18, - pub weekindex: MetricPattern11, - pub yearindex: MetricPattern20, - pub yearindex_count: MetricPattern22, + pub date: MetricPattern22, + pub dateindex: MetricPattern22, + pub dateindex_count: MetricPattern20, + pub decadeindex: MetricPattern13, + pub first_dateindex: MetricPattern20, + pub first_height: MetricPattern22, + pub first_monthindex: MetricPattern9, + pub first_yearindex: MetricPattern23, + pub height_count: MetricPattern22, + pub monthindex: MetricPattern11, + pub monthindex_count: MetricPattern9, + pub quarterindex: MetricPattern18, + pub semesterindex: MetricPattern19, + pub weekindex: MetricPattern12, + pub yearindex: MetricPattern21, + pub yearindex_count: MetricPattern23, } impl CatalogTree_Computed_Indexes_Time { pub fn new(client: Arc, base_path: String) -> Self { Self { - date: MetricPattern21::new(client.clone(), format!("{base_path}_date")), - dateindex: MetricPattern21::new(client.clone(), format!("{base_path}_dateindex")), - dateindex_count: MetricPattern19::new(client.clone(), format!("{base_path}_dateindex_count")), - decadeindex: MetricPattern12::new(client.clone(), format!("{base_path}_decadeindex")), - first_dateindex: MetricPattern19::new(client.clone(), format!("{base_path}_first_dateindex")), - first_height: MetricPattern21::new(client.clone(), format!("{base_path}_first_height")), - first_monthindex: MetricPattern8::new(client.clone(), format!("{base_path}_first_monthindex")), - first_yearindex: MetricPattern22::new(client.clone(), format!("{base_path}_first_yearindex")), - height_count: MetricPattern21::new(client.clone(), format!("{base_path}_height_count")), - monthindex: MetricPattern10::new(client.clone(), format!("{base_path}_monthindex")), - monthindex_count: MetricPattern8::new(client.clone(), format!("{base_path}_monthindex_count")), - quarterindex: MetricPattern17::new(client.clone(), format!("{base_path}_quarterindex")), - semesterindex: MetricPattern18::new(client.clone(), format!("{base_path}_semesterindex")), - weekindex: MetricPattern11::new(client.clone(), format!("{base_path}_weekindex")), - yearindex: MetricPattern20::new(client.clone(), format!("{base_path}_yearindex")), - yearindex_count: MetricPattern22::new(client.clone(), format!("{base_path}_yearindex_count")), + date: MetricPattern22::new(client.clone(), format!("{base_path}_date")), + dateindex: MetricPattern22::new(client.clone(), format!("{base_path}_dateindex")), + dateindex_count: MetricPattern20::new(client.clone(), format!("{base_path}_dateindex_count")), + decadeindex: MetricPattern13::new(client.clone(), format!("{base_path}_decadeindex")), + first_dateindex: MetricPattern20::new(client.clone(), format!("{base_path}_first_dateindex")), + first_height: MetricPattern22::new(client.clone(), format!("{base_path}_first_height")), + first_monthindex: MetricPattern9::new(client.clone(), format!("{base_path}_first_monthindex")), + first_yearindex: MetricPattern23::new(client.clone(), format!("{base_path}_first_yearindex")), + height_count: MetricPattern22::new(client.clone(), format!("{base_path}_height_count")), + monthindex: MetricPattern11::new(client.clone(), format!("{base_path}_monthindex")), + monthindex_count: MetricPattern9::new(client.clone(), format!("{base_path}_monthindex_count")), + quarterindex: MetricPattern18::new(client.clone(), format!("{base_path}_quarterindex")), + semesterindex: MetricPattern19::new(client.clone(), format!("{base_path}_semesterindex")), + weekindex: MetricPattern12::new(client.clone(), format!("{base_path}_weekindex")), + yearindex: MetricPattern21::new(client.clone(), format!("{base_path}_yearindex")), + yearindex_count: MetricPattern23::new(client.clone(), format!("{base_path}_yearindex_count")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Indexes_Transaction { - pub input_count: MetricPattern38, - pub output_count: MetricPattern38, - pub txindex: MetricPattern38, - pub txinindex: MetricPattern26, - pub txoutindex: MetricPattern28, + pub input_count: MetricPattern39, + pub output_count: MetricPattern39, + pub txindex: MetricPattern39, + pub txinindex: MetricPattern27, + pub txoutindex: MetricPattern29, } impl CatalogTree_Computed_Indexes_Transaction { pub fn new(client: Arc, base_path: String) -> Self { Self { - input_count: MetricPattern38::new(client.clone(), format!("{base_path}_input_count")), - output_count: MetricPattern38::new(client.clone(), format!("{base_path}_output_count")), - txindex: MetricPattern38::new(client.clone(), format!("{base_path}_txindex")), - txinindex: MetricPattern26::new(client.clone(), format!("{base_path}_txinindex")), - txoutindex: MetricPattern28::new(client.clone(), format!("{base_path}_txoutindex")), + input_count: MetricPattern39::new(client.clone(), format!("{base_path}_input_count")), + output_count: MetricPattern39::new(client.clone(), format!("{base_path}_output_count")), + txindex: MetricPattern39::new(client.clone(), format!("{base_path}_txindex")), + txinindex: MetricPattern27::new(client.clone(), format!("{base_path}_txinindex")), + txoutindex: MetricPattern29::new(client.clone(), format!("{base_path}_txoutindex")), } } } @@ -5712,28 +5872,28 @@ impl CatalogTree_Computed_Inputs { /// Catalog tree node. pub struct CatalogTree_Computed_Inputs_Count { - pub count: BlockSizePattern, + pub count: CountPattern2, } impl CatalogTree_Computed_Inputs_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - count: BlockSizePattern::new(client.clone(), "input_count".to_string()), + count: CountPattern2::new(client.clone(), "input_count".to_string()), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Inputs_Spent { - pub txoutindex: MetricPattern26, - pub value: MetricPattern26, + pub txoutindex: MetricPattern27, + pub value: MetricPattern27, } impl CatalogTree_Computed_Inputs_Spent { pub fn new(client: Arc, base_path: String) -> Self { Self { - txoutindex: MetricPattern26::new(client.clone(), format!("{base_path}_txoutindex")), - value: MetricPattern26::new(client.clone(), format!("{base_path}_value")), + txoutindex: MetricPattern27::new(client.clone(), format!("{base_path}_txoutindex")), + value: MetricPattern27::new(client.clone(), format!("{base_path}_value")), } } } @@ -5767,49 +5927,49 @@ impl CatalogTree_Computed_Market { /// Catalog tree node. pub struct CatalogTree_Computed_Market_Ath { - pub days_since_price_ath: MetricPattern4, - pub max_days_between_price_aths: MetricPattern4, - pub max_years_between_price_aths: MetricPattern4, + pub days_since_price_ath: MetricPattern5, + pub max_days_between_price_aths: MetricPattern5, + pub max_years_between_price_aths: MetricPattern5, pub price_ath: MetricPattern3, pub price_drawdown: MetricPattern3, - pub years_since_price_ath: MetricPattern4, + pub years_since_price_ath: MetricPattern5, } impl CatalogTree_Computed_Market_Ath { pub fn new(client: Arc, base_path: String) -> Self { Self { - days_since_price_ath: MetricPattern4::new(client.clone(), format!("{base_path}_days_since_price_ath")), - max_days_between_price_aths: MetricPattern4::new(client.clone(), format!("{base_path}_max_days_between_price_aths")), - max_years_between_price_aths: MetricPattern4::new(client.clone(), format!("{base_path}_max_years_between_price_aths")), + days_since_price_ath: MetricPattern5::new(client.clone(), format!("{base_path}_days_since_price_ath")), + max_days_between_price_aths: MetricPattern5::new(client.clone(), format!("{base_path}_max_days_between_price_aths")), + max_years_between_price_aths: MetricPattern5::new(client.clone(), format!("{base_path}_max_years_between_price_aths")), price_ath: MetricPattern3::new(client.clone(), format!("{base_path}_price_ath")), price_drawdown: MetricPattern3::new(client.clone(), format!("{base_path}_price_drawdown")), - years_since_price_ath: MetricPattern4::new(client.clone(), format!("{base_path}_years_since_price_ath")), + years_since_price_ath: MetricPattern5::new(client.clone(), format!("{base_path}_years_since_price_ath")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Market_Dca { - pub class_avg_price: ClassAvgPricePattern, - pub class_returns: ClassAvgPricePattern, + pub class_average_price: ClassAveragePricePattern, + pub class_returns: ClassAveragePricePattern, pub class_stack: CatalogTree_Computed_Market_Dca_ClassStack, - pub period_avg_price: PeriodAvgPricePattern, + pub period_average_price: PeriodAveragePricePattern, pub period_cagr: PeriodCagrPattern, pub period_lump_sum_stack: PeriodLumpSumStackPattern, - pub period_returns: PeriodAvgPricePattern, + pub period_returns: PeriodAveragePricePattern, pub period_stack: PeriodLumpSumStackPattern, } impl CatalogTree_Computed_Market_Dca { pub fn new(client: Arc, base_path: String) -> Self { Self { - class_avg_price: ClassAvgPricePattern::new(client.clone(), "dca_class".to_string()), - class_returns: ClassAvgPricePattern::new(client.clone(), "dca_class".to_string()), + class_average_price: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), + class_returns: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), class_stack: CatalogTree_Computed_Market_Dca_ClassStack::new(client.clone(), format!("{base_path}_class_stack")), - period_avg_price: PeriodAvgPricePattern::new(client.clone(), "dca_avg_price".to_string()), + period_average_price: PeriodAveragePricePattern::new(client.clone(), "dca_average_price".to_string()), period_cagr: PeriodCagrPattern::new(client.clone(), "dca_cagr".to_string()), period_lump_sum_stack: PeriodLumpSumStackPattern::new(client.clone(), "".to_string()), - period_returns: PeriodAvgPricePattern::new(client.clone(), "dca_returns".to_string()), + period_returns: PeriodAveragePricePattern::new(client.clone(), "dca_returns".to_string()), period_stack: PeriodLumpSumStackPattern::new(client.clone(), "".to_string()), } } @@ -5850,49 +6010,49 @@ impl CatalogTree_Computed_Market_Dca_ClassStack { /// Catalog tree node. pub struct CatalogTree_Computed_Market_Indicators { - pub gini: MetricPattern21, - pub macd_histogram: MetricPattern21, - pub macd_line: MetricPattern21, - pub macd_signal: MetricPattern21, - pub nvt: MetricPattern21, - pub pi_cycle: MetricPattern21, - pub puell_multiple: MetricPattern4, - pub rsi_14d: MetricPattern21, - pub rsi_14d_max: MetricPattern21, - pub rsi_14d_min: MetricPattern21, - pub rsi_avg_gain_14d: MetricPattern21, - pub rsi_avg_loss_14d: MetricPattern21, - pub rsi_gains: MetricPattern21, - pub rsi_losses: MetricPattern21, - pub stoch_d: MetricPattern21, - pub stoch_k: MetricPattern21, - pub stoch_rsi: MetricPattern21, - pub stoch_rsi_d: MetricPattern21, - pub stoch_rsi_k: MetricPattern21, + pub gini: MetricPattern22, + pub macd_histogram: MetricPattern22, + pub macd_line: MetricPattern22, + pub macd_signal: MetricPattern22, + pub nvt: MetricPattern5, + pub pi_cycle: MetricPattern22, + pub puell_multiple: MetricPattern5, + pub rsi_14d: MetricPattern22, + pub rsi_14d_max: MetricPattern22, + pub rsi_14d_min: MetricPattern22, + pub rsi_average_gain_14d: MetricPattern22, + pub rsi_average_loss_14d: MetricPattern22, + pub rsi_gains: MetricPattern22, + pub rsi_losses: MetricPattern22, + pub stoch_d: MetricPattern22, + pub stoch_k: MetricPattern22, + pub stoch_rsi: MetricPattern22, + pub stoch_rsi_d: MetricPattern22, + pub stoch_rsi_k: MetricPattern22, } impl CatalogTree_Computed_Market_Indicators { pub fn new(client: Arc, base_path: String) -> Self { Self { - gini: MetricPattern21::new(client.clone(), format!("{base_path}_gini")), - macd_histogram: MetricPattern21::new(client.clone(), format!("{base_path}_macd_histogram")), - macd_line: MetricPattern21::new(client.clone(), format!("{base_path}_macd_line")), - macd_signal: MetricPattern21::new(client.clone(), format!("{base_path}_macd_signal")), - nvt: MetricPattern21::new(client.clone(), format!("{base_path}_nvt")), - pi_cycle: MetricPattern21::new(client.clone(), format!("{base_path}_pi_cycle")), - puell_multiple: MetricPattern4::new(client.clone(), format!("{base_path}_puell_multiple")), - rsi_14d: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_14d")), - rsi_14d_max: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_14d_max")), - rsi_14d_min: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_14d_min")), - rsi_avg_gain_14d: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_avg_gain_14d")), - rsi_avg_loss_14d: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_avg_loss_14d")), - rsi_gains: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_gains")), - rsi_losses: MetricPattern21::new(client.clone(), format!("{base_path}_rsi_losses")), - stoch_d: MetricPattern21::new(client.clone(), format!("{base_path}_stoch_d")), - stoch_k: MetricPattern21::new(client.clone(), format!("{base_path}_stoch_k")), - stoch_rsi: MetricPattern21::new(client.clone(), format!("{base_path}_stoch_rsi")), - stoch_rsi_d: MetricPattern21::new(client.clone(), format!("{base_path}_stoch_rsi_d")), - stoch_rsi_k: MetricPattern21::new(client.clone(), format!("{base_path}_stoch_rsi_k")), + gini: MetricPattern22::new(client.clone(), format!("{base_path}_gini")), + macd_histogram: MetricPattern22::new(client.clone(), format!("{base_path}_macd_histogram")), + macd_line: MetricPattern22::new(client.clone(), format!("{base_path}_macd_line")), + macd_signal: MetricPattern22::new(client.clone(), format!("{base_path}_macd_signal")), + nvt: MetricPattern5::new(client.clone(), format!("{base_path}_nvt")), + pi_cycle: MetricPattern22::new(client.clone(), format!("{base_path}_pi_cycle")), + puell_multiple: MetricPattern5::new(client.clone(), format!("{base_path}_puell_multiple")), + rsi_14d: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_14d")), + rsi_14d_max: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_14d_max")), + rsi_14d_min: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_14d_min")), + rsi_average_gain_14d: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_average_gain_14d")), + rsi_average_loss_14d: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_average_loss_14d")), + rsi_gains: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_gains")), + rsi_losses: MetricPattern22::new(client.clone(), format!("{base_path}_rsi_losses")), + stoch_d: MetricPattern22::new(client.clone(), format!("{base_path}_stoch_d")), + stoch_k: MetricPattern22::new(client.clone(), format!("{base_path}_stoch_k")), + stoch_rsi: MetricPattern22::new(client.clone(), format!("{base_path}_stoch_rsi")), + stoch_rsi_d: MetricPattern22::new(client.clone(), format!("{base_path}_stoch_rsi_d")), + stoch_rsi_k: MetricPattern22::new(client.clone(), format!("{base_path}_stoch_rsi_k")), } } } @@ -5926,8 +6086,8 @@ pub struct CatalogTree_Computed_Market_MovingAverage { pub price_1y_sma: Price111dSmaPattern, pub price_200d_ema: Price111dSmaPattern, pub price_200d_sma: Price111dSmaPattern, - pub price_200d_sma_x0_8: MetricPattern4, - pub price_200d_sma_x2_4: MetricPattern4, + pub price_200d_sma_x0_8: MetricPattern5, + pub price_200d_sma_x2_4: MetricPattern5, pub price_200w_ema: Price111dSmaPattern, pub price_200w_sma: Price111dSmaPattern, pub price_21d_ema: Price111dSmaPattern, @@ -5938,7 +6098,7 @@ pub struct CatalogTree_Computed_Market_MovingAverage { pub price_34d_ema: Price111dSmaPattern, pub price_34d_sma: Price111dSmaPattern, pub price_350d_sma: Price111dSmaPattern, - pub price_350d_sma_x2: MetricPattern4, + pub price_350d_sma_x2: MetricPattern5, pub price_4y_ema: Price111dSmaPattern, pub price_4y_sma: Price111dSmaPattern, pub price_55d_ema: Price111dSmaPattern, @@ -5966,8 +6126,8 @@ impl CatalogTree_Computed_Market_MovingAverage { price_1y_sma: Price111dSmaPattern::new(client.clone(), "price_1y_sma".to_string()), price_200d_ema: Price111dSmaPattern::new(client.clone(), "price_200d_ema".to_string()), price_200d_sma: Price111dSmaPattern::new(client.clone(), "price_200d_sma".to_string()), - price_200d_sma_x0_8: MetricPattern4::new(client.clone(), format!("{base_path}_price_200d_sma_x0_8")), - price_200d_sma_x2_4: MetricPattern4::new(client.clone(), format!("{base_path}_price_200d_sma_x2_4")), + price_200d_sma_x0_8: MetricPattern5::new(client.clone(), format!("{base_path}_price_200d_sma_x0_8")), + price_200d_sma_x2_4: MetricPattern5::new(client.clone(), format!("{base_path}_price_200d_sma_x2_4")), price_200w_ema: Price111dSmaPattern::new(client.clone(), "price_200w_ema".to_string()), price_200w_sma: Price111dSmaPattern::new(client.clone(), "price_200w_sma".to_string()), price_21d_ema: Price111dSmaPattern::new(client.clone(), "price_21d_ema".to_string()), @@ -5978,7 +6138,7 @@ impl CatalogTree_Computed_Market_MovingAverage { price_34d_ema: Price111dSmaPattern::new(client.clone(), "price_34d_ema".to_string()), price_34d_sma: Price111dSmaPattern::new(client.clone(), "price_34d_sma".to_string()), price_350d_sma: Price111dSmaPattern::new(client.clone(), "price_350d_sma".to_string()), - price_350d_sma_x2: MetricPattern4::new(client.clone(), format!("{base_path}_price_350d_sma_x2")), + price_350d_sma_x2: MetricPattern5::new(client.clone(), format!("{base_path}_price_350d_sma_x2")), price_4y_ema: Price111dSmaPattern::new(client.clone(), "price_4y_ema".to_string()), price_4y_sma: Price111dSmaPattern::new(client.clone(), "price_4y_sma".to_string()), price_55d_ema: Price111dSmaPattern::new(client.clone(), "price_55d_ema".to_string()), @@ -5993,33 +6153,33 @@ impl CatalogTree_Computed_Market_MovingAverage { /// Catalog tree node. pub struct CatalogTree_Computed_Market_Range { - pub price_1m_max: MetricPattern4, - pub price_1m_min: MetricPattern4, - pub price_1w_max: MetricPattern4, - pub price_1w_min: MetricPattern4, - pub price_1y_max: MetricPattern4, - pub price_1y_min: MetricPattern4, - pub price_2w_choppiness_index: MetricPattern4, - pub price_2w_max: MetricPattern4, - pub price_2w_min: MetricPattern4, - pub price_true_range: MetricPattern21, - pub price_true_range_2w_sum: MetricPattern21, + pub price_1m_max: MetricPattern5, + pub price_1m_min: MetricPattern5, + pub price_1w_max: MetricPattern5, + pub price_1w_min: MetricPattern5, + pub price_1y_max: MetricPattern5, + pub price_1y_min: MetricPattern5, + pub price_2w_choppiness_index: MetricPattern5, + pub price_2w_max: MetricPattern5, + pub price_2w_min: MetricPattern5, + pub price_true_range: MetricPattern22, + pub price_true_range_2w_sum: MetricPattern22, } impl CatalogTree_Computed_Market_Range { pub fn new(client: Arc, base_path: String) -> Self { Self { - price_1m_max: MetricPattern4::new(client.clone(), format!("{base_path}_price_1m_max")), - price_1m_min: MetricPattern4::new(client.clone(), format!("{base_path}_price_1m_min")), - price_1w_max: MetricPattern4::new(client.clone(), format!("{base_path}_price_1w_max")), - price_1w_min: MetricPattern4::new(client.clone(), format!("{base_path}_price_1w_min")), - price_1y_max: MetricPattern4::new(client.clone(), format!("{base_path}_price_1y_max")), - price_1y_min: MetricPattern4::new(client.clone(), format!("{base_path}_price_1y_min")), - price_2w_choppiness_index: MetricPattern4::new(client.clone(), format!("{base_path}_price_2w_choppiness_index")), - price_2w_max: MetricPattern4::new(client.clone(), format!("{base_path}_price_2w_max")), - price_2w_min: MetricPattern4::new(client.clone(), format!("{base_path}_price_2w_min")), - price_true_range: MetricPattern21::new(client.clone(), format!("{base_path}_price_true_range")), - price_true_range_2w_sum: MetricPattern21::new(client.clone(), format!("{base_path}_price_true_range_2w_sum")), + price_1m_max: MetricPattern5::new(client.clone(), format!("{base_path}_price_1m_max")), + price_1m_min: MetricPattern5::new(client.clone(), format!("{base_path}_price_1m_min")), + price_1w_max: MetricPattern5::new(client.clone(), format!("{base_path}_price_1w_max")), + price_1w_min: MetricPattern5::new(client.clone(), format!("{base_path}_price_1w_min")), + price_1y_max: MetricPattern5::new(client.clone(), format!("{base_path}_price_1y_max")), + price_1y_min: MetricPattern5::new(client.clone(), format!("{base_path}_price_1y_min")), + price_2w_choppiness_index: MetricPattern5::new(client.clone(), format!("{base_path}_price_2w_choppiness_index")), + price_2w_max: MetricPattern5::new(client.clone(), format!("{base_path}_price_2w_max")), + price_2w_min: MetricPattern5::new(client.clone(), format!("{base_path}_price_2w_min")), + price_true_range: MetricPattern22::new(client.clone(), format!("{base_path}_price_true_range")), + price_true_range_2w_sum: MetricPattern22::new(client.clone(), format!("{base_path}_price_true_range_2w_sum")), } } } @@ -6033,7 +6193,7 @@ pub struct CatalogTree_Computed_Market_Returns { pub downside_1m_sd: _1dReturns1mSdPattern, pub downside_1w_sd: _1dReturns1mSdPattern, pub downside_1y_sd: _1dReturns1mSdPattern, - pub downside_returns: MetricPattern21, + pub downside_returns: MetricPattern22, pub price_returns: PriceAgoPattern, } @@ -6047,7 +6207,7 @@ impl CatalogTree_Computed_Market_Returns { downside_1m_sd: _1dReturns1mSdPattern::new(client.clone(), "downside_1m_sd".to_string()), downside_1w_sd: _1dReturns1mSdPattern::new(client.clone(), "downside_1w_sd".to_string()), downside_1y_sd: _1dReturns1mSdPattern::new(client.clone(), "downside_1y_sd".to_string()), - downside_returns: MetricPattern21::new(client.clone(), format!("{base_path}_downside_returns")), + downside_returns: MetricPattern22::new(client.clone(), format!("{base_path}_downside_returns")), price_returns: PriceAgoPattern::new(client.clone(), "price_returns".to_string()), } } @@ -6055,29 +6215,29 @@ impl CatalogTree_Computed_Market_Returns { /// Catalog tree node. pub struct CatalogTree_Computed_Market_Volatility { - pub price_1m_volatility: MetricPattern4, - pub price_1w_volatility: MetricPattern4, - pub price_1y_volatility: MetricPattern4, - pub sharpe_1m: MetricPattern21, - pub sharpe_1w: MetricPattern21, - pub sharpe_1y: MetricPattern21, - pub sortino_1m: MetricPattern21, - pub sortino_1w: MetricPattern21, - pub sortino_1y: MetricPattern21, + pub price_1m_volatility: MetricPattern5, + pub price_1w_volatility: MetricPattern5, + pub price_1y_volatility: MetricPattern5, + pub sharpe_1m: MetricPattern22, + pub sharpe_1w: MetricPattern22, + pub sharpe_1y: MetricPattern22, + pub sortino_1m: MetricPattern22, + pub sortino_1w: MetricPattern22, + pub sortino_1y: MetricPattern22, } impl CatalogTree_Computed_Market_Volatility { pub fn new(client: Arc, base_path: String) -> Self { Self { - price_1m_volatility: MetricPattern4::new(client.clone(), format!("{base_path}_price_1m_volatility")), - price_1w_volatility: MetricPattern4::new(client.clone(), format!("{base_path}_price_1w_volatility")), - price_1y_volatility: MetricPattern4::new(client.clone(), format!("{base_path}_price_1y_volatility")), - sharpe_1m: MetricPattern21::new(client.clone(), format!("{base_path}_sharpe_1m")), - sharpe_1w: MetricPattern21::new(client.clone(), format!("{base_path}_sharpe_1w")), - sharpe_1y: MetricPattern21::new(client.clone(), format!("{base_path}_sharpe_1y")), - sortino_1m: MetricPattern21::new(client.clone(), format!("{base_path}_sortino_1m")), - sortino_1w: MetricPattern21::new(client.clone(), format!("{base_path}_sortino_1w")), - sortino_1y: MetricPattern21::new(client.clone(), format!("{base_path}_sortino_1y")), + price_1m_volatility: MetricPattern5::new(client.clone(), format!("{base_path}_price_1m_volatility")), + price_1w_volatility: MetricPattern5::new(client.clone(), format!("{base_path}_price_1w_volatility")), + price_1y_volatility: MetricPattern5::new(client.clone(), format!("{base_path}_price_1y_volatility")), + sharpe_1m: MetricPattern22::new(client.clone(), format!("{base_path}_sharpe_1m")), + sharpe_1w: MetricPattern22::new(client.clone(), format!("{base_path}_sharpe_1w")), + sharpe_1y: MetricPattern22::new(client.clone(), format!("{base_path}_sharpe_1y")), + sortino_1m: MetricPattern22::new(client.clone(), format!("{base_path}_sortino_1m")), + sortino_1w: MetricPattern22::new(client.clone(), format!("{base_path}_sortino_1w")), + sortino_1y: MetricPattern22::new(client.clone(), format!("{base_path}_sortino_1y")), } } } @@ -6099,42 +6259,42 @@ impl CatalogTree_Computed_Outputs { /// Catalog tree node. pub struct CatalogTree_Computed_Outputs_Count { - pub count: BlockSizePattern, - pub utxo_count: BitcoinPattern, + pub count: CountPattern2, + pub utxo_count: DollarsPattern, } impl CatalogTree_Computed_Outputs_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - count: BlockSizePattern::new(client.clone(), "output_count".to_string()), - utxo_count: BitcoinPattern::new(client.clone(), "exact_utxo_count".to_string()), + count: CountPattern2::new(client.clone(), "output_count".to_string()), + utxo_count: DollarsPattern::new(client.clone(), "exact_utxo_count".to_string()), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Outputs_Spent { - pub txinindex: MetricPattern28, + pub txinindex: MetricPattern29, } impl CatalogTree_Computed_Outputs_Spent { pub fn new(client: Arc, base_path: String) -> Self { Self { - txinindex: MetricPattern28::new(client.clone(), format!("{base_path}_txinindex")), + txinindex: MetricPattern29::new(client.clone(), format!("{base_path}_txinindex")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Pools { - pub pool: MetricPattern25, + pub pool: MetricPattern26, pub vecs: CatalogTree_Computed_Pools_Vecs, } impl CatalogTree_Computed_Pools { pub fn new(client: Arc, base_path: String) -> Self { Self { - pool: MetricPattern25::new(client.clone(), format!("{base_path}_pool")), + pool: MetricPattern26::new(client.clone(), format!("{base_path}_pool")), vecs: CatalogTree_Computed_Pools_Vecs::new(client.clone(), format!("{base_path}_vecs")), } } @@ -6469,13 +6629,13 @@ impl CatalogTree_Computed_Pools_Vecs { /// Catalog tree node. pub struct CatalogTree_Computed_Positions { - pub position: MetricPattern16, + pub position: MetricPattern17, } impl CatalogTree_Computed_Positions { pub fn new(client: Arc, base_path: String) -> Self { Self { - position: MetricPattern16::new(client.clone(), format!("{base_path}_position")), + position: MetricPattern17::new(client.clone(), format!("{base_path}_position")), } } } @@ -6499,13 +6659,13 @@ impl CatalogTree_Computed_Price { /// Catalog tree node. pub struct CatalogTree_Computed_Price_Ohlc { - pub ohlc_in_cents: MetricPattern9, + pub ohlc_in_cents: MetricPattern10, } impl CatalogTree_Computed_Price_Ohlc { pub fn new(client: Arc, base_path: String) -> Self { Self { - ohlc_in_cents: MetricPattern9::new(client.clone(), format!("{base_path}_ohlc_in_cents")), + ohlc_in_cents: MetricPattern10::new(client.clone(), format!("{base_path}_ohlc_in_cents")), } } } @@ -6513,8 +6673,8 @@ impl CatalogTree_Computed_Price_Ohlc { /// Catalog tree node. pub struct CatalogTree_Computed_Price_Sats { pub price_close_in_sats: MetricPattern1, - pub price_high_in_sats: MetricPattern1, - pub price_low_in_sats: MetricPattern1, + pub price_high_in_sats: PriceHighInSatsPattern, + pub price_low_in_sats: PriceLowInSatsPattern, pub price_ohlc_in_sats: MetricPattern1, pub price_open_in_sats: MetricPattern1, } @@ -6523,8 +6683,8 @@ impl CatalogTree_Computed_Price_Sats { pub fn new(client: Arc, base_path: String) -> Self { Self { price_close_in_sats: MetricPattern1::new(client.clone(), format!("{base_path}_price_close_in_sats")), - price_high_in_sats: MetricPattern1::new(client.clone(), format!("{base_path}_price_high_in_sats")), - price_low_in_sats: MetricPattern1::new(client.clone(), format!("{base_path}_price_low_in_sats")), + price_high_in_sats: PriceHighInSatsPattern::new(client.clone(), "price_high_in_sats".to_string()), + price_low_in_sats: PriceLowInSatsPattern::new(client.clone(), "price_low_in_sats".to_string()), price_ohlc_in_sats: MetricPattern1::new(client.clone(), format!("{base_path}_price_ohlc_in_sats")), price_open_in_sats: MetricPattern1::new(client.clone(), format!("{base_path}_price_open_in_sats")), } @@ -6534,28 +6694,28 @@ impl CatalogTree_Computed_Price_Sats { /// Catalog tree node. pub struct CatalogTree_Computed_Price_Usd { pub price_close: MetricPattern1, - pub price_close_in_cents: MetricPattern9, - pub price_high: MetricPattern1, - pub price_high_in_cents: MetricPattern9, - pub price_low: MetricPattern1, - pub price_low_in_cents: MetricPattern9, + pub price_close_in_cents: MetricPattern10, + pub price_high: PriceHighInSatsPattern, + pub price_high_in_cents: MetricPattern10, + pub price_low: PriceLowInSatsPattern, + pub price_low_in_cents: MetricPattern10, pub price_ohlc: MetricPattern1, pub price_open: MetricPattern1, - pub price_open_in_cents: MetricPattern9, + pub price_open_in_cents: MetricPattern10, } impl CatalogTree_Computed_Price_Usd { pub fn new(client: Arc, base_path: String) -> Self { Self { price_close: MetricPattern1::new(client.clone(), format!("{base_path}_price_close")), - price_close_in_cents: MetricPattern9::new(client.clone(), format!("{base_path}_price_close_in_cents")), - price_high: MetricPattern1::new(client.clone(), format!("{base_path}_price_high")), - price_high_in_cents: MetricPattern9::new(client.clone(), format!("{base_path}_price_high_in_cents")), - price_low: MetricPattern1::new(client.clone(), format!("{base_path}_price_low")), - price_low_in_cents: MetricPattern9::new(client.clone(), format!("{base_path}_price_low_in_cents")), + price_close_in_cents: MetricPattern10::new(client.clone(), format!("{base_path}_price_close_in_cents")), + price_high: PriceHighInSatsPattern::new(client.clone(), "price_high".to_string()), + price_high_in_cents: MetricPattern10::new(client.clone(), format!("{base_path}_price_high_in_cents")), + price_low: PriceLowInSatsPattern::new(client.clone(), "price_low".to_string()), + price_low_in_cents: MetricPattern10::new(client.clone(), format!("{base_path}_price_low_in_cents")), price_ohlc: MetricPattern1::new(client.clone(), format!("{base_path}_price_ohlc")), price_open: MetricPattern1::new(client.clone(), format!("{base_path}_price_open")), - price_open_in_cents: MetricPattern9::new(client.clone(), format!("{base_path}_price_open_in_cents")), + price_open_in_cents: MetricPattern10::new(client.clone(), format!("{base_path}_price_open_in_cents")), } } } @@ -6577,94 +6737,54 @@ impl CatalogTree_Computed_Scripts { /// Catalog tree node. pub struct CatalogTree_Computed_Scripts_Count { - pub emptyoutput_count: BitcoinPattern, - pub opreturn_count: BitcoinPattern, - pub p2a_count: BitcoinPattern, - pub p2ms_count: BitcoinPattern, - pub p2pk33_count: BitcoinPattern, - pub p2pk65_count: BitcoinPattern, - pub p2pkh_count: BitcoinPattern, - pub p2sh_count: BitcoinPattern, - pub p2tr_count: BitcoinPattern, - pub p2wpkh_count: BitcoinPattern, - pub p2wsh_count: BitcoinPattern, - pub segwit_adoption: SegwitAdoptionPattern, - pub segwit_count: BitcoinPattern, - pub taproot_adoption: SegwitAdoptionPattern, - pub unknownoutput_count: BitcoinPattern, + pub emptyoutput_count: DollarsPattern, + pub opreturn_count: DollarsPattern, + pub p2a_count: DollarsPattern, + pub p2ms_count: DollarsPattern, + pub p2pk33_count: DollarsPattern, + pub p2pk65_count: DollarsPattern, + pub p2pkh_count: DollarsPattern, + pub p2sh_count: DollarsPattern, + pub p2tr_count: DollarsPattern, + pub p2wpkh_count: DollarsPattern, + pub p2wsh_count: DollarsPattern, + pub segwit_adoption: BlockCountPattern, + pub segwit_count: DollarsPattern, + pub taproot_adoption: BlockCountPattern, + pub unknownoutput_count: DollarsPattern, } impl CatalogTree_Computed_Scripts_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - emptyoutput_count: BitcoinPattern::new(client.clone(), "emptyoutput_count".to_string()), - opreturn_count: BitcoinPattern::new(client.clone(), "opreturn_count".to_string()), - p2a_count: BitcoinPattern::new(client.clone(), "p2a_count".to_string()), - p2ms_count: BitcoinPattern::new(client.clone(), "p2ms_count".to_string()), - p2pk33_count: BitcoinPattern::new(client.clone(), "p2pk33_count".to_string()), - p2pk65_count: BitcoinPattern::new(client.clone(), "p2pk65_count".to_string()), - p2pkh_count: BitcoinPattern::new(client.clone(), "p2pkh_count".to_string()), - p2sh_count: BitcoinPattern::new(client.clone(), "p2sh_count".to_string()), - p2tr_count: BitcoinPattern::new(client.clone(), "p2tr_count".to_string()), - p2wpkh_count: BitcoinPattern::new(client.clone(), "p2wpkh_count".to_string()), - p2wsh_count: BitcoinPattern::new(client.clone(), "p2wsh_count".to_string()), - segwit_adoption: SegwitAdoptionPattern::new(client.clone(), "segwit_adoption".to_string()), - segwit_count: BitcoinPattern::new(client.clone(), "segwit_count".to_string()), - taproot_adoption: SegwitAdoptionPattern::new(client.clone(), "taproot_adoption".to_string()), - unknownoutput_count: BitcoinPattern::new(client.clone(), "unknownoutput_count".to_string()), + emptyoutput_count: DollarsPattern::new(client.clone(), "emptyoutput_count".to_string()), + opreturn_count: DollarsPattern::new(client.clone(), "opreturn_count".to_string()), + p2a_count: DollarsPattern::new(client.clone(), "p2a_count".to_string()), + p2ms_count: DollarsPattern::new(client.clone(), "p2ms_count".to_string()), + p2pk33_count: DollarsPattern::new(client.clone(), "p2pk33_count".to_string()), + p2pk65_count: DollarsPattern::new(client.clone(), "p2pk65_count".to_string()), + p2pkh_count: DollarsPattern::new(client.clone(), "p2pkh_count".to_string()), + p2sh_count: DollarsPattern::new(client.clone(), "p2sh_count".to_string()), + p2tr_count: DollarsPattern::new(client.clone(), "p2tr_count".to_string()), + p2wpkh_count: DollarsPattern::new(client.clone(), "p2wpkh_count".to_string()), + p2wsh_count: DollarsPattern::new(client.clone(), "p2wsh_count".to_string()), + segwit_adoption: BlockCountPattern::new(client.clone(), "segwit_adoption".to_string()), + segwit_count: DollarsPattern::new(client.clone(), "segwit_count".to_string()), + taproot_adoption: BlockCountPattern::new(client.clone(), "taproot_adoption".to_string()), + unknownoutput_count: DollarsPattern::new(client.clone(), "unknownoutput_count".to_string()), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Scripts_Value { - pub opreturn_value: CatalogTree_Computed_Scripts_Value_OpreturnValue, + pub opreturn_value: CoinbasePattern, } impl CatalogTree_Computed_Scripts_Value { pub fn new(client: Arc, base_path: String) -> Self { Self { - opreturn_value: CatalogTree_Computed_Scripts_Value_OpreturnValue::new(client.clone(), format!("{base_path}_opreturn_value")), - } - } -} - -/// Catalog tree node. -pub struct CatalogTree_Computed_Scripts_Value_OpreturnValue { - pub base: MetricPattern25, - pub bitcoin: SegwitAdoptionPattern, - pub dollars: SegwitAdoptionPattern, - pub sats: CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats, -} - -impl CatalogTree_Computed_Scripts_Value_OpreturnValue { - pub fn new(client: Arc, base_path: String) -> Self { - Self { - base: MetricPattern25::new(client.clone(), format!("{base_path}_base")), - bitcoin: SegwitAdoptionPattern::new(client.clone(), "opreturn_value_btc".to_string()), - dollars: SegwitAdoptionPattern::new(client.clone(), "opreturn_value_usd".to_string()), - sats: CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats::new(client.clone(), format!("{base_path}_sats")), - } - } -} - -/// Catalog tree node. -pub struct CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats { - pub average: MetricPattern2, - pub cumulative: MetricPattern1, - pub max: MetricPattern2, - pub min: MetricPattern2, - pub sum: MetricPattern2, -} - -impl CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats { - pub fn new(client: Arc, base_path: String) -> Self { - Self { - average: MetricPattern2::new(client.clone(), format!("{base_path}_average")), - cumulative: MetricPattern1::new(client.clone(), format!("{base_path}_cumulative")), - max: MetricPattern2::new(client.clone(), format!("{base_path}_max")), - min: MetricPattern2::new(client.clone(), format!("{base_path}_min")), - sum: MetricPattern2::new(client.clone(), format!("{base_path}_sum")), + opreturn_value: CoinbasePattern::new(client.clone(), "opreturn_value".to_string()), } } } @@ -6692,77 +6812,77 @@ impl CatalogTree_Computed_Supply { /// Catalog tree node. pub struct CatalogTree_Computed_Supply_Burned { - pub opreturn: OpreturnPattern, - pub unspendable: OpreturnPattern, + pub opreturn: UnclaimedRewardsPattern, + pub unspendable: UnclaimedRewardsPattern, } impl CatalogTree_Computed_Supply_Burned { pub fn new(client: Arc, base_path: String) -> Self { Self { - opreturn: OpreturnPattern::new(client.clone(), "opreturn_supply".to_string()), - unspendable: OpreturnPattern::new(client.clone(), "unspendable_supply".to_string()), + opreturn: UnclaimedRewardsPattern::new(client.clone(), "opreturn_supply".to_string()), + unspendable: UnclaimedRewardsPattern::new(client.clone(), "unspendable_supply".to_string()), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Supply_Circulating { - pub btc: MetricPattern25, + pub btc: MetricPattern26, pub indexes: ActiveSupplyPattern, - pub sats: MetricPattern25, - pub usd: MetricPattern25, + pub sats: MetricPattern26, + pub usd: MetricPattern26, } impl CatalogTree_Computed_Supply_Circulating { pub fn new(client: Arc, base_path: String) -> Self { Self { - btc: MetricPattern25::new(client.clone(), format!("{base_path}_btc")), + btc: MetricPattern26::new(client.clone(), format!("{base_path}_btc")), indexes: ActiveSupplyPattern::new(client.clone(), "circulating".to_string()), - sats: MetricPattern25::new(client.clone(), format!("{base_path}_sats")), - usd: MetricPattern25::new(client.clone(), format!("{base_path}_usd")), + sats: MetricPattern26::new(client.clone(), format!("{base_path}_sats")), + usd: MetricPattern26::new(client.clone(), format!("{base_path}_usd")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Supply_Inflation { - pub indexes: MetricPattern4, + pub indexes: IndexesPattern2, } impl CatalogTree_Computed_Supply_Inflation { pub fn new(client: Arc, base_path: String) -> Self { Self { - indexes: MetricPattern4::new(client.clone(), format!("{base_path}_indexes")), + indexes: IndexesPattern2::new(client.clone(), "inflation_rate".to_string()), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Supply_MarketCap { - pub height: MetricPattern25, - pub indexes: MetricPattern4, + pub height: MetricPattern26, + pub indexes: MetricPattern5, } impl CatalogTree_Computed_Supply_MarketCap { pub fn new(client: Arc, base_path: String) -> Self { Self { - height: MetricPattern25::new(client.clone(), format!("{base_path}_height")), - indexes: MetricPattern4::new(client.clone(), format!("{base_path}_indexes")), + height: MetricPattern26::new(client.clone(), format!("{base_path}_height")), + indexes: MetricPattern5::new(client.clone(), format!("{base_path}_indexes")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Supply_Velocity { - pub btc: MetricPattern4, - pub usd: MetricPattern4, + pub btc: IndexesPattern2, + pub usd: IndexesPattern2, } impl CatalogTree_Computed_Supply_Velocity { pub fn new(client: Arc, base_path: String) -> Self { Self { - btc: MetricPattern4::new(client.clone(), format!("{base_path}_btc")), - usd: MetricPattern4::new(client.clone(), format!("{base_path}_usd")), + btc: IndexesPattern2::new(client.clone(), "btc_velocity".to_string()), + usd: IndexesPattern2::new(client.clone(), "usd_velocity".to_string()), } } } @@ -6790,15 +6910,15 @@ impl CatalogTree_Computed_Transactions { /// Catalog tree node. pub struct CatalogTree_Computed_Transactions_Count { - pub is_coinbase: MetricPattern38, - pub tx_count: BitcoinPattern, + pub is_coinbase: MetricPattern39, + pub tx_count: DollarsPattern, } impl CatalogTree_Computed_Transactions_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - is_coinbase: MetricPattern38::new(client.clone(), format!("{base_path}_is_coinbase")), - tx_count: BitcoinPattern::new(client.clone(), "tx_count".to_string()), + is_coinbase: MetricPattern39::new(client.clone(), format!("{base_path}_is_coinbase")), + tx_count: DollarsPattern::new(client.clone(), "tx_count".to_string()), } } } @@ -6807,8 +6927,8 @@ impl CatalogTree_Computed_Transactions_Count { pub struct CatalogTree_Computed_Transactions_Fees { pub fee: CatalogTree_Computed_Transactions_Fees_Fee, pub fee_rate: CatalogTree_Computed_Transactions_Fees_FeeRate, - pub input_value: MetricPattern38, - pub output_value: MetricPattern38, + pub input_value: MetricPattern39, + pub output_value: MetricPattern39, } impl CatalogTree_Computed_Transactions_Fees { @@ -6816,31 +6936,48 @@ impl CatalogTree_Computed_Transactions_Fees { Self { fee: CatalogTree_Computed_Transactions_Fees_Fee::new(client.clone(), format!("{base_path}_fee")), fee_rate: CatalogTree_Computed_Transactions_Fees_FeeRate::new(client.clone(), format!("{base_path}_fee_rate")), - input_value: MetricPattern38::new(client.clone(), format!("{base_path}_input_value")), - output_value: MetricPattern38::new(client.clone(), format!("{base_path}_output_value")), + input_value: MetricPattern39::new(client.clone(), format!("{base_path}_input_value")), + output_value: MetricPattern39::new(client.clone(), format!("{base_path}_output_value")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Transactions_Fees_Fee { - pub base: MetricPattern38, - pub bitcoin: BlockSizePattern, - pub bitcoin_txindex: MetricPattern38, - pub dollars: BlockSizePattern, - pub dollars_txindex: MetricPattern38, - pub sats: BlockSizePattern, + pub base: MetricPattern39, + pub bitcoin: CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin, + pub dollars: CountPattern2, + pub sats: CountPattern2, } impl CatalogTree_Computed_Transactions_Fees_Fee { pub fn new(client: Arc, base_path: String) -> Self { Self { - base: MetricPattern38::new(client.clone(), format!("{base_path}_base")), - bitcoin: BlockSizePattern::new(client.clone(), "fee_btc".to_string()), - bitcoin_txindex: MetricPattern38::new(client.clone(), format!("{base_path}_bitcoin_txindex")), - dollars: BlockSizePattern::new(client.clone(), "fee_usd".to_string()), - dollars_txindex: MetricPattern38::new(client.clone(), format!("{base_path}_dollars_txindex")), - sats: BlockSizePattern::new(client.clone(), "fee".to_string()), + base: MetricPattern39::new(client.clone(), format!("{base_path}_base")), + bitcoin: CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin::new(client.clone(), format!("{base_path}_bitcoin")), + dollars: CountPattern2::new(client.clone(), "fee_usd".to_string()), + sats: CountPattern2::new(client.clone(), "fee".to_string()), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin { + pub average: MetricPattern1, + pub cumulative: MetricPattern1, + pub max: MetricPattern1, + pub min: MetricPattern1, + pub sum: MetricPattern1, +} + +impl CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + average: MetricPattern1::new(client.clone(), format!("{base_path}_average")), + cumulative: MetricPattern1::new(client.clone(), format!("{base_path}_cumulative")), + max: MetricPattern1::new(client.clone(), format!("{base_path}_max")), + min: MetricPattern1::new(client.clone(), format!("{base_path}_min")), + sum: MetricPattern1::new(client.clone(), format!("{base_path}_sum")), } } } @@ -6848,28 +6985,20 @@ impl CatalogTree_Computed_Transactions_Fees_Fee { /// Catalog tree node. pub struct CatalogTree_Computed_Transactions_Fees_FeeRate { pub average: MetricPattern1, - pub base: MetricPattern38, + pub base: MetricPattern39, pub max: MetricPattern1, - pub median: MetricPattern25, pub min: MetricPattern1, - pub pct10: MetricPattern25, - pub pct25: MetricPattern25, - pub pct75: MetricPattern25, - pub pct90: MetricPattern25, + pub percentiles: PercentilesPattern, } impl CatalogTree_Computed_Transactions_Fees_FeeRate { pub fn new(client: Arc, base_path: String) -> Self { Self { average: MetricPattern1::new(client.clone(), format!("{base_path}_average")), - base: MetricPattern38::new(client.clone(), format!("{base_path}_base")), + base: MetricPattern39::new(client.clone(), format!("{base_path}_base")), max: MetricPattern1::new(client.clone(), format!("{base_path}_max")), - median: MetricPattern25::new(client.clone(), format!("{base_path}_median")), min: MetricPattern1::new(client.clone(), format!("{base_path}_min")), - pct10: MetricPattern25::new(client.clone(), format!("{base_path}_pct10")), - pct25: MetricPattern25::new(client.clone(), format!("{base_path}_pct25")), - pct75: MetricPattern25::new(client.clone(), format!("{base_path}_pct75")), - pct90: MetricPattern25::new(client.clone(), format!("{base_path}_pct90")), + percentiles: PercentilesPattern::new(client.clone(), "fee_rate".to_string()), } } } @@ -6878,8 +7007,8 @@ impl CatalogTree_Computed_Transactions_Fees_FeeRate { pub struct CatalogTree_Computed_Transactions_Size { pub tx_vsize: BlockIntervalPattern, pub tx_weight: BlockIntervalPattern, - pub vsize: MetricPattern38, - pub weight: MetricPattern38, + pub vsize: MetricPattern39, + pub weight: MetricPattern39, } impl CatalogTree_Computed_Transactions_Size { @@ -6887,8 +7016,8 @@ impl CatalogTree_Computed_Transactions_Size { Self { tx_vsize: BlockIntervalPattern::new(client.clone(), "tx_vsize".to_string()), tx_weight: BlockIntervalPattern::new(client.clone(), "tx_weight".to_string()), - vsize: MetricPattern38::new(client.clone(), format!("{base_path}_vsize")), - weight: MetricPattern38::new(client.clone(), format!("{base_path}_weight")), + vsize: MetricPattern39::new(client.clone(), format!("{base_path}_vsize")), + weight: MetricPattern39::new(client.clone(), format!("{base_path}_weight")), } } } @@ -6912,42 +7041,42 @@ impl CatalogTree_Computed_Transactions_Versions { /// Catalog tree node. pub struct CatalogTree_Computed_Transactions_Volume { - pub annualized_volume: MetricPattern4, - pub annualized_volume_btc: MetricPattern4, - pub annualized_volume_usd: MetricPattern4, - pub inputs_per_sec: MetricPattern4, - pub outputs_per_sec: MetricPattern4, + pub annualized_volume: MetricPattern5, + pub annualized_volume_btc: MetricPattern5, + pub annualized_volume_usd: MetricPattern5, + pub inputs_per_sec: MetricPattern5, + pub outputs_per_sec: MetricPattern5, pub sent_sum: CatalogTree_Computed_Transactions_Volume_SentSum, - pub tx_per_sec: MetricPattern4, + pub tx_per_sec: MetricPattern5, } impl CatalogTree_Computed_Transactions_Volume { pub fn new(client: Arc, base_path: String) -> Self { Self { - annualized_volume: MetricPattern4::new(client.clone(), format!("{base_path}_annualized_volume")), - annualized_volume_btc: MetricPattern4::new(client.clone(), format!("{base_path}_annualized_volume_btc")), - annualized_volume_usd: MetricPattern4::new(client.clone(), format!("{base_path}_annualized_volume_usd")), - inputs_per_sec: MetricPattern4::new(client.clone(), format!("{base_path}_inputs_per_sec")), - outputs_per_sec: MetricPattern4::new(client.clone(), format!("{base_path}_outputs_per_sec")), + annualized_volume: MetricPattern5::new(client.clone(), format!("{base_path}_annualized_volume")), + annualized_volume_btc: MetricPattern5::new(client.clone(), format!("{base_path}_annualized_volume_btc")), + annualized_volume_usd: MetricPattern5::new(client.clone(), format!("{base_path}_annualized_volume_usd")), + inputs_per_sec: MetricPattern5::new(client.clone(), format!("{base_path}_inputs_per_sec")), + outputs_per_sec: MetricPattern5::new(client.clone(), format!("{base_path}_outputs_per_sec")), sent_sum: CatalogTree_Computed_Transactions_Volume_SentSum::new(client.clone(), format!("{base_path}_sent_sum")), - tx_per_sec: MetricPattern4::new(client.clone(), format!("{base_path}_tx_per_sec")), + tx_per_sec: MetricPattern5::new(client.clone(), format!("{base_path}_tx_per_sec")), } } } /// Catalog tree node. pub struct CatalogTree_Computed_Transactions_Volume_SentSum { - pub bitcoin: TotalRealizedPnlPattern, - pub dollars: MetricPattern1, - pub sats: MetricPattern1, + pub bitcoin: MetricPattern1, + pub dollars: DifficultyAdjustmentPattern, + pub sats: DifficultyAdjustmentPattern, } impl CatalogTree_Computed_Transactions_Volume_SentSum { pub fn new(client: Arc, base_path: String) -> Self { Self { - bitcoin: TotalRealizedPnlPattern::new(client.clone(), "sent_sum_btc".to_string()), - dollars: MetricPattern1::new(client.clone(), format!("{base_path}_dollars")), - sats: MetricPattern1::new(client.clone(), format!("{base_path}_sats")), + bitcoin: MetricPattern1::new(client.clone(), format!("{base_path}_bitcoin")), + dollars: DifficultyAdjustmentPattern::new(client.clone(), "sent_sum_usd".to_string()), + sats: DifficultyAdjustmentPattern::new(client.clone(), "sent_sum".to_string()), } } } @@ -6977,158 +7106,158 @@ impl CatalogTree_Indexed { /// Catalog tree node. pub struct CatalogTree_Indexed_Address { - pub first_p2aaddressindex: MetricPattern25, - pub first_p2pk33addressindex: MetricPattern25, - pub first_p2pk65addressindex: MetricPattern25, - pub first_p2pkhaddressindex: MetricPattern25, - pub first_p2shaddressindex: MetricPattern25, - pub first_p2traddressindex: MetricPattern25, - pub first_p2wpkhaddressindex: MetricPattern25, - pub first_p2wshaddressindex: MetricPattern25, - pub p2abytes: MetricPattern29, - pub p2pk33bytes: MetricPattern31, - pub p2pk65bytes: MetricPattern32, - pub p2pkhbytes: MetricPattern33, - pub p2shbytes: MetricPattern34, - pub p2trbytes: MetricPattern35, - pub p2wpkhbytes: MetricPattern36, - pub p2wshbytes: MetricPattern37, + pub first_p2aaddressindex: MetricPattern26, + pub first_p2pk33addressindex: MetricPattern26, + pub first_p2pk65addressindex: MetricPattern26, + pub first_p2pkhaddressindex: MetricPattern26, + pub first_p2shaddressindex: MetricPattern26, + pub first_p2traddressindex: MetricPattern26, + pub first_p2wpkhaddressindex: MetricPattern26, + pub first_p2wshaddressindex: MetricPattern26, + pub p2abytes: MetricPattern30, + pub p2pk33bytes: MetricPattern32, + pub p2pk65bytes: MetricPattern33, + pub p2pkhbytes: MetricPattern34, + pub p2shbytes: MetricPattern35, + pub p2trbytes: MetricPattern36, + pub p2wpkhbytes: MetricPattern37, + pub p2wshbytes: MetricPattern38, } impl CatalogTree_Indexed_Address { pub fn new(client: Arc, base_path: String) -> Self { Self { - first_p2aaddressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2aaddressindex")), - first_p2pk33addressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2pk33addressindex")), - first_p2pk65addressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2pk65addressindex")), - first_p2pkhaddressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2pkhaddressindex")), - first_p2shaddressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2shaddressindex")), - first_p2traddressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2traddressindex")), - first_p2wpkhaddressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2wpkhaddressindex")), - first_p2wshaddressindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2wshaddressindex")), - p2abytes: MetricPattern29::new(client.clone(), format!("{base_path}_p2abytes")), - p2pk33bytes: MetricPattern31::new(client.clone(), format!("{base_path}_p2pk33bytes")), - p2pk65bytes: MetricPattern32::new(client.clone(), format!("{base_path}_p2pk65bytes")), - p2pkhbytes: MetricPattern33::new(client.clone(), format!("{base_path}_p2pkhbytes")), - p2shbytes: MetricPattern34::new(client.clone(), format!("{base_path}_p2shbytes")), - p2trbytes: MetricPattern35::new(client.clone(), format!("{base_path}_p2trbytes")), - p2wpkhbytes: MetricPattern36::new(client.clone(), format!("{base_path}_p2wpkhbytes")), - p2wshbytes: MetricPattern37::new(client.clone(), format!("{base_path}_p2wshbytes")), + first_p2aaddressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2aaddressindex")), + first_p2pk33addressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2pk33addressindex")), + first_p2pk65addressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2pk65addressindex")), + first_p2pkhaddressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2pkhaddressindex")), + first_p2shaddressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2shaddressindex")), + first_p2traddressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2traddressindex")), + first_p2wpkhaddressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2wpkhaddressindex")), + first_p2wshaddressindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2wshaddressindex")), + p2abytes: MetricPattern30::new(client.clone(), format!("{base_path}_p2abytes")), + p2pk33bytes: MetricPattern32::new(client.clone(), format!("{base_path}_p2pk33bytes")), + p2pk65bytes: MetricPattern33::new(client.clone(), format!("{base_path}_p2pk65bytes")), + p2pkhbytes: MetricPattern34::new(client.clone(), format!("{base_path}_p2pkhbytes")), + p2shbytes: MetricPattern35::new(client.clone(), format!("{base_path}_p2shbytes")), + p2trbytes: MetricPattern36::new(client.clone(), format!("{base_path}_p2trbytes")), + p2wpkhbytes: MetricPattern37::new(client.clone(), format!("{base_path}_p2wpkhbytes")), + p2wshbytes: MetricPattern38::new(client.clone(), format!("{base_path}_p2wshbytes")), } } } /// Catalog tree node. pub struct CatalogTree_Indexed_Block { - pub blockhash: MetricPattern25, - pub difficulty: MetricPattern25, - pub timestamp: MetricPattern25, - pub total_size: MetricPattern25, - pub weight: MetricPattern25, + pub blockhash: MetricPattern26, + pub difficulty: MetricPattern26, + pub timestamp: MetricPattern26, + pub total_size: MetricPattern26, + pub weight: MetricPattern26, } impl CatalogTree_Indexed_Block { pub fn new(client: Arc, base_path: String) -> Self { Self { - blockhash: MetricPattern25::new(client.clone(), format!("{base_path}_blockhash")), - difficulty: MetricPattern25::new(client.clone(), format!("{base_path}_difficulty")), - timestamp: MetricPattern25::new(client.clone(), format!("{base_path}_timestamp")), - total_size: MetricPattern25::new(client.clone(), format!("{base_path}_total_size")), - weight: MetricPattern25::new(client.clone(), format!("{base_path}_weight")), + blockhash: MetricPattern26::new(client.clone(), format!("{base_path}_blockhash")), + difficulty: MetricPattern26::new(client.clone(), format!("{base_path}_difficulty")), + timestamp: MetricPattern26::new(client.clone(), format!("{base_path}_timestamp")), + total_size: MetricPattern26::new(client.clone(), format!("{base_path}_total_size")), + weight: MetricPattern26::new(client.clone(), format!("{base_path}_weight")), } } } /// Catalog tree node. pub struct CatalogTree_Indexed_Output { - pub first_emptyoutputindex: MetricPattern25, - pub first_opreturnindex: MetricPattern25, - pub first_p2msoutputindex: MetricPattern25, - pub first_unknownoutputindex: MetricPattern25, - pub txindex: MetricPattern7, + pub first_emptyoutputindex: MetricPattern26, + pub first_opreturnindex: MetricPattern26, + pub first_p2msoutputindex: MetricPattern26, + pub first_unknownoutputindex: MetricPattern26, + pub txindex: MetricPattern8, } impl CatalogTree_Indexed_Output { pub fn new(client: Arc, base_path: String) -> Self { Self { - first_emptyoutputindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_emptyoutputindex")), - first_opreturnindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_opreturnindex")), - first_p2msoutputindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_p2msoutputindex")), - first_unknownoutputindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_unknownoutputindex")), - txindex: MetricPattern7::new(client.clone(), format!("{base_path}_txindex")), + first_emptyoutputindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_emptyoutputindex")), + first_opreturnindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_opreturnindex")), + first_p2msoutputindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_p2msoutputindex")), + first_unknownoutputindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_unknownoutputindex")), + txindex: MetricPattern8::new(client.clone(), format!("{base_path}_txindex")), } } } /// Catalog tree node. pub struct CatalogTree_Indexed_Tx { - pub base_size: MetricPattern38, - pub first_txindex: MetricPattern25, - pub first_txinindex: MetricPattern38, - pub first_txoutindex: MetricPattern38, - pub height: MetricPattern38, - pub is_explicitly_rbf: MetricPattern38, - pub rawlocktime: MetricPattern38, - pub total_size: MetricPattern38, - pub txid: MetricPattern38, - pub txversion: MetricPattern38, + pub base_size: MetricPattern39, + pub first_txindex: MetricPattern26, + pub first_txinindex: MetricPattern39, + pub first_txoutindex: MetricPattern39, + pub height: MetricPattern39, + pub is_explicitly_rbf: MetricPattern39, + pub rawlocktime: MetricPattern39, + pub total_size: MetricPattern39, + pub txid: MetricPattern39, + pub txversion: MetricPattern39, } impl CatalogTree_Indexed_Tx { pub fn new(client: Arc, base_path: String) -> Self { Self { - base_size: MetricPattern38::new(client.clone(), format!("{base_path}_base_size")), - first_txindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_txindex")), - first_txinindex: MetricPattern38::new(client.clone(), format!("{base_path}_first_txinindex")), - first_txoutindex: MetricPattern38::new(client.clone(), format!("{base_path}_first_txoutindex")), - height: MetricPattern38::new(client.clone(), format!("{base_path}_height")), - is_explicitly_rbf: MetricPattern38::new(client.clone(), format!("{base_path}_is_explicitly_rbf")), - rawlocktime: MetricPattern38::new(client.clone(), format!("{base_path}_rawlocktime")), - total_size: MetricPattern38::new(client.clone(), format!("{base_path}_total_size")), - txid: MetricPattern38::new(client.clone(), format!("{base_path}_txid")), - txversion: MetricPattern38::new(client.clone(), format!("{base_path}_txversion")), + base_size: MetricPattern39::new(client.clone(), format!("{base_path}_base_size")), + first_txindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_txindex")), + first_txinindex: MetricPattern39::new(client.clone(), format!("{base_path}_first_txinindex")), + first_txoutindex: MetricPattern39::new(client.clone(), format!("{base_path}_first_txoutindex")), + height: MetricPattern39::new(client.clone(), format!("{base_path}_height")), + is_explicitly_rbf: MetricPattern39::new(client.clone(), format!("{base_path}_is_explicitly_rbf")), + rawlocktime: MetricPattern39::new(client.clone(), format!("{base_path}_rawlocktime")), + total_size: MetricPattern39::new(client.clone(), format!("{base_path}_total_size")), + txid: MetricPattern39::new(client.clone(), format!("{base_path}_txid")), + txversion: MetricPattern39::new(client.clone(), format!("{base_path}_txversion")), } } } /// Catalog tree node. pub struct CatalogTree_Indexed_Txin { - pub first_txinindex: MetricPattern25, - pub outpoint: MetricPattern26, - pub outputtype: MetricPattern26, - pub txindex: MetricPattern26, - pub typeindex: MetricPattern26, + pub first_txinindex: MetricPattern26, + pub outpoint: MetricPattern27, + pub outputtype: MetricPattern27, + pub txindex: MetricPattern27, + pub typeindex: MetricPattern27, } impl CatalogTree_Indexed_Txin { pub fn new(client: Arc, base_path: String) -> Self { Self { - first_txinindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_txinindex")), - outpoint: MetricPattern26::new(client.clone(), format!("{base_path}_outpoint")), - outputtype: MetricPattern26::new(client.clone(), format!("{base_path}_outputtype")), - txindex: MetricPattern26::new(client.clone(), format!("{base_path}_txindex")), - typeindex: MetricPattern26::new(client.clone(), format!("{base_path}_typeindex")), + first_txinindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_txinindex")), + outpoint: MetricPattern27::new(client.clone(), format!("{base_path}_outpoint")), + outputtype: MetricPattern27::new(client.clone(), format!("{base_path}_outputtype")), + txindex: MetricPattern27::new(client.clone(), format!("{base_path}_txindex")), + typeindex: MetricPattern27::new(client.clone(), format!("{base_path}_typeindex")), } } } /// Catalog tree node. pub struct CatalogTree_Indexed_Txout { - pub first_txoutindex: MetricPattern25, - pub outputtype: MetricPattern28, - pub txindex: MetricPattern28, - pub typeindex: MetricPattern28, - pub value: MetricPattern28, + pub first_txoutindex: MetricPattern26, + pub outputtype: MetricPattern29, + pub txindex: MetricPattern29, + pub typeindex: MetricPattern29, + pub value: MetricPattern29, } impl CatalogTree_Indexed_Txout { pub fn new(client: Arc, base_path: String) -> Self { Self { - first_txoutindex: MetricPattern25::new(client.clone(), format!("{base_path}_first_txoutindex")), - outputtype: MetricPattern28::new(client.clone(), format!("{base_path}_outputtype")), - txindex: MetricPattern28::new(client.clone(), format!("{base_path}_txindex")), - typeindex: MetricPattern28::new(client.clone(), format!("{base_path}_typeindex")), - value: MetricPattern28::new(client.clone(), format!("{base_path}_value")), + first_txoutindex: MetricPattern26::new(client.clone(), format!("{base_path}_first_txoutindex")), + outputtype: MetricPattern29::new(client.clone(), format!("{base_path}_outputtype")), + txindex: MetricPattern29::new(client.clone(), format!("{base_path}_txindex")), + typeindex: MetricPattern29::new(client.clone(), format!("{base_path}_typeindex")), + value: MetricPattern29::new(client.clone(), format!("{base_path}_value")), } } } diff --git a/crates/brk_cohort/src/by_address_type.rs b/crates/brk_cohort/src/by_address_type.rs index 560840656..353fb5aca 100644 --- a/crates/brk_cohort/src/by_address_type.rs +++ b/crates/brk_cohort/src/by_address_type.rs @@ -1,10 +1,9 @@ use std::ops::{Add, AddAssign}; use brk_error::Result; -use brk_traversable::{Traversable, TreeNode}; +use brk_traversable::Traversable; use brk_types::OutputType; use rayon::prelude::*; -use vecdb::AnyExportableVec; use super::Filter; @@ -17,7 +16,7 @@ pub const P2WSH: &str = "p2wsh"; pub const P2TR: &str = "p2tr"; pub const P2A: &str = "p2a"; -#[derive(Default, Clone, Debug)] +#[derive(Default, Clone, Debug, Traversable)] pub struct ByAddressType { pub p2pk65: T, pub p2pk33: T, @@ -289,36 +288,3 @@ impl ByAddressType> { }); } } - -impl Traversable for ByAddressType { - fn to_tree_node(&self) -> TreeNode { - TreeNode::Branch( - [ - (P2PK65, &self.p2pk65), - (P2PK33, &self.p2pk33), - (P2PKH, &self.p2pkh), - (P2SH, &self.p2sh), - (P2WPKH, &self.p2wpkh), - (P2WSH, &self.p2wsh), - (P2TR, &self.p2tr), - (P2A, &self.p2a), - ] - .into_iter() - .map(|(name, field)| (name.to_string(), field.to_tree_node())) - .collect(), - ) - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut iter: Box> = - Box::new(self.p2pk65.iter_any_exportable()); - iter = Box::new(iter.chain(self.p2pk33.iter_any_exportable())); - iter = Box::new(iter.chain(self.p2pkh.iter_any_exportable())); - iter = Box::new(iter.chain(self.p2sh.iter_any_exportable())); - iter = Box::new(iter.chain(self.p2wpkh.iter_any_exportable())); - iter = Box::new(iter.chain(self.p2wsh.iter_any_exportable())); - iter = Box::new(iter.chain(self.p2tr.iter_any_exportable())); - iter = Box::new(iter.chain(self.p2a.iter_any_exportable())); - iter - } -} diff --git a/crates/brk_computer/Cargo.toml b/crates/brk_computer/Cargo.toml index d6a9b266e..db7821c02 100644 --- a/crates/brk_computer/Cargo.toml +++ b/crates/brk_computer/Cargo.toml @@ -21,7 +21,7 @@ brk_rpc = { workspace = true } brk_store = { workspace = true } brk_traversable = { workspace = true } brk_types = { workspace = true } -derive_deref = { workspace = true } +derive_more = { workspace = true } log = { workspace = true } pco = "0.4.9" rayon = { workspace = true } diff --git a/crates/brk_computer/src/blocks/count/compute.rs b/crates/brk_computer/src/blocks/count/compute.rs index 857c25240..7469bd5fb 100644 --- a/crates/brk_computer/src/blocks/count/compute.rs +++ b/crates/brk_computer/src/blocks/count/compute.rs @@ -47,38 +47,35 @@ impl Vecs { Ok(()) })?; - self.indexes_to_1w_block_count - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_block_count.dateindex.unwrap_sum(), - 7, - exit, - )?; - Ok(()) - })?; + self.indexes_to_1w_block_count.compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.sum.inner(), + 7, + exit, + )?; + Ok(()) + })?; - self.indexes_to_1m_block_count - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_block_count.dateindex.unwrap_sum(), - 30, - exit, - )?; - Ok(()) - })?; + self.indexes_to_1m_block_count.compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.sum.inner(), + 30, + exit, + )?; + Ok(()) + })?; - self.indexes_to_1y_block_count - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_block_count.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; + self.indexes_to_1y_block_count.compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.sum.inner(), + 365, + exit, + )?; + Ok(()) + })?; Ok(()) } diff --git a/crates/brk_computer/src/blocks/count/import.rs b/crates/brk_computer/src/blocks/count/import.rs index e51b492db..26e36385a 100644 --- a/crates/brk_computer/src/blocks/count/import.rs +++ b/crates/brk_computer/src/blocks/count/import.rs @@ -10,14 +10,11 @@ use crate::{ TARGET_BLOCKS_PER_YEAR, }, indexes, - internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::{ComputedBlockSumCum, ComputedDateLast}, }; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let last = || VecBuilderOptions::default().add_last(); - let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); - Ok(Self { dateindex_to_block_count_target: LazyVecFrom1::init( "block_count_target", @@ -62,37 +59,29 @@ impl Vecs { |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DECADE)), ), height_to_24h_block_count: EagerVec::forced_import(db, "24h_block_count", version)?, - indexes_to_block_count: ComputedVecsFromHeight::forced_import( + indexes_to_block_count: ComputedBlockSumCum::forced_import( db, "block_count", - Source::Compute, version, indexes, - sum_cum(), )?, - indexes_to_1w_block_count: ComputedVecsFromDateIndex::forced_import( + indexes_to_1w_block_count: ComputedDateLast::forced_import( db, "1w_block_count", - Source::Compute, version, indexes, - last(), )?, - indexes_to_1m_block_count: ComputedVecsFromDateIndex::forced_import( + indexes_to_1m_block_count: ComputedDateLast::forced_import( db, "1m_block_count", - Source::Compute, version, indexes, - last(), )?, - indexes_to_1y_block_count: ComputedVecsFromDateIndex::forced_import( + indexes_to_1y_block_count: ComputedDateLast::forced_import( db, "1y_block_count", - Source::Compute, version, indexes, - last(), )?, }) } diff --git a/crates/brk_computer/src/blocks/count/vecs.rs b/crates/brk_computer/src/blocks/count/vecs.rs index c67a71ec4..5d78a2fd1 100644 --- a/crates/brk_computer/src/blocks/count/vecs.rs +++ b/crates/brk_computer/src/blocks/count/vecs.rs @@ -1,24 +1,28 @@ use brk_traversable::Traversable; use brk_types::{ - DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, - StoredU32, StoredU64, WeekIndex, YearIndex, + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, StoredU32, StoredU64, + WeekIndex, YearIndex, }; use vecdb::LazyVecFrom1; -use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight}; +use crate::internal::{ComputedBlockSumCum, ComputedDateLast}; #[derive(Clone, Traversable)] pub struct Vecs { pub dateindex_to_block_count_target: LazyVecFrom1, pub weekindex_to_block_count_target: LazyVecFrom1, - pub monthindex_to_block_count_target: LazyVecFrom1, - pub quarterindex_to_block_count_target: LazyVecFrom1, - pub semesterindex_to_block_count_target: LazyVecFrom1, + pub monthindex_to_block_count_target: + LazyVecFrom1, + pub quarterindex_to_block_count_target: + LazyVecFrom1, + pub semesterindex_to_block_count_target: + LazyVecFrom1, pub yearindex_to_block_count_target: LazyVecFrom1, - pub decadeindex_to_block_count_target: LazyVecFrom1, + pub decadeindex_to_block_count_target: + LazyVecFrom1, pub height_to_24h_block_count: vecdb::EagerVec>, - pub indexes_to_block_count: ComputedVecsFromHeight, - pub indexes_to_1w_block_count: ComputedVecsFromDateIndex, - pub indexes_to_1m_block_count: ComputedVecsFromDateIndex, - pub indexes_to_1y_block_count: ComputedVecsFromDateIndex, + pub indexes_to_block_count: ComputedBlockSumCum, + pub indexes_to_1w_block_count: ComputedDateLast, + pub indexes_to_1m_block_count: ComputedDateLast, + pub indexes_to_1y_block_count: ComputedDateLast, } diff --git a/crates/brk_computer/src/blocks/difficulty/compute.rs b/crates/brk_computer/src/blocks/difficulty/compute.rs index 36b3b5cdb..e2a945385 100644 --- a/crates/brk_computer/src/blocks/difficulty/compute.rs +++ b/crates/brk_computer/src/blocks/difficulty/compute.rs @@ -15,8 +15,7 @@ impl Vecs { ) -> Result<()> { let mut height_to_difficultyepoch_iter = indexes.block.height_to_difficultyepoch.into_iter(); - self.indexes_to_difficultyepoch - .compute_all(starting_indexes, exit, |vec| { + self.indexes_to_difficultyepoch.compute_all(starting_indexes, exit, |vec| { let mut height_count_iter = indexes.time.dateindex_to_height_count.into_iter(); vec.compute_transform( starting_indexes.dateindex, @@ -48,10 +47,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_transform( starting_indexes.height, - self.indexes_to_blocks_before_next_difficulty_adjustment - .height - .as_ref() - .unwrap(), + &self.indexes_to_blocks_before_next_difficulty_adjustment.height, |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), exit, )?; diff --git a/crates/brk_computer/src/blocks/difficulty/import.rs b/crates/brk_computer/src/blocks/difficulty/import.rs index 07c50694a..034902bc3 100644 --- a/crates/brk_computer/src/blocks/difficulty/import.rs +++ b/crates/brk_computer/src/blocks/difficulty/import.rs @@ -5,41 +5,32 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::{ComputedBlockLast, ComputedDateLast}, }; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { let v2 = Version::TWO; - let last = || VecBuilderOptions::default().add_last(); Ok(Self { - indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import( + indexes_to_difficultyepoch: ComputedDateLast::forced_import( db, "difficultyepoch", - Source::Compute, version, indexes, - last(), )?, - indexes_to_blocks_before_next_difficulty_adjustment: - ComputedVecsFromHeight::forced_import( - db, - "blocks_before_next_difficulty_adjustment", - Source::Compute, - version + v2, - indexes, - last(), - )?, - indexes_to_days_before_next_difficulty_adjustment: - ComputedVecsFromHeight::forced_import( - db, - "days_before_next_difficulty_adjustment", - Source::Compute, - version + v2, - indexes, - last(), - )?, + indexes_to_blocks_before_next_difficulty_adjustment: ComputedBlockLast::forced_import( + db, + "blocks_before_next_difficulty_adjustment", + version + v2, + indexes, + )?, + indexes_to_days_before_next_difficulty_adjustment: ComputedBlockLast::forced_import( + db, + "days_before_next_difficulty_adjustment", + version + v2, + indexes, + )?, }) } } diff --git a/crates/brk_computer/src/blocks/difficulty/vecs.rs b/crates/brk_computer/src/blocks/difficulty/vecs.rs index 0fc429ba0..7bfef635f 100644 --- a/crates/brk_computer/src/blocks/difficulty/vecs.rs +++ b/crates/brk_computer/src/blocks/difficulty/vecs.rs @@ -1,12 +1,12 @@ use brk_traversable::Traversable; use brk_types::{DifficultyEpoch, StoredF32, StoredU32}; -use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight}; +use crate::internal::{ComputedBlockLast, ComputedDateLast}; /// Difficulty epoch metrics and countdown #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex, - pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedVecsFromHeight, - pub indexes_to_days_before_next_difficulty_adjustment: ComputedVecsFromHeight, + pub indexes_to_difficultyepoch: ComputedDateLast, + pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedBlockLast, + pub indexes_to_days_before_next_difficulty_adjustment: ComputedBlockLast, } diff --git a/crates/brk_computer/src/blocks/halving/compute.rs b/crates/brk_computer/src/blocks/halving/compute.rs index fa8ce7a45..48f9df86e 100644 --- a/crates/brk_computer/src/blocks/halving/compute.rs +++ b/crates/brk_computer/src/blocks/halving/compute.rs @@ -14,8 +14,7 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let mut height_to_halvingepoch_iter = indexes.block.height_to_halvingepoch.into_iter(); - self.indexes_to_halvingepoch - .compute_all(starting_indexes, exit, |vec| { + self.indexes_to_halvingepoch.compute_all(starting_indexes, exit, |vec| { let mut height_count_iter = indexes.time.dateindex_to_height_count.into_iter(); vec.compute_transform( starting_indexes.dateindex, @@ -54,10 +53,7 @@ impl Vecs { |v| { v.compute_transform( starting_indexes.height, - self.indexes_to_blocks_before_next_halving - .height - .as_ref() - .unwrap(), + &self.indexes_to_blocks_before_next_halving.height, |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), exit, )?; diff --git a/crates/brk_computer/src/blocks/halving/import.rs b/crates/brk_computer/src/blocks/halving/import.rs index e84ae82ef..8604d2d0f 100644 --- a/crates/brk_computer/src/blocks/halving/import.rs +++ b/crates/brk_computer/src/blocks/halving/import.rs @@ -5,38 +5,31 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::{ComputedBlockLast, ComputedDateLast}, }; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { let v2 = Version::TWO; - let last = || VecBuilderOptions::default().add_last(); Ok(Self { - indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import( + indexes_to_halvingepoch: ComputedDateLast::forced_import( db, "halvingepoch", - Source::Compute, version, indexes, - last(), )?, - indexes_to_blocks_before_next_halving: ComputedVecsFromHeight::forced_import( + indexes_to_blocks_before_next_halving: ComputedBlockLast::forced_import( db, "blocks_before_next_halving", - Source::Compute, version + v2, indexes, - last(), )?, - indexes_to_days_before_next_halving: ComputedVecsFromHeight::forced_import( + indexes_to_days_before_next_halving: ComputedBlockLast::forced_import( db, "days_before_next_halving", - Source::Compute, version + v2, indexes, - last(), )?, }) } diff --git a/crates/brk_computer/src/blocks/halving/vecs.rs b/crates/brk_computer/src/blocks/halving/vecs.rs index 950de887a..a94bee6e6 100644 --- a/crates/brk_computer/src/blocks/halving/vecs.rs +++ b/crates/brk_computer/src/blocks/halving/vecs.rs @@ -1,12 +1,12 @@ use brk_traversable::Traversable; use brk_types::{HalvingEpoch, StoredF32, StoredU32}; -use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight}; +use crate::internal::{ComputedBlockLast, ComputedDateLast}; /// Halving epoch metrics and countdown #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_halvingepoch: ComputedVecsFromDateIndex, - pub indexes_to_blocks_before_next_halving: ComputedVecsFromHeight, - pub indexes_to_days_before_next_halving: ComputedVecsFromHeight, + pub indexes_to_halvingepoch: ComputedDateLast, + pub indexes_to_blocks_before_next_halving: ComputedBlockLast, + pub indexes_to_days_before_next_halving: ComputedBlockLast, } diff --git a/crates/brk_computer/src/blocks/interval/compute.rs b/crates/brk_computer/src/blocks/interval/compute.rs index 19b5965de..5d0cdb732 100644 --- a/crates/brk_computer/src/blocks/interval/compute.rs +++ b/crates/brk_computer/src/blocks/interval/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use vecdb::Exit; use super::Vecs; -use crate::{ComputeIndexes, indexes}; +use crate::{indexes, ComputeIndexes}; impl Vecs { pub fn compute( @@ -11,11 +11,11 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_block_interval.compute_rest( + self.indexes_to_block_interval.derive_from( indexes, starting_indexes, + &self.height_to_interval, exit, - Some(&self.height_to_interval), )?; Ok(()) diff --git a/crates/brk_computer/src/blocks/interval/import.rs b/crates/brk_computer/src/blocks/interval/import.rs index d59207cd2..40653e58a 100644 --- a/crates/brk_computer/src/blocks/interval/import.rs +++ b/crates/brk_computer/src/blocks/interval/import.rs @@ -4,10 +4,7 @@ use brk_types::{CheckedSub, Height, Timestamp, Version}; use vecdb::{Database, IterableCloneableVec, LazyVecFrom1}; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::DerivedComputedBlockDistribution}; impl Vecs { pub fn forced_import( @@ -16,13 +13,6 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - }; - let height_to_interval = LazyVecFrom1::init( "interval", version, @@ -40,16 +30,17 @@ impl Vecs { }, ); + let indexes_to_block_interval = DerivedComputedBlockDistribution::forced_import( + db, + "block_interval", + height_to_interval.boxed_clone(), + version, + indexes, + )?; + Ok(Self { - indexes_to_block_interval: ComputedVecsFromHeight::forced_import( - db, - "block_interval", - Source::Vec(height_to_interval.boxed_clone()), - version, - indexes, - stats(), - )?, height_to_interval, + indexes_to_block_interval, }) } } diff --git a/crates/brk_computer/src/blocks/interval/vecs.rs b/crates/brk_computer/src/blocks/interval/vecs.rs index 64c36d2cb..9bab6f663 100644 --- a/crates/brk_computer/src/blocks/interval/vecs.rs +++ b/crates/brk_computer/src/blocks/interval/vecs.rs @@ -2,10 +2,10 @@ use brk_traversable::Traversable; use brk_types::{Height, Timestamp}; use vecdb::LazyVecFrom1; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::DerivedComputedBlockDistribution; #[derive(Clone, Traversable)] pub struct Vecs { pub height_to_interval: LazyVecFrom1, - pub indexes_to_block_interval: ComputedVecsFromHeight, + pub indexes_to_block_interval: DerivedComputedBlockDistribution, } diff --git a/crates/brk_computer/src/blocks/mining/compute.rs b/crates/brk_computer/src/blocks/mining/compute.rs index 02f5b315c..ffc0bea53 100644 --- a/crates/brk_computer/src/blocks/mining/compute.rs +++ b/crates/brk_computer/src/blocks/mining/compute.rs @@ -5,11 +5,7 @@ use vecdb::Exit; use super::Vecs; use super::super::{count, rewards, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F64}; -use crate::{ - indexes, - utils::OptionExt, - ComputeIndexes, -}; +use crate::{indexes, ComputeIndexes}; impl Vecs { pub fn compute( @@ -21,11 +17,11 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_difficulty.compute_rest( + self.indexes_to_difficulty.derive_from( indexes, starting_indexes, + &indexer.vecs.block.height_to_difficulty, exit, - Some(&indexer.vecs.block.height_to_difficulty), )?; self.indexes_to_difficulty_as_hash @@ -45,7 +41,7 @@ impl Vecs { v.compute_transform2( starting_indexes.height, &count_vecs.height_to_24h_block_count, - self.indexes_to_difficulty_as_hash.height.u(), + &self.indexes_to_difficulty_as_hash.height, |(i, block_count_sum, difficulty_as_hash, ..)| { ( i, @@ -60,44 +56,40 @@ impl Vecs { Ok(()) })?; - self.indexes_to_hash_rate_1w_sma - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_hash_rate_1w_sma.compute_all(starting_indexes, exit, |v| { v.compute_sma( starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), + self.indexes_to_hash_rate.dateindex.inner(), 7, exit, )?; Ok(()) })?; - self.indexes_to_hash_rate_1m_sma - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_hash_rate_1m_sma.compute_all(starting_indexes, exit, |v| { v.compute_sma( starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), + self.indexes_to_hash_rate.dateindex.inner(), 30, exit, )?; Ok(()) })?; - self.indexes_to_hash_rate_2m_sma - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_hash_rate_2m_sma.compute_all(starting_indexes, exit, |v| { v.compute_sma( starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), + self.indexes_to_hash_rate.dateindex.inner(), 2 * 30, exit, )?; Ok(()) })?; - self.indexes_to_hash_rate_1y_sma - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_hash_rate_1y_sma.compute_all(starting_indexes, exit, |v| { v.compute_sma( starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), + self.indexes_to_hash_rate.dateindex.inner(), 365, exit, )?; @@ -124,7 +116,7 @@ impl Vecs { v.compute_transform2( starting_indexes.height, &rewards_vecs.height_to_24h_coinbase_usd_sum, - self.indexes_to_hash_rate.height.u(), + &self.indexes_to_hash_rate.height, |(i, coinbase_sum, hashrate, ..)| { let hashrate_ths = *hashrate / ONE_TERA_HASH; let price = if hashrate_ths == 0.0 { @@ -143,7 +135,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_transform( starting_indexes.height, - self.indexes_to_hash_price_ths.height.u(), + &self.indexes_to_hash_price_ths.height, |(i, price, ..)| (i, (*price * 1000.0).into()), exit, )?; @@ -155,7 +147,7 @@ impl Vecs { v.compute_transform2( starting_indexes.height, &rewards_vecs.height_to_24h_coinbase_sum, - self.indexes_to_hash_rate.height.u(), + &self.indexes_to_hash_rate.height, |(i, coinbase_sum, hashrate, ..)| { let hashrate_ths = *hashrate / ONE_TERA_HASH; let value = if hashrate_ths == 0.0 { @@ -174,7 +166,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_transform( starting_indexes.height, - self.indexes_to_hash_value_ths.height.u(), + &self.indexes_to_hash_value_ths.height, |(i, value, ..)| (i, (*value * 1000.0).into()), exit, )?; @@ -185,7 +177,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_all_time_low_( starting_indexes.height, - self.indexes_to_hash_price_ths.height.u(), + &self.indexes_to_hash_price_ths.height, exit, true, )?; @@ -196,7 +188,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_all_time_low_( starting_indexes.height, - self.indexes_to_hash_price_phs.height.u(), + &self.indexes_to_hash_price_phs.height, exit, true, )?; @@ -207,7 +199,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_all_time_low_( starting_indexes.height, - self.indexes_to_hash_value_ths.height.u(), + &self.indexes_to_hash_value_ths.height, exit, true, )?; @@ -218,7 +210,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_all_time_low_( starting_indexes.height, - self.indexes_to_hash_value_phs.height.u(), + &self.indexes_to_hash_value_phs.height, exit, true, )?; @@ -229,8 +221,8 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_percentage_difference( starting_indexes.height, - self.indexes_to_hash_price_phs.height.u(), - self.indexes_to_hash_price_phs_min.height.u(), + &self.indexes_to_hash_price_phs.height, + &self.indexes_to_hash_price_phs_min.height, exit, )?; Ok(()) @@ -240,8 +232,8 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |v| { v.compute_percentage_difference( starting_indexes.height, - self.indexes_to_hash_value_phs.height.u(), - self.indexes_to_hash_value_phs_min.height.u(), + &self.indexes_to_hash_value_phs.height, + &self.indexes_to_hash_value_phs_min.height, exit, )?; Ok(()) diff --git a/crates/brk_computer/src/blocks/mining/import.rs b/crates/brk_computer/src/blocks/mining/import.rs index 89973be17..40d54cd50 100644 --- a/crates/brk_computer/src/blocks/mining/import.rs +++ b/crates/brk_computer/src/blocks/mining/import.rs @@ -6,7 +6,7 @@ use vecdb::{Database, IterableCloneableVec}; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::{ComputedBlockLast, ComputedBlockSum, ComputedDateLast, DerivedComputedBlockLast}, }; impl Vecs { @@ -19,153 +19,116 @@ impl Vecs { let v4 = Version::new(4); let v5 = Version::new(5); - let last = || VecBuilderOptions::default().add_last(); - let sum = || VecBuilderOptions::default().add_sum(); - Ok(Self { - indexes_to_hash_rate: ComputedVecsFromHeight::forced_import( + indexes_to_hash_rate: ComputedBlockLast::forced_import( db, "hash_rate", - Source::Compute, version + v5, indexes, - last(), )?, - indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex::forced_import( + indexes_to_hash_rate_1w_sma: ComputedDateLast::forced_import( db, "hash_rate_1w_sma", - Source::Compute, version, indexes, - last(), )?, - indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex::forced_import( + indexes_to_hash_rate_1m_sma: ComputedDateLast::forced_import( db, "hash_rate_1m_sma", - Source::Compute, version, indexes, - last(), )?, - indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex::forced_import( + indexes_to_hash_rate_2m_sma: ComputedDateLast::forced_import( db, "hash_rate_2m_sma", - Source::Compute, version, indexes, - last(), )?, - indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex::forced_import( + indexes_to_hash_rate_1y_sma: ComputedDateLast::forced_import( db, "hash_rate_1y_sma", - Source::Compute, version, indexes, - last(), )?, - indexes_to_hash_price_ths: ComputedVecsFromHeight::forced_import( + indexes_to_hash_price_ths: ComputedBlockLast::forced_import( db, "hash_price_ths", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_price_ths_min: ComputedVecsFromHeight::forced_import( + indexes_to_hash_price_ths_min: ComputedBlockLast::forced_import( db, "hash_price_ths_min", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_price_phs: ComputedVecsFromHeight::forced_import( + indexes_to_hash_price_phs: ComputedBlockLast::forced_import( db, "hash_price_phs", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_price_phs_min: ComputedVecsFromHeight::forced_import( + indexes_to_hash_price_phs_min: ComputedBlockLast::forced_import( db, "hash_price_phs_min", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_price_rebound: ComputedVecsFromHeight::forced_import( + indexes_to_hash_price_rebound: ComputedBlockLast::forced_import( db, "hash_price_rebound", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_value_ths: ComputedVecsFromHeight::forced_import( + indexes_to_hash_value_ths: ComputedBlockLast::forced_import( db, "hash_value_ths", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_value_ths_min: ComputedVecsFromHeight::forced_import( + indexes_to_hash_value_ths_min: ComputedBlockLast::forced_import( db, "hash_value_ths_min", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_value_phs: ComputedVecsFromHeight::forced_import( + indexes_to_hash_value_phs: ComputedBlockLast::forced_import( db, "hash_value_phs", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_value_phs_min: ComputedVecsFromHeight::forced_import( + indexes_to_hash_value_phs_min: ComputedBlockLast::forced_import( db, "hash_value_phs_min", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_hash_value_rebound: ComputedVecsFromHeight::forced_import( + indexes_to_hash_value_rebound: ComputedBlockLast::forced_import( db, "hash_value_rebound", - Source::Compute, version + v4, indexes, - last(), )?, - indexes_to_difficulty: ComputedVecsFromHeight::forced_import( + // Derived from external indexer data - no height storage needed + indexes_to_difficulty: DerivedComputedBlockLast::forced_import( db, "difficulty", - Source::Vec(indexer.vecs.block.height_to_difficulty.boxed_clone()), + indexer.vecs.block.height_to_difficulty.boxed_clone(), version, indexes, - last(), )?, - indexes_to_difficulty_as_hash: ComputedVecsFromHeight::forced_import( + indexes_to_difficulty_as_hash: ComputedBlockLast::forced_import( db, "difficulty_as_hash", - Source::Compute, version, indexes, - last(), )?, - indexes_to_difficulty_adjustment: ComputedVecsFromHeight::forced_import( + indexes_to_difficulty_adjustment: ComputedBlockSum::forced_import( db, "difficulty_adjustment", - Source::Compute, version, indexes, - sum(), )?, }) } diff --git a/crates/brk_computer/src/blocks/mining/vecs.rs b/crates/brk_computer/src/blocks/mining/vecs.rs index c14077999..6051df11f 100644 --- a/crates/brk_computer/src/blocks/mining/vecs.rs +++ b/crates/brk_computer/src/blocks/mining/vecs.rs @@ -1,27 +1,30 @@ use brk_traversable::Traversable; use brk_types::{StoredF32, StoredF64}; -use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight}; +use crate::internal::{ + ComputedBlockLast, ComputedBlockSum, ComputedDateLast, DerivedComputedBlockLast, +}; /// Mining-related metrics: hash rate, hash price, hash value, difficulty #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_hash_rate: ComputedVecsFromHeight, - pub indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_price_ths: ComputedVecsFromHeight, - pub indexes_to_hash_price_ths_min: ComputedVecsFromHeight, - pub indexes_to_hash_price_phs: ComputedVecsFromHeight, - pub indexes_to_hash_price_phs_min: ComputedVecsFromHeight, - pub indexes_to_hash_price_rebound: ComputedVecsFromHeight, - pub indexes_to_hash_value_ths: ComputedVecsFromHeight, - pub indexes_to_hash_value_ths_min: ComputedVecsFromHeight, - pub indexes_to_hash_value_phs: ComputedVecsFromHeight, - pub indexes_to_hash_value_phs_min: ComputedVecsFromHeight, - pub indexes_to_hash_value_rebound: ComputedVecsFromHeight, - pub indexes_to_difficulty: ComputedVecsFromHeight, - pub indexes_to_difficulty_as_hash: ComputedVecsFromHeight, - pub indexes_to_difficulty_adjustment: ComputedVecsFromHeight, + pub indexes_to_hash_rate: ComputedBlockLast, + pub indexes_to_hash_rate_1w_sma: ComputedDateLast, + pub indexes_to_hash_rate_1m_sma: ComputedDateLast, + pub indexes_to_hash_rate_2m_sma: ComputedDateLast, + pub indexes_to_hash_rate_1y_sma: ComputedDateLast, + pub indexes_to_hash_price_ths: ComputedBlockLast, + pub indexes_to_hash_price_ths_min: ComputedBlockLast, + pub indexes_to_hash_price_phs: ComputedBlockLast, + pub indexes_to_hash_price_phs_min: ComputedBlockLast, + pub indexes_to_hash_price_rebound: ComputedBlockLast, + pub indexes_to_hash_value_ths: ComputedBlockLast, + pub indexes_to_hash_value_ths_min: ComputedBlockLast, + pub indexes_to_hash_value_phs: ComputedBlockLast, + pub indexes_to_hash_value_phs_min: ComputedBlockLast, + pub indexes_to_hash_value_rebound: ComputedBlockLast, + /// Derived from indexer - no height storage needed + pub indexes_to_difficulty: DerivedComputedBlockLast, + pub indexes_to_difficulty_as_hash: ComputedBlockLast, + pub indexes_to_difficulty_adjustment: ComputedBlockSum, } diff --git a/crates/brk_computer/src/blocks/rewards/compute.rs b/crates/brk_computer/src/blocks/rewards/compute.rs index c1e3041ba..79ae21444 100644 --- a/crates/brk_computer/src/blocks/rewards/compute.rs +++ b/crates/brk_computer/src/blocks/rewards/compute.rs @@ -3,14 +3,9 @@ use brk_indexer::Indexer; use brk_types::{CheckedSub, Dollars, HalvingEpoch, Height, Sats, StoredF32, TxOutIndex}; use vecdb::{Exit, IterableVec, TypedVecIterator, VecIndex}; -use super::Vecs; -use crate::{ - transactions, - ComputeIndexes, - indexes, price, - utils::OptionExt, -}; use super::super::count; +use super::Vecs; +use crate::{indexes, price, transactions, ComputeIndexes}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -53,13 +48,7 @@ impl Vecs { Ok(()) })?; - let mut height_to_coinbase_iter = self - .indexes_to_coinbase - .sats - .height - .as_ref() - .unwrap() - .into_iter(); + let mut height_to_coinbase_iter = self.indexes_to_coinbase.sats.height.into_iter(); self.height_to_24h_coinbase_sum.compute_transform( starting_indexes.height, &count_vecs.height_to_24h_block_count, @@ -75,12 +64,8 @@ impl Vecs { )?; drop(height_to_coinbase_iter); - if let Some(mut height_to_coinbase_iter) = self - .indexes_to_coinbase - .dollars - .as_ref() - .map(|c| c.height.u().into_iter()) - { + if let Some(ref dollars) = self.indexes_to_coinbase.dollars { + let mut height_to_coinbase_iter = dollars.height.into_iter(); self.height_to_24h_coinbase_usd_sum.compute_transform( starting_indexes.height, &count_vecs.height_to_24h_block_count, @@ -98,10 +83,11 @@ impl Vecs { self.indexes_to_subsidy .compute_all(indexes, price, starting_indexes, exit, |vec| { + // KISS: height.sum_cum.sum.0 is now a concrete field vec.compute_transform2( starting_indexes.height, - self.indexes_to_coinbase.sats.height.u(), - transactions_fees.indexes_to_fee.sats.height.unwrap_sum(), + &self.indexes_to_coinbase.sats.height, + &transactions_fees.indexes_to_fee.sats.height.sum_cum.sum.0, |(height, coinbase, fees, ..)| { ( height, @@ -124,7 +110,7 @@ impl Vecs { |vec| { vec.compute_transform( starting_indexes.height, - self.indexes_to_subsidy.sats.height.u(), + &self.indexes_to_subsidy.sats.height, |(height, subsidy, ..)| { let halving = HalvingEpoch::from(height); let expected = Sats::FIFTY_BTC / 2_usize.pow(halving.to_usize() as u32); @@ -136,10 +122,11 @@ impl Vecs { }, )?; + // KISS: dateindex.sum_cum.sum.0 is now a concrete field self.dateindex_to_fee_dominance.compute_transform2( starting_indexes.dateindex, - transactions_fees.indexes_to_fee.sats.dateindex.unwrap_sum(), - self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), + &transactions_fees.indexes_to_fee.sats.dateindex.sum_cum.sum.0, + &self.indexes_to_coinbase.sats.dateindex.sum_cum.sum.0, |(i, fee, coinbase, ..)| { let coinbase_f64 = u64::from(coinbase) as f64; let dominance = if coinbase_f64 == 0.0 { @@ -154,8 +141,8 @@ impl Vecs { self.dateindex_to_subsidy_dominance.compute_transform2( starting_indexes.dateindex, - self.indexes_to_subsidy.sats.dateindex.unwrap_sum(), - self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), + &self.indexes_to_subsidy.sats.dateindex.sum_cum.sum.0, + &self.indexes_to_coinbase.sats.dateindex.sum_cum.sum.0, |(i, subsidy, coinbase, ..)| { let coinbase_f64 = u64::from(coinbase) as f64; let dominance = if coinbase_f64 == 0.0 { @@ -169,13 +156,15 @@ impl Vecs { )?; if let Some(sma) = self.indexes_to_subsidy_usd_1y_sma.as_mut() { - let date_to_coinbase_usd_sum = self + let date_to_coinbase_usd_sum = &self .indexes_to_coinbase .dollars .as_ref() .unwrap() .dateindex - .unwrap_sum(); + .sum_cum + .sum + .0; sma.compute_all(starting_indexes, exit, |v| { v.compute_sma( diff --git a/crates/brk_computer/src/blocks/rewards/import.rs b/crates/brk_computer/src/blocks/rewards/import.rs index f1a96c957..48dbbad81 100644 --- a/crates/brk_computer/src/blocks/rewards/import.rs +++ b/crates/brk_computer/src/blocks/rewards/import.rs @@ -5,7 +5,7 @@ use vecdb::{Database, EagerVec, ImportableVec}; use super::Vecs; use crate::{ indexes, - internal::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, Source, VecBuilderOptions}, + internal::{ComputedDateLast, ValueBlockFull, ValueBlockSumCum}, }; impl Vecs { @@ -15,8 +15,6 @@ impl Vecs { indexes: &indexes::Vecs, compute_dollars: bool, ) -> Result { - let last = || VecBuilderOptions::default().add_last(); - Ok(Self { height_to_24h_coinbase_sum: EagerVec::forced_import(db, "24h_coinbase_sum", version)?, height_to_24h_coinbase_usd_sum: EagerVec::forced_import( @@ -24,42 +22,26 @@ impl Vecs { "24h_coinbase_usd_sum", version, )?, - indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import( + indexes_to_coinbase: ValueBlockFull::forced_import( db, "coinbase", - Source::Compute, version, - VecBuilderOptions::default() - .add_sum() - .add_cumulative() - .add_percentiles() - .add_minmax() - .add_average(), - compute_dollars, indexes, + compute_dollars, )?, - indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import( + indexes_to_subsidy: ValueBlockFull::forced_import( db, "subsidy", - Source::Compute, version, - VecBuilderOptions::default() - .add_percentiles() - .add_sum() - .add_cumulative() - .add_minmax() - .add_average(), - compute_dollars, indexes, + compute_dollars, )?, - indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight::forced_import( + indexes_to_unclaimed_rewards: ValueBlockSumCum::forced_import( db, "unclaimed_rewards", - Source::Compute, version, - VecBuilderOptions::default().add_sum().add_cumulative(), - compute_dollars, indexes, + compute_dollars, )?, dateindex_to_fee_dominance: EagerVec::forced_import(db, "fee_dominance", version)?, dateindex_to_subsidy_dominance: EagerVec::forced_import( @@ -69,14 +51,7 @@ impl Vecs { )?, indexes_to_subsidy_usd_1y_sma: compute_dollars .then(|| { - ComputedVecsFromDateIndex::forced_import( - db, - "subsidy_usd_1y_sma", - Source::Compute, - version, - indexes, - last(), - ) + ComputedDateLast::forced_import(db, "subsidy_usd_1y_sma", version, indexes) }) .transpose()?, }) diff --git a/crates/brk_computer/src/blocks/rewards/vecs.rs b/crates/brk_computer/src/blocks/rewards/vecs.rs index e1a0188ea..e6f6dd3a8 100644 --- a/crates/brk_computer/src/blocks/rewards/vecs.rs +++ b/crates/brk_computer/src/blocks/rewards/vecs.rs @@ -2,17 +2,17 @@ use brk_traversable::Traversable; use brk_types::{DateIndex, Dollars, Height, Sats, StoredF32}; use vecdb::{EagerVec, PcoVec}; -use crate::internal::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex}; +use crate::internal::{ComputedDateLast, ValueBlockFull, ValueBlockSumCum}; /// Coinbase/subsidy/rewards metrics #[derive(Clone, Traversable)] pub struct Vecs { pub height_to_24h_coinbase_sum: EagerVec>, pub height_to_24h_coinbase_usd_sum: EagerVec>, - pub indexes_to_coinbase: ComputedValueVecsFromHeight, - pub indexes_to_subsidy: ComputedValueVecsFromHeight, - pub indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight, + pub indexes_to_coinbase: ValueBlockFull, + pub indexes_to_subsidy: ValueBlockFull, + pub indexes_to_unclaimed_rewards: ValueBlockSumCum, pub dateindex_to_fee_dominance: EagerVec>, pub dateindex_to_subsidy_dominance: EagerVec>, - pub indexes_to_subsidy_usd_1y_sma: Option>, + pub indexes_to_subsidy_usd_1y_sma: Option>, } diff --git a/crates/brk_computer/src/blocks/size/compute.rs b/crates/brk_computer/src/blocks/size/compute.rs index ec33f0cdd..423c5ad14 100644 --- a/crates/brk_computer/src/blocks/size/compute.rs +++ b/crates/brk_computer/src/blocks/size/compute.rs @@ -13,18 +13,18 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_block_size.compute_rest( + self.indexes_to_block_size.derive_from( indexes, starting_indexes, + &indexer.vecs.block.height_to_total_size, exit, - Some(&indexer.vecs.block.height_to_total_size), )?; - self.indexes_to_block_vbytes.compute_rest( + self.indexes_to_block_vbytes.derive_from( indexes, starting_indexes, + &self.height_to_vbytes, exit, - Some(&self.height_to_vbytes), )?; Ok(()) diff --git a/crates/brk_computer/src/blocks/size/import.rs b/crates/brk_computer/src/blocks/size/import.rs index d8e4031fd..5b7d6b675 100644 --- a/crates/brk_computer/src/blocks/size/import.rs +++ b/crates/brk_computer/src/blocks/size/import.rs @@ -6,7 +6,7 @@ use vecdb::{Database, IterableCloneableVec, LazyVecFrom1, VecIndex}; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::DerivedComputedBlockFull, }; impl Vecs { @@ -16,15 +16,6 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; - let height_to_vbytes = LazyVecFrom1::init( "vbytes", version, @@ -37,21 +28,19 @@ impl Vecs { ); Ok(Self { - indexes_to_block_size: ComputedVecsFromHeight::forced_import( + indexes_to_block_size: DerivedComputedBlockFull::forced_import( db, "block_size", - Source::Vec(indexer.vecs.block.height_to_total_size.boxed_clone()), + indexer.vecs.block.height_to_total_size.boxed_clone(), version, indexes, - full_stats(), )?, - indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import( + indexes_to_block_vbytes: DerivedComputedBlockFull::forced_import( db, "block_vbytes", - Source::Vec(height_to_vbytes.boxed_clone()), + height_to_vbytes.boxed_clone(), version, indexes, - full_stats(), )?, height_to_vbytes, }) diff --git a/crates/brk_computer/src/blocks/size/vecs.rs b/crates/brk_computer/src/blocks/size/vecs.rs index 85a240afd..40690d44f 100644 --- a/crates/brk_computer/src/blocks/size/vecs.rs +++ b/crates/brk_computer/src/blocks/size/vecs.rs @@ -2,11 +2,11 @@ use brk_traversable::Traversable; use brk_types::{Height, StoredU64, Weight}; use vecdb::LazyVecFrom1; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::DerivedComputedBlockFull; #[derive(Clone, Traversable)] pub struct Vecs { pub height_to_vbytes: LazyVecFrom1, - pub indexes_to_block_size: ComputedVecsFromHeight, - pub indexes_to_block_vbytes: ComputedVecsFromHeight, + pub indexes_to_block_size: DerivedComputedBlockFull, + pub indexes_to_block_vbytes: DerivedComputedBlockFull, } diff --git a/crates/brk_computer/src/blocks/time/import.rs b/crates/brk_computer/src/blocks/time/import.rs index 956df1347..5870f0a66 100644 --- a/crates/brk_computer/src/blocks/time/import.rs +++ b/crates/brk_computer/src/blocks/time/import.rs @@ -6,10 +6,7 @@ use vecdb::{ }; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedVecsDateFirst}; impl Vecs { pub fn forced_import( @@ -47,13 +44,11 @@ impl Vecs { .and_then(|h: Height| timestamp_iter.get(h)) }, ), - timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import( + timeindexes_to_timestamp: ComputedVecsDateFirst::forced_import( db, "timestamp", - Source::Compute, version, indexes, - VecBuilderOptions::default().add_first(), )?, }) } diff --git a/crates/brk_computer/src/blocks/time/vecs.rs b/crates/brk_computer/src/blocks/time/vecs.rs index 58f8d64fd..e886a5704 100644 --- a/crates/brk_computer/src/blocks/time/vecs.rs +++ b/crates/brk_computer/src/blocks/time/vecs.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::{Date, DifficultyEpoch, Height, Timestamp}; use vecdb::{EagerVec, LazyVecFrom1, LazyVecFrom2, PcoVec}; -use crate::internal::ComputedVecsFromDateIndex; +use crate::internal::ComputedVecsDateFirst; /// Timestamp and date metrics for blocks #[derive(Clone, Traversable)] @@ -12,5 +12,5 @@ pub struct Vecs { pub height_to_timestamp_fixed: EagerVec>, pub difficultyepoch_to_timestamp: LazyVecFrom2, - pub timeindexes_to_timestamp: ComputedVecsFromDateIndex, + pub timeindexes_to_timestamp: ComputedVecsDateFirst, } diff --git a/crates/brk_computer/src/blocks/weight/compute.rs b/crates/brk_computer/src/blocks/weight/compute.rs index 5caa10600..e9a05634a 100644 --- a/crates/brk_computer/src/blocks/weight/compute.rs +++ b/crates/brk_computer/src/blocks/weight/compute.rs @@ -13,11 +13,11 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_block_weight.compute_rest( + self.indexes_to_block_weight.derive_from( indexes, starting_indexes, + &indexer.vecs.block.height_to_weight, exit, - Some(&indexer.vecs.block.height_to_weight), )?; Ok(()) diff --git a/crates/brk_computer/src/blocks/weight/import.rs b/crates/brk_computer/src/blocks/weight/import.rs index 2e61994e4..8cd819a30 100644 --- a/crates/brk_computer/src/blocks/weight/import.rs +++ b/crates/brk_computer/src/blocks/weight/import.rs @@ -7,7 +7,7 @@ use super::Vecs; use crate::{ indexes, internal::{ - ComputedVecsFromHeight, LazyVecsFromHeight, Source, VecBuilderOptions, WeightToFullness, + DerivedComputedBlockFull, LazyBlockFull, WeightToFullness, }, }; @@ -18,30 +18,21 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; - - let indexes_to_block_weight = ComputedVecsFromHeight::forced_import( + let indexes_to_block_weight = DerivedComputedBlockFull::forced_import( db, "block_weight", - Source::Vec(indexer.vecs.block.height_to_weight.boxed_clone()), + indexer.vecs.block.height_to_weight.boxed_clone(), version, indexes, - full_stats(), )?; - let indexes_to_block_fullness = LazyVecsFromHeight::from_computed::( - "block_fullness", - version, - indexer.vecs.block.height_to_weight.boxed_clone(), - &indexes_to_block_weight, - ); + let indexes_to_block_fullness = + LazyBlockFull::from_derived::( + "block_fullness", + version, + indexer.vecs.block.height_to_weight.boxed_clone(), + &indexes_to_block_weight, + ); Ok(Self { indexes_to_block_weight, diff --git a/crates/brk_computer/src/blocks/weight/vecs.rs b/crates/brk_computer/src/blocks/weight/vecs.rs index 409b62762..baf72f3fd 100644 --- a/crates/brk_computer/src/blocks/weight/vecs.rs +++ b/crates/brk_computer/src/blocks/weight/vecs.rs @@ -1,11 +1,11 @@ use brk_traversable::Traversable; use brk_types::{StoredF32, Weight}; -use crate::internal::{ComputedVecsFromHeight, LazyVecsFromHeight}; +use crate::internal::{DerivedComputedBlockFull, LazyBlockFull}; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_block_weight: ComputedVecsFromHeight, + pub indexes_to_block_weight: DerivedComputedBlockFull, /// Block fullness as percentage of max block weight (0-100%) - pub indexes_to_block_fullness: LazyVecsFromHeight, + pub indexes_to_block_fullness: LazyBlockFull, } diff --git a/crates/brk_computer/src/cointime/activity/compute.rs b/crates/brk_computer/src/cointime/activity/compute.rs index 95af18156..f8c3065ce 100644 --- a/crates/brk_computer/src/cointime/activity/compute.rs +++ b/crates/brk_computer/src/cointime/activity/compute.rs @@ -3,7 +3,7 @@ use brk_types::{Bitcoin, CheckedSub, StoredF64}; use vecdb::{Exit, TypedVecIterator}; use super::Vecs; -use crate::{distribution, indexes, utils::OptionExt, ComputeIndexes}; +use crate::{distribution, indexes, ComputeIndexes}; impl Vecs { pub fn compute( @@ -37,12 +37,10 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |vec| { let mut coinblocks_destroyed_iter = indexes_to_coinblocks_destroyed .height - .as_ref() - .unwrap() .into_iter(); vec.compute_transform( starting_indexes.height, - self.indexes_to_coinblocks_created.height.u(), + &self.indexes_to_coinblocks_created.height, |(i, created, ..)| { let destroyed = coinblocks_destroyed_iter.get_unwrap(i); (i, created.checked_sub(destroyed).unwrap()) @@ -56,12 +54,8 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |vec| { vec.compute_divide( starting_indexes.height, - indexes_to_coinblocks_destroyed - .height_extra - .unwrap_cumulative(), - self.indexes_to_coinblocks_created - .height_extra - .unwrap_cumulative(), + indexes_to_coinblocks_destroyed.height_cumulative.inner(), + self.indexes_to_coinblocks_created.height_cumulative.inner(), exit, )?; Ok(()) @@ -71,7 +65,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |vec| { vec.compute_transform( starting_indexes.height, - self.indexes_to_liveliness.height.u(), + &self.indexes_to_liveliness.height, |(i, v, ..)| (i, StoredF64::from(1.0).checked_sub(v).unwrap()), exit, )?; @@ -85,8 +79,8 @@ impl Vecs { |vec| { vec.compute_divide( starting_indexes.height, - self.indexes_to_liveliness.height.u(), - self.indexes_to_vaultedness.height.u(), + &self.indexes_to_liveliness.height, + &self.indexes_to_vaultedness.height, exit, )?; Ok(()) diff --git a/crates/brk_computer/src/cointime/activity/import.rs b/crates/brk_computer/src/cointime/activity/import.rs index 696088a15..74e46b6e8 100644 --- a/crates/brk_computer/src/cointime/activity/import.rs +++ b/crates/brk_computer/src/cointime/activity/import.rs @@ -5,36 +5,42 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::{ComputedBlockLast, ComputedBlockSumCum}, }; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let last = || VecBuilderOptions::default().add_last(); - let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); - - macro_rules! computed_h { - ($name:expr, $opts:expr) => { - ComputedVecsFromHeight::forced_import( - db, - $name, - Source::Compute, - version, - indexes, - $opts, - )? - }; - } - Ok(Self { - indexes_to_coinblocks_created: computed_h!("coinblocks_created", sum_cum()), - indexes_to_coinblocks_stored: computed_h!("coinblocks_stored", sum_cum()), - indexes_to_liveliness: computed_h!("liveliness", last()), - indexes_to_vaultedness: computed_h!("vaultedness", last()), - indexes_to_activity_to_vaultedness_ratio: computed_h!( + indexes_to_coinblocks_created: ComputedBlockSumCum::forced_import( + db, + "coinblocks_created", + version, + indexes, + )?, + indexes_to_coinblocks_stored: ComputedBlockSumCum::forced_import( + db, + "coinblocks_stored", + version, + indexes, + )?, + indexes_to_liveliness: ComputedBlockLast::forced_import( + db, + "liveliness", + version, + indexes, + )?, + indexes_to_vaultedness: ComputedBlockLast::forced_import( + db, + "vaultedness", + version, + indexes, + )?, + indexes_to_activity_to_vaultedness_ratio: ComputedBlockLast::forced_import( + db, "activity_to_vaultedness_ratio", - last() - ), + version, + indexes, + )?, }) } } diff --git a/crates/brk_computer/src/cointime/activity/vecs.rs b/crates/brk_computer/src/cointime/activity/vecs.rs index a7bddcfb1..12083d784 100644 --- a/crates/brk_computer/src/cointime/activity/vecs.rs +++ b/crates/brk_computer/src/cointime/activity/vecs.rs @@ -1,13 +1,13 @@ use brk_traversable::Traversable; use brk_types::StoredF64; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::{ComputedBlockLast, ComputedBlockSumCum}; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_coinblocks_created: ComputedVecsFromHeight, - pub indexes_to_coinblocks_stored: ComputedVecsFromHeight, - pub indexes_to_liveliness: ComputedVecsFromHeight, - pub indexes_to_vaultedness: ComputedVecsFromHeight, - pub indexes_to_activity_to_vaultedness_ratio: ComputedVecsFromHeight, + pub indexes_to_coinblocks_created: ComputedBlockSumCum, + pub indexes_to_coinblocks_stored: ComputedBlockSumCum, + pub indexes_to_liveliness: ComputedBlockLast, + pub indexes_to_vaultedness: ComputedBlockLast, + pub indexes_to_activity_to_vaultedness_ratio: ComputedBlockLast, } diff --git a/crates/brk_computer/src/cointime/adjusted/compute.rs b/crates/brk_computer/src/cointime/adjusted/compute.rs index 7208b2af3..5378b8f8e 100644 --- a/crates/brk_computer/src/cointime/adjusted/compute.rs +++ b/crates/brk_computer/src/cointime/adjusted/compute.rs @@ -3,7 +3,7 @@ use vecdb::Exit; use super::Vecs; use super::super::activity; -use crate::{supply, ComputeIndexes, utils::OptionExt}; +use crate::{supply, ComputeIndexes}; impl Vecs { pub fn compute( @@ -18,11 +18,8 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_multiply( starting_indexes.dateindex, - activity - .indexes_to_activity_to_vaultedness_ratio - .dateindex - .unwrap_last(), - supply.inflation.indexes.dateindex.u(), + activity.indexes_to_activity_to_vaultedness_ratio.dateindex.inner(), + &supply.inflation.indexes.dateindex, exit, )?; Ok(()) @@ -32,33 +29,23 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_multiply( starting_indexes.dateindex, - activity - .indexes_to_activity_to_vaultedness_ratio - .dateindex - .unwrap_last(), - supply.velocity.indexes_to_btc.dateindex.u(), + activity.indexes_to_activity_to_vaultedness_ratio.dateindex.inner(), + &supply.velocity.indexes_to_btc.dateindex, exit, )?; Ok(()) })?; if has_price { - self.indexes_to_cointime_adj_tx_usd_velocity.compute_all( - starting_indexes, - exit, - |v| { - v.compute_multiply( - starting_indexes.dateindex, - activity - .indexes_to_activity_to_vaultedness_ratio - .dateindex - .unwrap_last(), - supply.velocity.indexes_to_usd.u().dateindex.u(), - exit, - )?; - Ok(()) - }, - )?; + self.indexes_to_cointime_adj_tx_usd_velocity.compute_all(starting_indexes, exit, |v| { + v.compute_multiply( + starting_indexes.dateindex, + activity.indexes_to_activity_to_vaultedness_ratio.dateindex.inner(), + &supply.velocity.indexes_to_usd.as_ref().unwrap().dateindex, + exit, + )?; + Ok(()) + })?; } Ok(()) diff --git a/crates/brk_computer/src/cointime/adjusted/import.rs b/crates/brk_computer/src/cointime/adjusted/import.rs index 87c4d9b47..fc1c813d2 100644 --- a/crates/brk_computer/src/cointime/adjusted/import.rs +++ b/crates/brk_computer/src/cointime/adjusted/import.rs @@ -3,32 +3,29 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedDateLast}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let last = || VecBuilderOptions::default().add_last(); - - macro_rules! computed_di { - ($name:expr) => { - ComputedVecsFromDateIndex::forced_import( - db, - $name, - Source::Compute, - version, - indexes, - last(), - )? - }; - } - Ok(Self { - indexes_to_cointime_adj_inflation_rate: computed_di!("cointime_adj_inflation_rate"), - indexes_to_cointime_adj_tx_btc_velocity: computed_di!("cointime_adj_tx_btc_velocity"), - indexes_to_cointime_adj_tx_usd_velocity: computed_di!("cointime_adj_tx_usd_velocity"), + indexes_to_cointime_adj_inflation_rate: ComputedDateLast::forced_import( + db, + "cointime_adj_inflation_rate", + version, + indexes, + )?, + indexes_to_cointime_adj_tx_btc_velocity: ComputedDateLast::forced_import( + db, + "cointime_adj_tx_btc_velocity", + version, + indexes, + )?, + indexes_to_cointime_adj_tx_usd_velocity: ComputedDateLast::forced_import( + db, + "cointime_adj_tx_usd_velocity", + version, + indexes, + )?, }) } } diff --git a/crates/brk_computer/src/cointime/adjusted/vecs.rs b/crates/brk_computer/src/cointime/adjusted/vecs.rs index c0cc1fc64..7d479ee33 100644 --- a/crates/brk_computer/src/cointime/adjusted/vecs.rs +++ b/crates/brk_computer/src/cointime/adjusted/vecs.rs @@ -1,11 +1,11 @@ use brk_traversable::Traversable; use brk_types::{StoredF32, StoredF64}; -use crate::internal::ComputedVecsFromDateIndex; +use crate::internal::ComputedDateLast; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_cointime_adj_inflation_rate: ComputedVecsFromDateIndex, - pub indexes_to_cointime_adj_tx_btc_velocity: ComputedVecsFromDateIndex, - pub indexes_to_cointime_adj_tx_usd_velocity: ComputedVecsFromDateIndex, + pub indexes_to_cointime_adj_inflation_rate: ComputedDateLast, + pub indexes_to_cointime_adj_tx_btc_velocity: ComputedDateLast, + pub indexes_to_cointime_adj_tx_usd_velocity: ComputedDateLast, } diff --git a/crates/brk_computer/src/cointime/cap/compute.rs b/crates/brk_computer/src/cointime/cap/compute.rs index ba1f240b6..71f08e694 100644 --- a/crates/brk_computer/src/cointime/cap/compute.rs +++ b/crates/brk_computer/src/cointime/cap/compute.rs @@ -4,7 +4,7 @@ use vecdb::Exit; use super::super::{activity, value}; use super::Vecs; -use crate::{ComputeIndexes, blocks, distribution, indexes, utils::OptionExt}; +use crate::{blocks, distribution, indexes, utils::OptionExt, ComputeIndexes}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -36,16 +36,17 @@ impl Vecs { self.indexes_to_thermo_cap .compute_all(indexes, starting_indexes, exit, |vec| { + // KISS: height_cumulative is now a concrete field (not Option) vec.compute_transform( starting_indexes.height, - blocks + &blocks .rewards .indexes_to_subsidy .dollars .as_ref() .unwrap() - .height_extra - .unwrap_cumulative(), + .height_cumulative + .0, |(i, v, ..)| (i, v), exit, )?; @@ -57,7 +58,7 @@ impl Vecs { vec.compute_subtract( starting_indexes.height, realized_cap, - self.indexes_to_thermo_cap.height.u(), + &self.indexes_to_thermo_cap.height, exit, )?; Ok(()) @@ -68,7 +69,7 @@ impl Vecs { vec.compute_divide( starting_indexes.height, realized_cap, - activity.indexes_to_vaultedness.height.u(), + &activity.indexes_to_vaultedness.height, exit, )?; Ok(()) @@ -79,7 +80,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, realized_cap, - activity.indexes_to_liveliness.height.u(), + &activity.indexes_to_liveliness.height, exit, )?; Ok(()) @@ -90,15 +91,9 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |vec| { vec.compute_transform3( starting_indexes.height, - value - .indexes_to_cointime_value_destroyed - .height_extra - .unwrap_cumulative(), + value.indexes_to_cointime_value_destroyed.height_cumulative.inner(), circulating_supply, - activity - .indexes_to_coinblocks_stored - .height_extra - .unwrap_cumulative(), + activity.indexes_to_coinblocks_stored.height_cumulative.inner(), |(i, destroyed, supply, stored, ..)| { let destroyed: f64 = *destroyed; let supply: f64 = supply.into(); diff --git a/crates/brk_computer/src/cointime/cap/import.rs b/crates/brk_computer/src/cointime/cap/import.rs index d78610831..fbb30fdd4 100644 --- a/crates/brk_computer/src/cointime/cap/import.rs +++ b/crates/brk_computer/src/cointime/cap/import.rs @@ -3,34 +3,41 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedBlockLast}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let last = || VecBuilderOptions::default().add_last(); - - macro_rules! computed_h { - ($name:expr) => { - ComputedVecsFromHeight::forced_import( - db, - $name, - Source::Compute, - version, - indexes, - last(), - )? - }; - } - Ok(Self { - indexes_to_thermo_cap: computed_h!("thermo_cap"), - indexes_to_investor_cap: computed_h!("investor_cap"), - indexes_to_vaulted_cap: computed_h!("vaulted_cap"), - indexes_to_active_cap: computed_h!("active_cap"), - indexes_to_cointime_cap: computed_h!("cointime_cap"), + indexes_to_thermo_cap: ComputedBlockLast::forced_import( + db, + "thermo_cap", + version, + indexes, + )?, + indexes_to_investor_cap: ComputedBlockLast::forced_import( + db, + "investor_cap", + version, + indexes, + )?, + indexes_to_vaulted_cap: ComputedBlockLast::forced_import( + db, + "vaulted_cap", + version, + indexes, + )?, + indexes_to_active_cap: ComputedBlockLast::forced_import( + db, + "active_cap", + version, + indexes, + )?, + indexes_to_cointime_cap: ComputedBlockLast::forced_import( + db, + "cointime_cap", + version, + indexes, + )?, }) } } diff --git a/crates/brk_computer/src/cointime/cap/vecs.rs b/crates/brk_computer/src/cointime/cap/vecs.rs index aa091e6e8..0a8f9f5e8 100644 --- a/crates/brk_computer/src/cointime/cap/vecs.rs +++ b/crates/brk_computer/src/cointime/cap/vecs.rs @@ -1,13 +1,13 @@ use brk_traversable::Traversable; use brk_types::Dollars; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::ComputedBlockLast; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_thermo_cap: ComputedVecsFromHeight, - pub indexes_to_investor_cap: ComputedVecsFromHeight, - pub indexes_to_vaulted_cap: ComputedVecsFromHeight, - pub indexes_to_active_cap: ComputedVecsFromHeight, - pub indexes_to_cointime_cap: ComputedVecsFromHeight, + pub indexes_to_thermo_cap: ComputedBlockLast, + pub indexes_to_investor_cap: ComputedBlockLast, + pub indexes_to_vaulted_cap: ComputedBlockLast, + pub indexes_to_active_cap: ComputedBlockLast, + pub indexes_to_cointime_cap: ComputedBlockLast, } diff --git a/crates/brk_computer/src/cointime/pricing/compute.rs b/crates/brk_computer/src/cointime/pricing/compute.rs index d98b11832..cf98b1cc8 100644 --- a/crates/brk_computer/src/cointime/pricing/compute.rs +++ b/crates/brk_computer/src/cointime/pricing/compute.rs @@ -19,22 +19,21 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.height_to_supply_value.bitcoin; - let realized_price = distribution + let realized_price = &distribution .utxo_cohorts .all .metrics .realized .u() .indexes_to_realized_price - .height - .u(); + .height; self.indexes_to_vaulted_price .compute_all(indexes, starting_indexes, exit, |vec| { vec.compute_divide( starting_indexes.height, realized_price, - activity.indexes_to_vaultedness.height.u(), + &activity.indexes_to_vaultedness.height, exit, )?; Ok(()) @@ -44,7 +43,7 @@ impl Vecs { price, starting_indexes, exit, - Some(self.indexes_to_vaulted_price.dateindex.unwrap_last()), + Some(&self.indexes_to_vaulted_price.dateindex.0), )?; self.indexes_to_active_price @@ -52,7 +51,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, realized_price, - activity.indexes_to_liveliness.height.u(), + &activity.indexes_to_liveliness.height, exit, )?; Ok(()) @@ -62,7 +61,7 @@ impl Vecs { price, starting_indexes, exit, - Some(self.indexes_to_active_price.dateindex.unwrap_last()), + Some(&self.indexes_to_active_price.dateindex.0), )?; self.indexes_to_true_market_mean.compute_all( @@ -72,7 +71,7 @@ impl Vecs { |vec| { vec.compute_divide( starting_indexes.height, - cap.indexes_to_investor_cap.height.u(), + &cap.indexes_to_investor_cap.height, &supply.indexes_to_active_supply.bitcoin.height, exit, )?; @@ -84,7 +83,7 @@ impl Vecs { price, starting_indexes, exit, - Some(self.indexes_to_true_market_mean.dateindex.unwrap_last()), + Some(&self.indexes_to_true_market_mean.dateindex.0), )?; // cointime_price = cointime_cap / circulating_supply @@ -92,7 +91,7 @@ impl Vecs { .compute_all(indexes, starting_indexes, exit, |vec| { vec.compute_divide( starting_indexes.height, - cap.indexes_to_cointime_cap.height.u(), + &cap.indexes_to_cointime_cap.height, circulating_supply, exit, )?; @@ -103,7 +102,7 @@ impl Vecs { price, starting_indexes, exit, - Some(self.indexes_to_cointime_price.dateindex.unwrap_last()), + Some(&self.indexes_to_cointime_price.dateindex.0), )?; Ok(()) diff --git a/crates/brk_computer/src/cointime/pricing/import.rs b/crates/brk_computer/src/cointime/pricing/import.rs index ef2f4b0eb..283f4a192 100644 --- a/crates/brk_computer/src/cointime/pricing/import.rs +++ b/crates/brk_computer/src/cointime/pricing/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, price, - internal::{ComputedRatioVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::{ComputedRatioVecsDate, ComputedBlockLast}, }; impl Vecs { @@ -15,17 +15,13 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, ) -> Result { - let last = || VecBuilderOptions::default().add_last(); - macro_rules! computed_h { ($name:expr) => { - ComputedVecsFromHeight::forced_import( + ComputedBlockLast::forced_import( db, $name, - Source::Compute, version, indexes, - last(), )? }; } @@ -38,7 +34,7 @@ impl Vecs { macro_rules! ratio_di { ($name:expr, $source:expr) => { - ComputedRatioVecsFromDateIndex::forced_import( + ComputedRatioVecsDate::forced_import( db, $name, Some($source), diff --git a/crates/brk_computer/src/cointime/pricing/vecs.rs b/crates/brk_computer/src/cointime/pricing/vecs.rs index 85d641fc7..b9929dd36 100644 --- a/crates/brk_computer/src/cointime/pricing/vecs.rs +++ b/crates/brk_computer/src/cointime/pricing/vecs.rs @@ -1,16 +1,16 @@ use brk_traversable::Traversable; use brk_types::Dollars; -use crate::internal::{ComputedRatioVecsFromDateIndex, ComputedVecsFromHeight}; +use crate::internal::{ComputedRatioVecsDate, ComputedBlockLast}; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_vaulted_price: ComputedVecsFromHeight, - pub indexes_to_vaulted_price_ratio: ComputedRatioVecsFromDateIndex, - pub indexes_to_active_price: ComputedVecsFromHeight, - pub indexes_to_active_price_ratio: ComputedRatioVecsFromDateIndex, - pub indexes_to_true_market_mean: ComputedVecsFromHeight, - pub indexes_to_true_market_mean_ratio: ComputedRatioVecsFromDateIndex, - pub indexes_to_cointime_price: ComputedVecsFromHeight, - pub indexes_to_cointime_price_ratio: ComputedRatioVecsFromDateIndex, + pub indexes_to_vaulted_price: ComputedBlockLast, + pub indexes_to_vaulted_price_ratio: ComputedRatioVecsDate, + pub indexes_to_active_price: ComputedBlockLast, + pub indexes_to_active_price_ratio: ComputedRatioVecsDate, + pub indexes_to_true_market_mean: ComputedBlockLast, + pub indexes_to_true_market_mean_ratio: ComputedRatioVecsDate, + pub indexes_to_cointime_price: ComputedBlockLast, + pub indexes_to_cointime_price_ratio: ComputedRatioVecsDate, } diff --git a/crates/brk_computer/src/cointime/supply/compute.rs b/crates/brk_computer/src/cointime/supply/compute.rs index 16fad3974..0a87f7250 100644 --- a/crates/brk_computer/src/cointime/supply/compute.rs +++ b/crates/brk_computer/src/cointime/supply/compute.rs @@ -3,7 +3,7 @@ use vecdb::Exit; use super::Vecs; use super::super::activity; -use crate::{distribution, indexes, price, ComputeIndexes, utils::OptionExt}; +use crate::{distribution, indexes, price, ComputeIndexes}; impl Vecs { pub fn compute( @@ -26,7 +26,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, circulating_supply, - activity.indexes_to_vaultedness.height.u(), + &activity.indexes_to_vaultedness.height, exit, )?; Ok(()) @@ -42,7 +42,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, circulating_supply, - activity.indexes_to_liveliness.height.u(), + &activity.indexes_to_liveliness.height, exit, )?; Ok(()) diff --git a/crates/brk_computer/src/cointime/supply/import.rs b/crates/brk_computer/src/cointime/supply/import.rs index f7332fad1..459ef3809 100644 --- a/crates/brk_computer/src/cointime/supply/import.rs +++ b/crates/brk_computer/src/cointime/supply/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedValueVecsFromHeight, Source, VecBuilderOptions}, + internal::ValueBlockLast, }; impl Vecs { @@ -15,25 +15,21 @@ impl Vecs { indexes: &indexes::Vecs, compute_dollars: bool, ) -> Result { - let last = || VecBuilderOptions::default().add_last(); - - macro_rules! value_h { - ($name:expr) => { - ComputedValueVecsFromHeight::forced_import( - db, - $name, - Source::Compute, - version, - last(), - compute_dollars, - indexes, - )? - }; - } - Ok(Self { - indexes_to_vaulted_supply: value_h!("vaulted_supply"), - indexes_to_active_supply: value_h!("active_supply"), + indexes_to_vaulted_supply: ValueBlockLast::forced_import( + db, + "vaulted_supply", + version, + indexes, + compute_dollars, + )?, + indexes_to_active_supply: ValueBlockLast::forced_import( + db, + "active_supply", + version, + indexes, + compute_dollars, + )?, }) } } diff --git a/crates/brk_computer/src/cointime/supply/vecs.rs b/crates/brk_computer/src/cointime/supply/vecs.rs index 83e981ec8..a1bc13b06 100644 --- a/crates/brk_computer/src/cointime/supply/vecs.rs +++ b/crates/brk_computer/src/cointime/supply/vecs.rs @@ -1,9 +1,9 @@ use brk_traversable::Traversable; -use crate::internal::ComputedValueVecsFromHeight; +use crate::internal::ValueBlockLast; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_vaulted_supply: ComputedValueVecsFromHeight, - pub indexes_to_active_supply: ComputedValueVecsFromHeight, + pub indexes_to_vaulted_supply: ValueBlockLast, + pub indexes_to_active_supply: ValueBlockLast, } diff --git a/crates/brk_computer/src/cointime/value/compute.rs b/crates/brk_computer/src/cointime/value/compute.rs index fca533aba..60fc6b264 100644 --- a/crates/brk_computer/src/cointime/value/compute.rs +++ b/crates/brk_computer/src/cointime/value/compute.rs @@ -3,7 +3,7 @@ use vecdb::Exit; use super::super::activity; use super::Vecs; -use crate::{distribution, indexes, price, utils::OptionExt, ComputeIndexes}; +use crate::{distribution, indexes, price, ComputeIndexes}; impl Vecs { pub fn compute( @@ -30,7 +30,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, &price.usd.chainindexes_to_price_close.height, - indexes_to_coinblocks_destroyed.height.u(), + &indexes_to_coinblocks_destroyed.height, exit, )?; Ok(()) @@ -45,7 +45,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, &price.usd.chainindexes_to_price_close.height, - activity.indexes_to_coinblocks_created.height.u(), + &activity.indexes_to_coinblocks_created.height, exit, )?; Ok(()) @@ -60,7 +60,7 @@ impl Vecs { vec.compute_multiply( starting_indexes.height, &price.usd.chainindexes_to_price_close.height, - activity.indexes_to_coinblocks_stored.height.u(), + &activity.indexes_to_coinblocks_stored.height, exit, )?; Ok(()) diff --git a/crates/brk_computer/src/cointime/value/import.rs b/crates/brk_computer/src/cointime/value/import.rs index 4ce53422f..89f7cc907 100644 --- a/crates/brk_computer/src/cointime/value/import.rs +++ b/crates/brk_computer/src/cointime/value/import.rs @@ -3,32 +3,29 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedBlockSumCum}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); - - macro_rules! computed_h { - ($name:expr) => { - ComputedVecsFromHeight::forced_import( - db, - $name, - Source::Compute, - version, - indexes, - sum_cum(), - )? - }; - } - Ok(Self { - indexes_to_cointime_value_destroyed: computed_h!("cointime_value_destroyed"), - indexes_to_cointime_value_created: computed_h!("cointime_value_created"), - indexes_to_cointime_value_stored: computed_h!("cointime_value_stored"), + indexes_to_cointime_value_destroyed: ComputedBlockSumCum::forced_import( + db, + "cointime_value_destroyed", + version, + indexes, + )?, + indexes_to_cointime_value_created: ComputedBlockSumCum::forced_import( + db, + "cointime_value_created", + version, + indexes, + )?, + indexes_to_cointime_value_stored: ComputedBlockSumCum::forced_import( + db, + "cointime_value_stored", + version, + indexes, + )?, }) } } diff --git a/crates/brk_computer/src/cointime/value/vecs.rs b/crates/brk_computer/src/cointime/value/vecs.rs index e906e0796..9d00e3c1d 100644 --- a/crates/brk_computer/src/cointime/value/vecs.rs +++ b/crates/brk_computer/src/cointime/value/vecs.rs @@ -1,11 +1,11 @@ use brk_traversable::Traversable; use brk_types::StoredF64; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::ComputedBlockSumCum; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_cointime_value_destroyed: ComputedVecsFromHeight, - pub indexes_to_cointime_value_created: ComputedVecsFromHeight, - pub indexes_to_cointime_value_stored: ComputedVecsFromHeight, + pub indexes_to_cointime_value_destroyed: ComputedBlockSumCum, + pub indexes_to_cointime_value_created: ComputedBlockSumCum, + pub indexes_to_cointime_value_stored: ComputedBlockSumCum, } diff --git a/crates/brk_computer/src/distribution/address/address_count.rs b/crates/brk_computer/src/distribution/address/address_count.rs index 1dc7d0eef..eaa250f4e 100644 --- a/crates/brk_computer/src/distribution/address/address_count.rs +++ b/crates/brk_computer/src/distribution/address/address_count.rs @@ -2,17 +2,14 @@ use brk_cohort::ByAddressType; use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Height, StoredU64, Version}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use rayon::prelude::*; use vecdb::{ AnyStoredVec, AnyVec, Database, EagerVec, Exit, GenericStoredVec, ImportableVec, IterableCloneableVec, PcoVec, TypedVecIterator, }; -use crate::{ - ComputeIndexes, indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{ComputeIndexes, indexes, internal::DerivedComputedBlockLast}; /// Address count per address type (runtime state). #[derive(Debug, Default, Deref, DerefMut)] @@ -142,11 +139,13 @@ impl AddressTypeToHeightToAddressCount { /// Address count per address type, indexed by various indexes (dateindex, etc.). #[derive(Clone, Deref, DerefMut, Traversable)] -pub struct AddressTypeToIndexesToAddressCount(ByAddressType>); +pub struct AddressTypeToIndexesToAddressCount(ByAddressType>); -impl From>> for AddressTypeToIndexesToAddressCount { +impl From>> + for AddressTypeToIndexesToAddressCount +{ #[inline] - fn from(value: ByAddressType>) -> Self { + fn from(value: ByAddressType>) -> Self { Self(value) } } @@ -160,17 +159,16 @@ impl AddressTypeToIndexesToAddressCount { sources: &AddressTypeToHeightToAddressCount, ) -> Result { Ok(Self::from(ByAddressType::< - ComputedVecsFromHeight, + DerivedComputedBlockLast, >::try_zip_with_name( sources, |type_name, source| { - ComputedVecsFromHeight::forced_import( + DerivedComputedBlockLast::forced_import( db, &format!("{type_name}_{name}"), - Source::Vec(source.boxed_clone()), + source.boxed_clone(), version, indexes, - VecBuilderOptions::default().add_last(), ) }, )?)) @@ -183,53 +181,53 @@ impl AddressTypeToIndexesToAddressCount { exit: &Exit, addresstype_to_height_to_addresscount: &AddressTypeToHeightToAddressCount, ) -> Result<()> { - self.p2pk65.compute_rest( + self.p2pk65.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2pk65, exit, - Some(&addresstype_to_height_to_addresscount.p2pk65), )?; - self.p2pk33.compute_rest( + self.p2pk33.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2pk33, exit, - Some(&addresstype_to_height_to_addresscount.p2pk33), )?; - self.p2pkh.compute_rest( + self.p2pkh.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2pkh, exit, - Some(&addresstype_to_height_to_addresscount.p2pkh), )?; - self.p2sh.compute_rest( + self.p2sh.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2sh, exit, - Some(&addresstype_to_height_to_addresscount.p2sh), )?; - self.p2wpkh.compute_rest( + self.p2wpkh.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2wpkh, exit, - Some(&addresstype_to_height_to_addresscount.p2wpkh), )?; - self.p2wsh.compute_rest( + self.p2wsh.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2wsh, exit, - Some(&addresstype_to_height_to_addresscount.p2wsh), )?; - self.p2tr.compute_rest( + self.p2tr.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2tr, exit, - Some(&addresstype_to_height_to_addresscount.p2tr), )?; - self.p2a.compute_rest( + self.p2a.derive_from( indexes, starting_indexes, + &addresstype_to_height_to_addresscount.p2a, exit, - Some(&addresstype_to_height_to_addresscount.p2a), )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/address/type_map/height_vec.rs b/crates/brk_computer/src/distribution/address/type_map/height_vec.rs index bef053b4b..245387ccf 100644 --- a/crates/brk_computer/src/distribution/address/type_map/height_vec.rs +++ b/crates/brk_computer/src/distribution/address/type_map/height_vec.rs @@ -1,5 +1,5 @@ use brk_types::Height; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use rustc_hash::FxHashMap; use super::vec::AddressTypeToVec; diff --git a/crates/brk_computer/src/distribution/address/type_map/index_map.rs b/crates/brk_computer/src/distribution/address/type_map/index_map.rs index ff6a8f32d..d88dab378 100644 --- a/crates/brk_computer/src/distribution/address/type_map/index_map.rs +++ b/crates/brk_computer/src/distribution/address/type_map/index_map.rs @@ -2,7 +2,7 @@ use std::{collections::hash_map::Entry, mem}; use brk_cohort::ByAddressType; use brk_types::{OutputType, TypeIndex}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use rustc_hash::FxHashMap; use smallvec::{Array, SmallVec}; diff --git a/crates/brk_computer/src/distribution/address/type_map/vec.rs b/crates/brk_computer/src/distribution/address/type_map/vec.rs index 44d9632a6..28e0c10f8 100644 --- a/crates/brk_computer/src/distribution/address/type_map/vec.rs +++ b/crates/brk_computer/src/distribution/address/type_map/vec.rs @@ -1,5 +1,5 @@ use brk_cohort::ByAddressType; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; /// A vector for each address type. #[derive(Debug, Deref, DerefMut)] diff --git a/crates/brk_computer/src/distribution/cohorts/address/groups.rs b/crates/brk_computer/src/distribution/cohorts/address/groups.rs index 9fcbfba64..f36b890d9 100644 --- a/crates/brk_computer/src/distribution/cohorts/address/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/address/groups.rs @@ -6,7 +6,7 @@ use brk_cohort::{ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{DateIndex, Dollars, Height, Version}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use rayon::prelude::*; use vecdb::{AnyStoredVec, Database, Exit, IterableVec}; diff --git a/crates/brk_computer/src/distribution/cohorts/address/vecs.rs b/crates/brk_computer/src/distribution/cohorts/address/vecs.rs index f3ff7dbc1..f8709155e 100644 --- a/crates/brk_computer/src/distribution/cohorts/address/vecs.rs +++ b/crates/brk_computer/src/distribution/cohorts/address/vecs.rs @@ -14,7 +14,7 @@ use crate::{ ComputeIndexes, distribution::state::AddressCohortState, indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::DerivedComputedBlockLast, price, }; @@ -42,7 +42,7 @@ pub struct AddressCohortVecs { pub height_to_addr_count: EagerVec>, /// Address count indexed by various dimensions - pub indexes_to_addr_count: ComputedVecsFromHeight, + pub indexes_to_addr_count: DerivedComputedBlockLast, } impl AddressCohortVecs { @@ -86,13 +86,12 @@ impl AddressCohortVecs { metrics: CohortMetrics::forced_import(&cfg, all_supply)?, - indexes_to_addr_count: ComputedVecsFromHeight::forced_import( + indexes_to_addr_count: DerivedComputedBlockLast::forced_import( db, &cfg.name("addr_count"), - Source::Vec(height_to_addr_count.boxed_clone()), + height_to_addr_count.boxed_clone(), version + VERSION, indexes, - VecBuilderOptions::default().add_last(), )?, height_to_addr_count, }) @@ -248,11 +247,11 @@ impl DynCohortVecs for AddressCohortVecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_addr_count.compute_rest( + self.indexes_to_addr_count.derive_from( indexes, starting_indexes, + &self.height_to_addr_count, exit, - Some(&self.height_to_addr_count), )?; self.metrics .compute_rest_part1(indexes, price, starting_indexes, exit)?; diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index 63e42ae0c..71bcf4e79 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -7,7 +7,7 @@ use brk_cohort::{ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{DateIndex, Dollars, Height, Sats, Version}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use rayon::prelude::*; use vecdb::{AnyStoredVec, Database, Exit, IterableVec}; diff --git a/crates/brk_computer/src/distribution/compute/block_loop.rs b/crates/brk_computer/src/distribution/compute/block_loop.rs index ec736b43c..85c3c0c77 100644 --- a/crates/brk_computer/src/distribution/compute/block_loop.rs +++ b/crates/brk_computer/src/distribution/compute/block_loop.rs @@ -20,7 +20,6 @@ use crate::{ state::{BlockState, Transacted}, }, inputs, outputs, - utils::OptionExt, }; use super::{ @@ -63,10 +62,10 @@ pub fn process_blocks( let height_to_first_txoutindex = &indexer.vecs.txout.height_to_first_txoutindex; let height_to_first_txinindex = &indexer.vecs.txin.height_to_first_txinindex; - // From transactions and inputs/outputs (via .height.u() or .height.unwrap_sum() patterns): - let height_to_tx_count = transactions.count.indexes_to_tx_count.height.u(); - let height_to_output_count = outputs.count.indexes_to_count.height.unwrap_sum(); - let height_to_input_count = inputs.count.indexes_to_count.height.unwrap_sum(); + // From transactions and inputs/outputs (via .height or .height.sum_cum.sum patterns): + let height_to_tx_count = &transactions.count.indexes_to_tx_count.height; + let height_to_output_count = &outputs.count.indexes_to_count.height.sum_cum.sum.0; + let height_to_input_count = &inputs.count.indexes_to_count.height.sum_cum.sum.0; // From blocks: let height_to_timestamp = &blocks.time.height_to_timestamp_fixed; let height_to_date = &blocks.time.height_to_date_fixed; @@ -77,7 +76,7 @@ pub fn process_blocks( // From price (optional): let height_to_price = price.map(|p| &p.usd.chainindexes_to_price_close.height); - let dateindex_to_price = price.map(|p| p.usd.timeindexes_to_price_close.dateindex.u()); + let dateindex_to_price = price.map(|p| &p.usd.timeindexes_to_price_close.dateindex); // Access pre-computed vectors from context for thread-safe access let height_to_price_vec = &ctx.height_to_price; diff --git a/crates/brk_computer/src/distribution/metrics/activity.rs b/crates/brk_computer/src/distribution/metrics/activity.rs index 9f659e2d4..b6487cea7 100644 --- a/crates/brk_computer/src/distribution/metrics/activity.rs +++ b/crates/brk_computer/src/distribution/metrics/activity.rs @@ -9,8 +9,7 @@ use vecdb::{ use crate::{ ComputeIndexes, indexes, - internal::{ComputedValueVecsFromHeight, ComputedVecsFromHeight, Source, VecBuilderOptions}, - price, + internal::{ComputedBlockSumCum, DerivedValueBlockSumCum}, }; use super::ImportConfig; @@ -21,8 +20,8 @@ pub struct ActivityMetrics { /// Total satoshis sent at each height pub height_to_sent: EagerVec>, - /// Sent amounts indexed by various dimensions - pub indexes_to_sent: ComputedValueVecsFromHeight, + /// Sent amounts indexed by various dimensions (derives from height_to_sent) + pub indexes_to_sent: DerivedValueBlockSumCum, /// Satoshi-blocks destroyed (supply * blocks_old when spent) pub height_to_satblocks_destroyed: EagerVec>, @@ -31,28 +30,24 @@ pub struct ActivityMetrics { pub height_to_satdays_destroyed: EagerVec>, /// Coin-blocks destroyed (in BTC rather than sats) - pub indexes_to_coinblocks_destroyed: ComputedVecsFromHeight, + pub indexes_to_coinblocks_destroyed: ComputedBlockSumCum, /// Coin-days destroyed (in BTC rather than sats) - pub indexes_to_coindays_destroyed: ComputedVecsFromHeight, + pub indexes_to_coindays_destroyed: ComputedBlockSumCum, } impl ActivityMetrics { /// Import activity metrics from database. pub fn forced_import(cfg: &ImportConfig) -> Result { - let compute_dollars = cfg.compute_dollars(); - let sum_cum = VecBuilderOptions::default().add_sum().add_cumulative(); - let height_to_sent: EagerVec> = EagerVec::forced_import(cfg.db, &cfg.name("sent"), cfg.version)?; - let indexes_to_sent = ComputedValueVecsFromHeight::forced_import( + let indexes_to_sent = DerivedValueBlockSumCum::forced_import( cfg.db, &cfg.name("sent"), - Source::Vec(height_to_sent.boxed_clone()), cfg.version, - sum_cum, - compute_dollars, cfg.indexes, + height_to_sent.boxed_clone(), + cfg.price, )?; Ok(Self { @@ -71,22 +66,18 @@ impl ActivityMetrics { cfg.version, )?, - indexes_to_coinblocks_destroyed: ComputedVecsFromHeight::forced_import( + indexes_to_coinblocks_destroyed: ComputedBlockSumCum::forced_import( cfg.db, &cfg.name("coinblocks_destroyed"), - Source::Compute, cfg.version, cfg.indexes, - sum_cum, )?, - indexes_to_coindays_destroyed: ComputedVecsFromHeight::forced_import( + indexes_to_coindays_destroyed: ComputedBlockSumCum::forced_import( cfg.db, &cfg.name("coindays_destroyed"), - Source::Compute, cfg.version, cfg.indexes, - sum_cum, )?, }) } @@ -174,16 +165,14 @@ impl ActivityMetrics { pub fn compute_rest_part1( &mut self, indexes: &indexes::Vecs, - price: Option<&price::Vecs>, starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_sent.compute_rest( + self.indexes_to_sent.derive_from( indexes, - price, starting_indexes, + &self.height_to_sent, exit, - Some(&self.height_to_sent), )?; self.indexes_to_coinblocks_destroyed diff --git a/crates/brk_computer/src/distribution/metrics/cost_basis.rs b/crates/brk_computer/src/distribution/metrics/cost_basis.rs index 63f40e11e..454be7bb3 100644 --- a/crates/brk_computer/src/distribution/metrics/cost_basis.rs +++ b/crates/brk_computer/src/distribution/metrics/cost_basis.rs @@ -10,7 +10,7 @@ use vecdb::{ use crate::{ ComputeIndexes, distribution::state::CohortState, - internal::{ComputedVecsFromHeight, CostBasisPercentiles, Source, VecBuilderOptions}, + internal::{CostBasisPercentiles, DerivedComputedBlockLast}, }; use super::ImportConfig; @@ -20,11 +20,11 @@ use super::ImportConfig; pub struct CostBasisMetrics { /// Minimum cost basis for any UTXO at this height pub height_to_min_cost_basis: EagerVec>, - pub indexes_to_min_cost_basis: ComputedVecsFromHeight, + pub indexes_to_min_cost_basis: DerivedComputedBlockLast, /// Maximum cost basis for any UTXO at this height pub height_to_max_cost_basis: EagerVec>, - pub indexes_to_max_cost_basis: ComputedVecsFromHeight, + pub indexes_to_max_cost_basis: DerivedComputedBlockLast, /// Cost basis distribution percentiles (median, quartiles, etc.) pub percentiles: Option, @@ -34,7 +34,6 @@ impl CostBasisMetrics { /// Import cost basis metrics from database. pub fn forced_import(cfg: &ImportConfig) -> Result { let extended = cfg.extended(); - let last = VecBuilderOptions::default().add_last(); let height_to_min_cost_basis = EagerVec::forced_import(cfg.db, &cfg.name("min_cost_basis"), cfg.version)?; @@ -43,21 +42,19 @@ impl CostBasisMetrics { EagerVec::forced_import(cfg.db, &cfg.name("max_cost_basis"), cfg.version)?; Ok(Self { - indexes_to_min_cost_basis: ComputedVecsFromHeight::forced_import( + indexes_to_min_cost_basis: DerivedComputedBlockLast::forced_import( cfg.db, &cfg.name("min_cost_basis"), - Source::Vec(height_to_min_cost_basis.boxed_clone()), + height_to_min_cost_basis.boxed_clone(), cfg.version, cfg.indexes, - last, )?, - indexes_to_max_cost_basis: ComputedVecsFromHeight::forced_import( + indexes_to_max_cost_basis: DerivedComputedBlockLast::forced_import( cfg.db, &cfg.name("max_cost_basis"), - Source::Vec(height_to_max_cost_basis.boxed_clone()), + height_to_max_cost_basis.boxed_clone(), cfg.version, cfg.indexes, - last, )?, height_to_min_cost_basis, height_to_max_cost_basis, @@ -145,8 +142,7 @@ impl CostBasisMetrics { .vecs .iter_mut() .flatten() - .filter_map(|v| v.dateindex.as_mut()) - .map(|v| v as &mut dyn AnyStoredVec), + .map(|v| &mut v.dateindex as &mut dyn AnyStoredVec), ); } vecs.into_par_iter() @@ -193,18 +189,18 @@ impl CostBasisMetrics { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_min_cost_basis.compute_rest( + self.indexes_to_min_cost_basis.derive_from( indexes, starting_indexes, + &self.height_to_min_cost_basis, exit, - Some(&self.height_to_min_cost_basis), )?; - self.indexes_to_max_cost_basis.compute_rest( + self.indexes_to_max_cost_basis.derive_from( indexes, starting_indexes, + &self.height_to_max_cost_basis, exit, - Some(&self.height_to_max_cost_basis), )?; Ok(()) diff --git a/crates/brk_computer/src/distribution/metrics/mod.rs b/crates/brk_computer/src/distribution/metrics/mod.rs index 84f13afba..825ff1b10 100644 --- a/crates/brk_computer/src/distribution/metrics/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/mod.rs @@ -295,7 +295,7 @@ impl CohortMetrics { self.supply .compute_rest_part1(indexes, price, starting_indexes, exit)?; self.activity - .compute_rest_part1(indexes, price, starting_indexes, exit)?; + .compute_rest_part1(indexes, starting_indexes, exit)?; if let Some(realized) = self.realized.as_mut() { realized.compute_rest_part1(indexes, starting_indexes, exit)?; diff --git a/crates/brk_computer/src/distribution/metrics/realized.rs b/crates/brk_computer/src/distribution/metrics/realized.rs index 82a6f9e5c..d088f86d4 100644 --- a/crates/brk_computer/src/distribution/metrics/realized.rs +++ b/crates/brk_computer/src/distribution/metrics/realized.rs @@ -12,12 +12,12 @@ use crate::{ distribution::state::RealizedState, indexes, internal::{ - ComputedRatioVecsFromDateIndex, ComputedVecsFromDateIndex, ComputedVecsFromHeight, - DollarsMinus, LazyVecsFrom2FromHeight, LazyVecsFromDateIndex, LazyVecsFromHeight, - PercentageDollarsF32, Source, StoredF32Identity, VecBuilderOptions, + BinaryBlockSum, BinaryBlockSumCumLast, ComputedBlockLast, ComputedBlockSum, + ComputedBlockSumCum, ComputedDateLast, ComputedRatioVecsDate, DerivedComputedBlockLast, + DerivedComputedBlockSum, DerivedComputedBlockSumCum, DollarsMinus, LazyBlockSum, + LazyBlockSumCum, LazyDateLast, PercentageDollarsF32, StoredF32Identity, }, price, - utils::OptionExt, }; use super::ImportConfig; @@ -27,48 +27,48 @@ use super::ImportConfig; pub struct RealizedMetrics { // === Realized Cap === pub height_to_realized_cap: EagerVec>, - pub indexes_to_realized_cap: ComputedVecsFromHeight, - pub indexes_to_realized_price: ComputedVecsFromHeight, - pub indexes_to_realized_price_extra: ComputedRatioVecsFromDateIndex, - pub indexes_to_realized_cap_rel_to_own_market_cap: Option>, - pub indexes_to_realized_cap_30d_delta: ComputedVecsFromDateIndex, + pub indexes_to_realized_cap: DerivedComputedBlockLast, + pub indexes_to_realized_price: ComputedBlockLast, + pub indexes_to_realized_price_extra: ComputedRatioVecsDate, + pub indexes_to_realized_cap_rel_to_own_market_cap: Option>, + pub indexes_to_realized_cap_30d_delta: ComputedDateLast, // === MVRV (Market Value to Realized Value) === // Proxy for indexes_to_realized_price_extra.ratio (close / realized_price = market_cap / realized_cap) - pub indexes_to_mvrv: LazyVecsFromDateIndex, + pub indexes_to_mvrv: LazyDateLast, // === Realized Profit/Loss === pub height_to_realized_profit: EagerVec>, - pub indexes_to_realized_profit: ComputedVecsFromHeight, + pub indexes_to_realized_profit: DerivedComputedBlockSumCum, pub height_to_realized_loss: EagerVec>, - pub indexes_to_realized_loss: ComputedVecsFromHeight, - pub indexes_to_neg_realized_loss: LazyVecsFromHeight, - pub indexes_to_net_realized_pnl: ComputedVecsFromHeight, - pub indexes_to_realized_value: ComputedVecsFromHeight, + pub indexes_to_realized_loss: DerivedComputedBlockSumCum, + pub indexes_to_neg_realized_loss: LazyBlockSumCum, + pub indexes_to_net_realized_pnl: ComputedBlockSumCum, + pub indexes_to_realized_value: ComputedBlockSum, // === Realized vs Realized Cap Ratios (lazy) === pub indexes_to_realized_profit_rel_to_realized_cap: - LazyVecsFrom2FromHeight, + BinaryBlockSumCumLast, pub indexes_to_realized_loss_rel_to_realized_cap: - LazyVecsFrom2FromHeight, + BinaryBlockSumCumLast, pub indexes_to_net_realized_pnl_rel_to_realized_cap: - LazyVecsFrom2FromHeight, + BinaryBlockSumCumLast, // === Total Realized PnL === - pub indexes_to_total_realized_pnl: LazyVecsFromHeight, + pub indexes_to_total_realized_pnl: LazyBlockSum, pub dateindex_to_realized_profit_to_loss_ratio: Option>>, // === Value Created/Destroyed === pub height_to_value_created: EagerVec>, - pub indexes_to_value_created: ComputedVecsFromHeight, + #[traversable(rename = "value_created_sum")] + pub indexes_to_value_created: DerivedComputedBlockSum, pub height_to_value_destroyed: EagerVec>, - pub indexes_to_value_destroyed: ComputedVecsFromHeight, + #[traversable(rename = "value_destroyed_sum")] + pub indexes_to_value_destroyed: DerivedComputedBlockSum, // === Adjusted Value (lazy: cohort - up_to_1h) === - pub indexes_to_adjusted_value_created: - Option>, - pub indexes_to_adjusted_value_destroyed: - Option>, + pub indexes_to_adjusted_value_created: Option>, + pub indexes_to_adjusted_value_destroyed: Option>, // === SOPR (Spent Output Profit Ratio) === pub dateindex_to_sopr: EagerVec>, @@ -84,11 +84,11 @@ pub struct RealizedMetrics { pub dateindex_to_sell_side_risk_ratio_30d_ema: EagerVec>, // === Net Realized PnL Deltas === - pub indexes_to_net_realized_pnl_cumulative_30d_delta: ComputedVecsFromDateIndex, + pub indexes_to_net_realized_pnl_cumulative_30d_delta: ComputedDateLast, pub indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: - ComputedVecsFromDateIndex, + ComputedDateLast, pub indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: - ComputedVecsFromDateIndex, + ComputedDateLast, } impl RealizedMetrics { @@ -98,23 +98,19 @@ impl RealizedMetrics { let v3 = Version::new(3); let extended = cfg.extended(); let compute_adjusted = cfg.compute_adjusted(); - let last = VecBuilderOptions::default().add_last(); - let sum = VecBuilderOptions::default().add_sum(); - let sum_cum = VecBuilderOptions::default().add_sum().add_cumulative(); let height_to_realized_loss: EagerVec> = EagerVec::forced_import(cfg.db, &cfg.name("realized_loss"), cfg.version)?; - let indexes_to_realized_loss = ComputedVecsFromHeight::forced_import( + let indexes_to_realized_loss = DerivedComputedBlockSumCum::forced_import( cfg.db, &cfg.name("realized_loss"), - Source::Vec(height_to_realized_loss.boxed_clone()), + height_to_realized_loss.boxed_clone(), cfg.version, cfg.indexes, - sum_cum, )?; - let indexes_to_neg_realized_loss = LazyVecsFromHeight::from_computed::( + let indexes_to_neg_realized_loss = LazyBlockSumCum::from_derived::( &cfg.name("neg_realized_loss"), cfg.version + v1, height_to_realized_loss.boxed_clone(), @@ -122,24 +118,18 @@ impl RealizedMetrics { ); // realized_value is the source for total_realized_pnl (they're identical) - let indexes_to_realized_value = ComputedVecsFromHeight::forced_import( + let indexes_to_realized_value = ComputedBlockSum::forced_import( cfg.db, &cfg.name("realized_value"), - Source::Compute, cfg.version, cfg.indexes, - sum, )?; // total_realized_pnl is a lazy alias to realized_value - let indexes_to_total_realized_pnl = LazyVecsFromHeight::from_computed::( + let indexes_to_total_realized_pnl = LazyBlockSum::from_computed::( &cfg.name("total_realized_pnl"), cfg.version + v1, - indexes_to_realized_value - .height - .as_ref() - .unwrap() - .boxed_clone(), + indexes_to_realized_value.height.boxed_clone(), &indexes_to_realized_value, ); @@ -147,39 +137,35 @@ impl RealizedMetrics { let height_to_realized_cap: EagerVec> = EagerVec::forced_import(cfg.db, &cfg.name("realized_cap"), cfg.version)?; - let indexes_to_realized_cap = ComputedVecsFromHeight::forced_import( + let indexes_to_realized_cap = DerivedComputedBlockLast::forced_import( cfg.db, &cfg.name("realized_cap"), - Source::Vec(height_to_realized_cap.boxed_clone()), + height_to_realized_cap.boxed_clone(), cfg.version, cfg.indexes, - last, )?; let height_to_realized_profit: EagerVec> = EagerVec::forced_import(cfg.db, &cfg.name("realized_profit"), cfg.version)?; - let indexes_to_realized_profit = ComputedVecsFromHeight::forced_import( + let indexes_to_realized_profit = DerivedComputedBlockSumCum::forced_import( cfg.db, &cfg.name("realized_profit"), - Source::Vec(height_to_realized_profit.boxed_clone()), + height_to_realized_profit.boxed_clone(), cfg.version, cfg.indexes, - sum_cum, )?; - let indexes_to_net_realized_pnl = ComputedVecsFromHeight::forced_import( + let indexes_to_net_realized_pnl = ComputedBlockSumCum::forced_import( cfg.db, &cfg.name("net_realized_pnl"), - Source::Compute, cfg.version, cfg.indexes, - sum_cum, )?; // Construct lazy ratio vecs (before struct assignment to satisfy borrow checker) let indexes_to_realized_profit_rel_to_realized_cap = - LazyVecsFrom2FromHeight::from_computed::( + BinaryBlockSumCumLast::from_derived::( &cfg.name("realized_profit_rel_to_realized_cap"), cfg.version + v1, height_to_realized_profit.boxed_clone(), @@ -189,7 +175,7 @@ impl RealizedMetrics { ); let indexes_to_realized_loss_rel_to_realized_cap = - LazyVecsFrom2FromHeight::from_computed::( + BinaryBlockSumCumLast::from_derived::( &cfg.name("realized_loss_rel_to_realized_cap"), cfg.version + v1, height_to_realized_loss.boxed_clone(), @@ -199,26 +185,20 @@ impl RealizedMetrics { ); let indexes_to_net_realized_pnl_rel_to_realized_cap = - LazyVecsFrom2FromHeight::from_computed::( + BinaryBlockSumCumLast::from_computed_derived::( &cfg.name("net_realized_pnl_rel_to_realized_cap"), cfg.version + v1, - indexes_to_net_realized_pnl - .height - .as_ref() - .unwrap() - .boxed_clone(), + indexes_to_net_realized_pnl.height.boxed_clone(), height_to_realized_cap.boxed_clone(), &indexes_to_net_realized_pnl, &indexes_to_realized_cap, ); - let indexes_to_realized_price = ComputedVecsFromHeight::forced_import( + let indexes_to_realized_price = ComputedBlockLast::forced_import( cfg.db, &cfg.name("realized_price"), - Source::Compute, cfg.version + v1, cfg.indexes, - last, )?; let height_to_value_created = @@ -226,28 +206,26 @@ impl RealizedMetrics { let height_to_value_destroyed = EagerVec::forced_import(cfg.db, &cfg.name("value_destroyed"), cfg.version)?; - let indexes_to_value_created = ComputedVecsFromHeight::forced_import( + let indexes_to_value_created = DerivedComputedBlockSum::forced_import( cfg.db, &cfg.name("value_created"), - Source::Vec(height_to_value_created.boxed_clone()), + height_to_value_created.boxed_clone(), cfg.version, cfg.indexes, - sum, )?; - let indexes_to_value_destroyed = ComputedVecsFromHeight::forced_import( + let indexes_to_value_destroyed = DerivedComputedBlockSum::forced_import( cfg.db, &cfg.name("value_destroyed"), - Source::Vec(height_to_value_destroyed.boxed_clone()), + height_to_value_destroyed.boxed_clone(), cfg.version, cfg.indexes, - sum, )?; // Create lazy adjusted vecs if compute_adjusted and up_to_1h is available - let indexes_to_adjusted_value_created = (compute_adjusted && cfg.up_to_1h_realized.is_some()) - .then(|| { + let indexes_to_adjusted_value_created = + (compute_adjusted && cfg.up_to_1h_realized.is_some()).then(|| { let up_to_1h = cfg.up_to_1h_realized.unwrap(); - LazyVecsFrom2FromHeight::from_computed::( + BinaryBlockSum::from_derived::( &cfg.name("adjusted_value_created"), cfg.version, height_to_value_created.boxed_clone(), @@ -259,7 +237,7 @@ impl RealizedMetrics { let indexes_to_adjusted_value_destroyed = (compute_adjusted && cfg.up_to_1h_realized.is_some()).then(|| { let up_to_1h = cfg.up_to_1h_realized.unwrap(); - LazyVecsFrom2FromHeight::from_computed::( + BinaryBlockSum::from_derived::( &cfg.name("adjusted_value_destroyed"), cfg.version, height_to_value_destroyed.boxed_clone(), @@ -270,7 +248,7 @@ impl RealizedMetrics { }); // Create realized_price_extra first so we can reference its ratio for MVRV proxy - let indexes_to_realized_price_extra = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_realized_price_extra = ComputedRatioVecsDate::forced_import( cfg.db, &cfg.name("realized_price"), Some(&indexes_to_realized_price), @@ -282,14 +260,9 @@ impl RealizedMetrics { // MVRV is a lazy proxy for realized_price_extra.ratio // ratio = close / realized_price = market_cap / realized_cap = MVRV - let indexes_to_mvrv = LazyVecsFromDateIndex::from_computed::( + let indexes_to_mvrv = LazyDateLast::from_source::( &cfg.name("mvrv"), cfg.version, - indexes_to_realized_price_extra - .ratio - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), &indexes_to_realized_price_extra.ratio, ); @@ -303,23 +276,19 @@ impl RealizedMetrics { indexes_to_mvrv, indexes_to_realized_cap_rel_to_own_market_cap: extended .then(|| { - ComputedVecsFromHeight::forced_import( + ComputedBlockLast::forced_import( cfg.db, &cfg.name("realized_cap_rel_to_own_market_cap"), - Source::Compute, cfg.version, cfg.indexes, - last, ) }) .transpose()?, - indexes_to_realized_cap_30d_delta: ComputedVecsFromDateIndex::forced_import( + indexes_to_realized_cap_30d_delta: ComputedDateLast::forced_import( cfg.db, &cfg.name("realized_cap_30d_delta"), - Source::Compute, cfg.version, cfg.indexes, - last, )?, // === Realized Profit/Loss === @@ -416,32 +385,25 @@ impl RealizedMetrics { )?, // === Net Realized PnL Deltas === - indexes_to_net_realized_pnl_cumulative_30d_delta: - ComputedVecsFromDateIndex::forced_import( - cfg.db, - &cfg.name("net_realized_pnl_cumulative_30d_delta"), - Source::Compute, - cfg.version + v3, - cfg.indexes, - last, - )?, + indexes_to_net_realized_pnl_cumulative_30d_delta: ComputedDateLast::forced_import( + cfg.db, + &cfg.name("net_realized_pnl_cumulative_30d_delta"), + cfg.version + v3, + cfg.indexes, + )?, indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: - ComputedVecsFromDateIndex::forced_import( + ComputedDateLast::forced_import( cfg.db, &cfg.name("net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap"), - Source::Compute, cfg.version + v3, cfg.indexes, - last, )?, indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: - ComputedVecsFromDateIndex::forced_import( + ComputedDateLast::forced_import( cfg.db, &cfg.name("net_realized_pnl_cumulative_30d_delta_rel_to_market_cap"), - Source::Compute, cfg.version + v3, cfg.indexes, - last, )?, }) } @@ -558,25 +520,25 @@ impl RealizedMetrics { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_realized_cap.compute_rest( + self.indexes_to_realized_cap.derive_from( indexes, starting_indexes, + &self.height_to_realized_cap, exit, - Some(&self.height_to_realized_cap), )?; - self.indexes_to_realized_profit.compute_rest( + self.indexes_to_realized_profit.derive_from( indexes, starting_indexes, + &self.height_to_realized_profit, exit, - Some(&self.height_to_realized_profit), )?; - self.indexes_to_realized_loss.compute_rest( + self.indexes_to_realized_loss.derive_from( indexes, starting_indexes, + &self.height_to_realized_loss, exit, - Some(&self.height_to_realized_loss), )?; // net_realized_pnl = profit - loss @@ -605,18 +567,18 @@ impl RealizedMetrics { Ok(()) })?; - self.indexes_to_value_created.compute_rest( + self.indexes_to_value_created.derive_from( indexes, starting_indexes, + &self.height_to_value_created, exit, - Some(&self.height_to_value_created), )?; - self.indexes_to_value_destroyed.compute_rest( + self.indexes_to_value_destroyed.derive_from( indexes, starting_indexes, + &self.height_to_value_destroyed, exit, - Some(&self.height_to_value_destroyed), )?; Ok(()) @@ -651,7 +613,7 @@ impl RealizedMetrics { price, starting_indexes, exit, - Some(self.indexes_to_realized_price.dateindex.unwrap_last()), + Some(&self.indexes_to_realized_price.dateindex.0), )?; } @@ -660,7 +622,7 @@ impl RealizedMetrics { .compute_all(starting_indexes, exit, |vec| { vec.compute_change( starting_indexes.dateindex, - self.indexes_to_realized_cap.dateindex.unwrap_last(), + &self.indexes_to_realized_cap.dateindex.0, 30, exit, )?; @@ -670,8 +632,8 @@ impl RealizedMetrics { // SOPR = value_created / value_destroyed self.dateindex_to_sopr.compute_divide( starting_indexes.dateindex, - self.indexes_to_value_created.dateindex.unwrap_sum(), - self.indexes_to_value_destroyed.dateindex.unwrap_sum(), + &self.indexes_to_value_created.dateindex.0, + &self.indexes_to_value_destroyed.dateindex.0, exit, )?; @@ -692,17 +654,13 @@ impl RealizedMetrics { // Optional: adjusted SOPR (lazy: cohort - up_to_1h) if let (Some(adjusted_sopr), Some(adj_created), Some(adj_destroyed)) = ( self.dateindex_to_adjusted_sopr.as_mut(), - self.indexes_to_adjusted_value_created - .as_ref() - .and_then(|v| v.dateindex.sum.as_ref()), - self.indexes_to_adjusted_value_destroyed - .as_ref() - .and_then(|v| v.dateindex.sum.as_ref()), + self.indexes_to_adjusted_value_created.as_ref(), + self.indexes_to_adjusted_value_destroyed.as_ref(), ) { adjusted_sopr.compute_divide( starting_indexes.dateindex, - adj_created.as_ref(), - adj_destroyed.as_ref(), + &*adj_created.dateindex, + &*adj_destroyed.dateindex, exit, )?; @@ -728,8 +686,8 @@ impl RealizedMetrics { // sell_side_risk_ratio = realized_value / realized_cap self.dateindex_to_sell_side_risk_ratio.compute_percentage( starting_indexes.dateindex, - self.indexes_to_realized_value.dateindex.unwrap_sum(), - self.indexes_to_realized_cap.dateindex.unwrap_last(), + &self.indexes_to_realized_value.dateindex.0, + &self.indexes_to_realized_cap.dateindex.0, exit, )?; @@ -752,9 +710,7 @@ impl RealizedMetrics { .compute_all(starting_indexes, exit, |vec| { vec.compute_change( starting_indexes.dateindex, - self.indexes_to_net_realized_pnl - .dateindex - .unwrap_cumulative(), + &self.indexes_to_net_realized_pnl.dateindex.cumulative.0, 30, exit, )?; @@ -766,10 +722,10 @@ impl RealizedMetrics { .compute_all(starting_indexes, exit, |vec| { vec.compute_percentage( starting_indexes.dateindex, - self.indexes_to_net_realized_pnl_cumulative_30d_delta - .dateindex - .u(), - self.indexes_to_realized_cap.dateindex.unwrap_last(), + &self + .indexes_to_net_realized_pnl_cumulative_30d_delta + .dateindex, + &self.indexes_to_realized_cap.dateindex.0, exit, )?; Ok(()) @@ -781,9 +737,9 @@ impl RealizedMetrics { .compute_all(starting_indexes, exit, |vec| { vec.compute_percentage( starting_indexes.dateindex, - self.indexes_to_net_realized_pnl_cumulative_30d_delta - .dateindex - .u(), + &self + .indexes_to_net_realized_pnl_cumulative_30d_delta + .dateindex, dateindex_to_market_cap, exit, )?; @@ -811,8 +767,8 @@ impl RealizedMetrics { if let Some(ratio) = self.dateindex_to_realized_profit_to_loss_ratio.as_mut() { ratio.compute_divide( starting_indexes.dateindex, - self.indexes_to_realized_profit.dateindex.unwrap_sum(), - self.indexes_to_realized_loss.dateindex.unwrap_sum(), + &self.indexes_to_realized_profit.dateindex.sum.0, + &self.indexes_to_realized_loss.dateindex.sum.0, exit, )?; } diff --git a/crates/brk_computer/src/distribution/metrics/relative.rs b/crates/brk_computer/src/distribution/metrics/relative.rs index 5cac95da4..90c9b0a18 100644 --- a/crates/brk_computer/src/distribution/metrics/relative.rs +++ b/crates/brk_computer/src/distribution/metrics/relative.rs @@ -4,7 +4,7 @@ use brk_types::{Bitcoin, Dollars, Height, Sats, StoredF32, StoredF64, Version}; use vecdb::{IterableCloneableVec, LazyVecFrom2}; use crate::internal::{ - LazyVecsFrom2FromDateIndex, NegPercentageDollarsF32, NegRatio32, PercentageBtcF64, + BinaryDateLast, NegPercentageDollarsF32, NegRatio32, PercentageBtcF64, PercentageDollarsF32, PercentageSatsF64, Ratio32, }; @@ -15,28 +15,31 @@ use super::{ImportConfig, SupplyMetrics, UnrealizedMetrics}; #[derive(Clone, Traversable)] pub struct RelativeMetrics { // === Supply Relative to Circulating Supply (lazy from global supply) === + // KISS: both sources are ComputedVecsDateLast pub indexes_to_supply_rel_to_circulating_supply: - Option>, + Option>, // === Supply in Profit/Loss Relative to Own Supply (lazy) === pub height_to_supply_in_profit_rel_to_own_supply: LazyVecFrom2, pub height_to_supply_in_loss_rel_to_own_supply: LazyVecFrom2, + // KISS: both unrealized and supply are now KISS types pub indexes_to_supply_in_profit_rel_to_own_supply: - LazyVecsFrom2FromDateIndex, + BinaryDateLast, pub indexes_to_supply_in_loss_rel_to_own_supply: - LazyVecsFrom2FromDateIndex, + BinaryDateLast, // === Supply in Profit/Loss Relative to Circulating Supply (lazy from global supply) === pub height_to_supply_in_profit_rel_to_circulating_supply: Option>, pub height_to_supply_in_loss_rel_to_circulating_supply: Option>, + // KISS: both unrealized and global_supply are now KISS types pub indexes_to_supply_in_profit_rel_to_circulating_supply: - Option>, + Option>, pub indexes_to_supply_in_loss_rel_to_circulating_supply: - Option>, + Option>, // === Unrealized vs Market Cap (lazy from global market cap) === pub height_to_unrealized_profit_rel_to_market_cap: @@ -47,18 +50,20 @@ pub struct RelativeMetrics { Option>, pub height_to_net_unrealized_pnl_rel_to_market_cap: Option>, + // KISS: DerivedDateLast + ComputedVecsDateLast pub indexes_to_unrealized_profit_rel_to_market_cap: - Option>, + Option>, pub indexes_to_unrealized_loss_rel_to_market_cap: - Option>, + Option>, pub indexes_to_neg_unrealized_loss_rel_to_market_cap: - Option>, + Option>, + // KISS: both ComputedVecsDateLast pub indexes_to_net_unrealized_pnl_rel_to_market_cap: - Option>, + Option>, // === NUPL (Net Unrealized Profit/Loss) === - // Proxy for indexes_to_net_unrealized_pnl_rel_to_market_cap - pub indexes_to_nupl: Option>, + // KISS: both ComputedVecsDateLast + pub indexes_to_nupl: Option>, // === Unrealized vs Own Market Cap (lazy) === pub height_to_unrealized_profit_rel_to_own_market_cap: @@ -69,14 +74,16 @@ pub struct RelativeMetrics { Option>, pub height_to_net_unrealized_pnl_rel_to_own_market_cap: Option>, + // KISS: DerivedDateLast + ComputedVecsDateLast pub indexes_to_unrealized_profit_rel_to_own_market_cap: - Option>, + Option>, pub indexes_to_unrealized_loss_rel_to_own_market_cap: - Option>, + Option>, pub indexes_to_neg_unrealized_loss_rel_to_own_market_cap: - Option>, + Option>, + // KISS: both ComputedVecsDateLast pub indexes_to_net_unrealized_pnl_rel_to_own_market_cap: - Option>, + Option>, // === Unrealized vs Own Total Unrealized PnL (lazy) === pub height_to_unrealized_profit_rel_to_own_total_unrealized_pnl: @@ -87,14 +94,15 @@ pub struct RelativeMetrics { Option>, pub height_to_net_unrealized_pnl_rel_to_own_total_unrealized_pnl: Option>, + // KISS: DerivedDateLast + DerivedDateLast pub indexes_to_unrealized_profit_rel_to_own_total_unrealized_pnl: - Option>, + Option>, pub indexes_to_unrealized_loss_rel_to_own_total_unrealized_pnl: - Option>, + Option>, pub indexes_to_neg_unrealized_loss_rel_to_own_total_unrealized_pnl: - Option>, + Option>, pub indexes_to_net_unrealized_pnl_rel_to_own_total_unrealized_pnl: - Option>, + Option>, } impl RelativeMetrics { @@ -115,6 +123,7 @@ impl RelativeMetrics { // Global sources from "all" cohort let global_supply_sats = all_supply.map(|s| &s.indexes_to_supply.sats); + let global_supply_sats_dateindex = all_supply.map(|s| &s.indexes_to_supply.sats_dateindex); let global_supply_btc = all_supply.map(|s| &s.height_to_supply_value.bitcoin); let global_market_cap = all_supply.and_then(|s| s.indexes_to_supply.dollars.as_ref()); let global_market_cap_height = @@ -129,10 +138,12 @@ impl RelativeMetrics { indexes_to_supply_rel_to_circulating_supply: (compute_rel_to_all && global_supply_sats.is_some()) .then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_both_derived_last::( &cfg.name("supply_rel_to_circulating_supply"), cfg.version + v1, + supply.indexes_to_supply.sats_dateindex.boxed_clone(), &supply.indexes_to_supply.sats, + global_supply_sats_dateindex.unwrap().boxed_clone(), global_supply_sats.unwrap(), ) }), @@ -159,20 +170,23 @@ impl RelativeMetrics { supply.height_to_supply_value.bitcoin.boxed_clone(), ), indexes_to_supply_in_profit_rel_to_own_supply: - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_both_derived_last::( &cfg.name("supply_in_profit_rel_to_own_supply"), cfg.version + v1, + unrealized.dateindex_to_supply_in_profit.boxed_clone(), &unrealized.indexes_to_supply_in_profit.sats, + supply.indexes_to_supply.sats_dateindex.boxed_clone(), + &supply.indexes_to_supply.sats, + ), + indexes_to_supply_in_loss_rel_to_own_supply: + BinaryDateLast::from_both_derived_last::( + &cfg.name("supply_in_loss_rel_to_own_supply"), + cfg.version + v1, + unrealized.dateindex_to_supply_in_loss.boxed_clone(), + &unrealized.indexes_to_supply_in_loss.sats, + supply.indexes_to_supply.sats_dateindex.boxed_clone(), &supply.indexes_to_supply.sats, ), - indexes_to_supply_in_loss_rel_to_own_supply: LazyVecsFrom2FromDateIndex::from_computed::< - PercentageSatsF64, - >( - &cfg.name("supply_in_loss_rel_to_own_supply"), - cfg.version + v1, - &unrealized.indexes_to_supply_in_loss.sats, - &supply.indexes_to_supply.sats, - ), // === Supply in Profit/Loss Relative to Circulating Supply (lazy from global supply) === height_to_supply_in_profit_rel_to_circulating_supply: (compute_rel_to_all @@ -204,20 +218,24 @@ impl RelativeMetrics { indexes_to_supply_in_profit_rel_to_circulating_supply: (compute_rel_to_all && global_supply_sats.is_some()) .then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_both_derived_last::( &cfg.name("supply_in_profit_rel_to_circulating_supply"), cfg.version + v1, + unrealized.dateindex_to_supply_in_profit.boxed_clone(), &unrealized.indexes_to_supply_in_profit.sats, + global_supply_sats_dateindex.unwrap().boxed_clone(), global_supply_sats.unwrap(), ) }), indexes_to_supply_in_loss_rel_to_circulating_supply: (compute_rel_to_all && global_supply_sats.is_some()) .then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_both_derived_last::( &cfg.name("supply_in_loss_rel_to_circulating_supply"), cfg.version + v1, + unrealized.dateindex_to_supply_in_loss.boxed_clone(), &unrealized.indexes_to_supply_in_loss.sats, + global_supply_sats_dateindex.unwrap().boxed_clone(), global_supply_sats.unwrap(), ) }), @@ -255,32 +273,36 @@ impl RelativeMetrics { mc.boxed_clone(), ) }), + // KISS: market_cap is now ComputedVecsDateLast indexes_to_unrealized_profit_rel_to_market_cap: global_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("unrealized_profit_rel_to_market_cap"), cfg.version + v2, + unrealized.dateindex_to_unrealized_profit.boxed_clone(), &unrealized.indexes_to_unrealized_profit, mc, ) }), indexes_to_unrealized_loss_rel_to_market_cap: global_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("unrealized_loss_rel_to_market_cap"), cfg.version + v2, + unrealized.dateindex_to_unrealized_loss.boxed_clone(), &unrealized.indexes_to_unrealized_loss, mc, ) }), indexes_to_neg_unrealized_loss_rel_to_market_cap: global_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("neg_unrealized_loss_rel_to_market_cap"), cfg.version + v2, + unrealized.dateindex_to_unrealized_loss.boxed_clone(), &unrealized.indexes_to_unrealized_loss, mc, ) }), indexes_to_net_unrealized_pnl_rel_to_market_cap: global_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, &unrealized.indexes_to_net_unrealized_pnl, @@ -290,7 +312,7 @@ impl RelativeMetrics { // NUPL is a proxy for net_unrealized_pnl_rel_to_market_cap indexes_to_nupl: global_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &cfg.name("nupl"), cfg.version + v2, &unrealized.indexes_to_net_unrealized_pnl, @@ -347,12 +369,14 @@ impl RelativeMetrics { }) }) .flatten(), + // KISS: own_market_cap is now ComputedVecsDateLast indexes_to_unrealized_profit_rel_to_own_market_cap: (extended && compute_rel_to_all) .then(|| { own_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("unrealized_profit_rel_to_own_market_cap"), cfg.version + v2, + unrealized.dateindex_to_unrealized_profit.boxed_clone(), &unrealized.indexes_to_unrealized_profit, mc, ) @@ -362,9 +386,10 @@ impl RelativeMetrics { indexes_to_unrealized_loss_rel_to_own_market_cap: (extended && compute_rel_to_all) .then(|| { own_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("unrealized_loss_rel_to_own_market_cap"), cfg.version + v2, + unrealized.dateindex_to_unrealized_loss.boxed_clone(), &unrealized.indexes_to_unrealized_loss, mc, ) @@ -374,9 +399,10 @@ impl RelativeMetrics { indexes_to_neg_unrealized_loss_rel_to_own_market_cap: (extended && compute_rel_to_all) .then(|| { own_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("neg_unrealized_loss_rel_to_own_market_cap"), cfg.version + v2, + unrealized.dateindex_to_unrealized_loss.boxed_clone(), &unrealized.indexes_to_unrealized_loss, mc, ) @@ -386,7 +412,7 @@ impl RelativeMetrics { indexes_to_net_unrealized_pnl_rel_to_own_market_cap: (extended && compute_rel_to_all) .then(|| { own_market_cap.map(|mc| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &cfg.name("net_unrealized_pnl_rel_to_own_market_cap"), cfg.version + v2, &unrealized.indexes_to_net_unrealized_pnl, @@ -430,31 +456,34 @@ impl RelativeMetrics { ) }), indexes_to_unrealized_profit_rel_to_own_total_unrealized_pnl: extended.then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("unrealized_profit_rel_to_own_total_unrealized_pnl"), cfg.version + v1, + unrealized.dateindex_to_unrealized_profit.boxed_clone(), &unrealized.indexes_to_unrealized_profit, &unrealized.indexes_to_total_unrealized_pnl, ) }), indexes_to_unrealized_loss_rel_to_own_total_unrealized_pnl: extended.then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("unrealized_loss_rel_to_own_total_unrealized_pnl"), cfg.version + v1, + unrealized.dateindex_to_unrealized_loss.boxed_clone(), &unrealized.indexes_to_unrealized_loss, &unrealized.indexes_to_total_unrealized_pnl, ) }), indexes_to_neg_unrealized_loss_rel_to_own_total_unrealized_pnl: extended.then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_derived_last_and_computed_last::( &cfg.name("neg_unrealized_loss_rel_to_own_total_unrealized_pnl"), cfg.version + v1, + unrealized.dateindex_to_unrealized_loss.boxed_clone(), &unrealized.indexes_to_unrealized_loss, &unrealized.indexes_to_total_unrealized_pnl, ) }), indexes_to_net_unrealized_pnl_rel_to_own_total_unrealized_pnl: extended.then(|| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &cfg.name("net_unrealized_pnl_rel_to_own_total_unrealized_pnl"), cfg.version + v1, &unrealized.indexes_to_net_unrealized_pnl, diff --git a/crates/brk_computer/src/distribution/metrics/supply.rs b/crates/brk_computer/src/distribution/metrics/supply.rs index 443de4f67..c40ff62a9 100644 --- a/crates/brk_computer/src/distribution/metrics/supply.rs +++ b/crates/brk_computer/src/distribution/metrics/supply.rs @@ -10,9 +10,8 @@ use vecdb::{ use crate::{ ComputeIndexes, indexes, internal::{ - ComputedHeightValueVecs, ComputedValueVecsFromDateIndex, ComputedVecsFromHeight, - HalfClosePriceTimesSats, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyHeightValueVecs, - LazyValueVecsFromDateIndex, Source, VecBuilderOptions, + DerivedComputedBlockLast, HalfClosePriceTimesSats, HalveDollars, HalveSats, + HalveSatsToBitcoin, LazyBlockValue, LazyDerivedBlockValue, LazyValueDateLast, ValueDateLast, }, price, }; @@ -22,26 +21,13 @@ use super::ImportConfig; /// Supply and UTXO count metrics for a cohort. #[derive(Clone, Traversable)] pub struct SupplyMetrics { - /// Total supply at each height pub height_to_supply: EagerVec>, - - /// Supply value in BTC and USD (computed from height_to_supply) - pub height_to_supply_value: ComputedHeightValueVecs, - - /// Supply indexed by date - pub indexes_to_supply: ComputedValueVecsFromDateIndex, - - /// UTXO count at each height + pub height_to_supply_value: LazyDerivedBlockValue, + pub indexes_to_supply: ValueDateLast, pub height_to_utxo_count: EagerVec>, - - /// UTXO count indexed by various dimensions - pub indexes_to_utxo_count: ComputedVecsFromHeight, - - /// Half of supply value (used for computing median) - lazy from supply_value - pub height_to_supply_half_value: LazyHeightValueVecs, - - /// Half of supply indexed by date - lazy from indexes_to_supply - pub indexes_to_supply_half: LazyValueVecsFromDateIndex, + pub indexes_to_utxo_count: DerivedComputedBlockLast, + pub height_to_supply_half_value: LazyBlockValue, + pub indexes_to_supply_half: LazyValueDateLast, } impl SupplyMetrics { @@ -49,7 +35,6 @@ impl SupplyMetrics { pub fn forced_import(cfg: &ImportConfig) -> Result { let v1 = Version::ONE; let compute_dollars = cfg.compute_dollars(); - let last = VecBuilderOptions::default().add_last(); let height_to_supply: EagerVec> = EagerVec::forced_import(cfg.db, &cfg.name("supply"), cfg.version)?; @@ -58,26 +43,23 @@ impl SupplyMetrics { .price .map(|p| p.usd.chainindexes_to_price_close.height.boxed_clone()); - let height_to_supply_value = ComputedHeightValueVecs::forced_import( - cfg.db, + let height_to_supply_value = LazyDerivedBlockValue::from_source( &cfg.name("supply"), - Source::Vec(height_to_supply.boxed_clone()), + height_to_supply.boxed_clone(), cfg.version, price_source.clone(), - )?; + ); - let indexes_to_supply = ComputedValueVecsFromDateIndex::forced_import( + let indexes_to_supply = ValueDateLast::forced_import( cfg.db, &cfg.name("supply"), - Source::Compute, cfg.version + v1, - last, compute_dollars, cfg.indexes, )?; // Create lazy supply_half from supply sources - let height_to_supply_half_value = LazyHeightValueVecs::from_sources::< + let height_to_supply_half_value = LazyBlockValue::from_sources::< HalveSats, HalveSatsToBitcoin, HalfClosePriceTimesSats, @@ -89,7 +71,7 @@ impl SupplyMetrics { ); let indexes_to_supply_half = - LazyValueVecsFromDateIndex::from_source::( + LazyValueDateLast::from_source::( &cfg.name("supply_half"), &indexes_to_supply, cfg.version, @@ -99,13 +81,12 @@ impl SupplyMetrics { EagerVec::forced_import(cfg.db, &cfg.name("utxo_count"), cfg.version)?; Ok(Self { - indexes_to_utxo_count: ComputedVecsFromHeight::forced_import( + indexes_to_utxo_count: DerivedComputedBlockLast::forced_import( cfg.db, &cfg.name("utxo_count"), - Source::Vec(height_to_utxo_count.boxed_clone()), + height_to_utxo_count.boxed_clone(), cfg.version, cfg.indexes, - last, )?, height_to_supply, height_to_supply_value, @@ -208,11 +189,11 @@ impl SupplyMetrics { Ok(()) })?; - self.indexes_to_utxo_count.compute_rest( + self.indexes_to_utxo_count.derive_from( indexes, starting_indexes, + &self.height_to_utxo_count, exit, - Some(&self.height_to_utxo_count), )?; Ok(()) diff --git a/crates/brk_computer/src/distribution/metrics/unrealized.rs b/crates/brk_computer/src/distribution/metrics/unrealized.rs index c078edbda..090cf02bf 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized.rs @@ -11,8 +11,8 @@ use crate::{ ComputeIndexes, distribution::state::UnrealizedState, internal::{ - ComputedHeightValueVecs, ComputedValueVecsFromDateIndex, ComputedVecsFromDateIndex, - DollarsMinus, DollarsPlus, LazyVecsFromDateIndex, Source, VecBuilderOptions, + ComputedDateLast, DerivedDateLast, DollarsMinus, DollarsPlus, LazyDateLast, + LazyDerivedBlockValue, ValueDerivedDateLast, }, }; @@ -23,42 +23,41 @@ use super::ImportConfig; pub struct UnrealizedMetrics { // === Supply in Profit/Loss === pub height_to_supply_in_profit: EagerVec>, - pub indexes_to_supply_in_profit: ComputedValueVecsFromDateIndex, + pub indexes_to_supply_in_profit: ValueDerivedDateLast, pub height_to_supply_in_loss: EagerVec>, - pub indexes_to_supply_in_loss: ComputedValueVecsFromDateIndex, + pub indexes_to_supply_in_loss: ValueDerivedDateLast, pub dateindex_to_supply_in_profit: EagerVec>, pub dateindex_to_supply_in_loss: EagerVec>, - pub height_to_supply_in_profit_value: ComputedHeightValueVecs, - pub height_to_supply_in_loss_value: ComputedHeightValueVecs, + pub height_to_supply_in_profit_value: LazyDerivedBlockValue, + pub height_to_supply_in_loss_value: LazyDerivedBlockValue, // === Unrealized Profit/Loss === pub height_to_unrealized_profit: EagerVec>, - pub indexes_to_unrealized_profit: ComputedVecsFromDateIndex, + pub indexes_to_unrealized_profit: DerivedDateLast, pub height_to_unrealized_loss: EagerVec>, - pub indexes_to_unrealized_loss: ComputedVecsFromDateIndex, + pub indexes_to_unrealized_loss: DerivedDateLast, pub dateindex_to_unrealized_profit: EagerVec>, pub dateindex_to_unrealized_loss: EagerVec>, // === Negated and Net === pub height_to_neg_unrealized_loss: LazyVecFrom1, - pub indexes_to_neg_unrealized_loss: LazyVecsFromDateIndex, + pub indexes_to_neg_unrealized_loss: LazyDateLast, // net = profit - loss (height is lazy, indexes computed) pub height_to_net_unrealized_pnl: LazyVecFrom2, - pub indexes_to_net_unrealized_pnl: ComputedVecsFromDateIndex, + pub indexes_to_net_unrealized_pnl: ComputedDateLast, // total = profit + loss (height is lazy, indexes computed) pub height_to_total_unrealized_pnl: LazyVecFrom2, - pub indexes_to_total_unrealized_pnl: ComputedVecsFromDateIndex, + pub indexes_to_total_unrealized_pnl: ComputedDateLast, } impl UnrealizedMetrics { /// Import unrealized metrics from database. pub fn forced_import(cfg: &ImportConfig) -> Result { let compute_dollars = cfg.compute_dollars(); - let last = VecBuilderOptions::default().add_last(); let dateindex_to_supply_in_profit = EagerVec::forced_import(cfg.db, &cfg.name("supply_in_profit"), cfg.version)?; @@ -76,33 +75,29 @@ impl UnrealizedMetrics { height_to_unrealized_loss.boxed_clone(), ); - let indexes_to_unrealized_loss = ComputedVecsFromDateIndex::forced_import( - cfg.db, + let indexes_to_unrealized_loss = DerivedDateLast::from_source( &cfg.name("unrealized_loss"), - Source::Vec(dateindex_to_unrealized_loss.boxed_clone()), cfg.version, + dateindex_to_unrealized_loss.boxed_clone(), cfg.indexes, - last, - )?; + ); - let indexes_to_neg_unrealized_loss = LazyVecsFromDateIndex::from_computed::( + let indexes_to_neg_unrealized_loss = LazyDateLast::from_derived::( &cfg.name("neg_unrealized_loss"), cfg.version, - Some(dateindex_to_unrealized_loss.boxed_clone()), + dateindex_to_unrealized_loss.boxed_clone(), &indexes_to_unrealized_loss, ); // Extract profit sources for lazy net/total vecs let height_to_unrealized_profit: EagerVec> = EagerVec::forced_import(cfg.db, &cfg.name("unrealized_profit"), cfg.version)?; - let indexes_to_unrealized_profit = ComputedVecsFromDateIndex::forced_import( - cfg.db, + let indexes_to_unrealized_profit = DerivedDateLast::from_source( &cfg.name("unrealized_profit"), - Source::Vec(dateindex_to_unrealized_profit.boxed_clone()), cfg.version, + dateindex_to_unrealized_profit.boxed_clone(), cfg.indexes, - last, - )?; + ); // Create lazy height vecs from profit/loss sources let height_to_net_unrealized_pnl = LazyVecFrom2::transformed::( @@ -119,21 +114,17 @@ impl UnrealizedMetrics { ); // indexes_to_net/total remain computed (needed by relative.rs) - let indexes_to_net_unrealized_pnl = ComputedVecsFromDateIndex::forced_import( + let indexes_to_net_unrealized_pnl = ComputedDateLast::forced_import( cfg.db, &cfg.name("net_unrealized_pnl"), - Source::Compute, cfg.version, cfg.indexes, - last, )?; - let indexes_to_total_unrealized_pnl = ComputedVecsFromDateIndex::forced_import( + let indexes_to_total_unrealized_pnl = ComputedDateLast::forced_import( cfg.db, &cfg.name("total_unrealized_pnl"), - Source::Compute, cfg.version, cfg.indexes, - last, )?; let height_to_supply_in_profit: EagerVec> = @@ -145,40 +136,36 @@ impl UnrealizedMetrics { .price .map(|p| p.usd.chainindexes_to_price_close.height.boxed_clone()); - let height_to_supply_in_profit_value = ComputedHeightValueVecs::forced_import( - cfg.db, + let height_to_supply_in_profit_value = LazyDerivedBlockValue::from_source( &cfg.name("supply_in_profit"), - Source::Vec(height_to_supply_in_profit.boxed_clone()), + height_to_supply_in_profit.boxed_clone(), cfg.version, price_source.clone(), - )?; - let height_to_supply_in_loss_value = ComputedHeightValueVecs::forced_import( - cfg.db, + ); + let height_to_supply_in_loss_value = LazyDerivedBlockValue::from_source( &cfg.name("supply_in_loss"), - Source::Vec(height_to_supply_in_loss.boxed_clone()), + height_to_supply_in_loss.boxed_clone(), cfg.version, price_source, - )?; + ); Ok(Self { // === Supply in Profit/Loss === height_to_supply_in_profit, - indexes_to_supply_in_profit: ComputedValueVecsFromDateIndex::forced_import( + indexes_to_supply_in_profit: ValueDerivedDateLast::from_source( cfg.db, &cfg.name("supply_in_profit"), - Source::Vec(dateindex_to_supply_in_profit.boxed_clone()), + dateindex_to_supply_in_profit.boxed_clone(), cfg.version, - last, compute_dollars, cfg.indexes, )?, height_to_supply_in_loss, - indexes_to_supply_in_loss: ComputedValueVecsFromDateIndex::forced_import( + indexes_to_supply_in_loss: ValueDerivedDateLast::from_source( cfg.db, &cfg.name("supply_in_loss"), - Source::Vec(dateindex_to_supply_in_loss.boxed_clone()), + dateindex_to_supply_in_loss.boxed_clone(), cfg.version, - last, compute_dollars, cfg.indexes, )?, @@ -362,31 +349,14 @@ impl UnrealizedMetrics { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_supply_in_profit.compute_rest( - price, - starting_indexes, - exit, - Some(&self.dateindex_to_supply_in_profit), - )?; + // KISS: compute_rest doesn't need source vec - lazy vecs are set up during import + self.indexes_to_supply_in_profit + .compute_rest(price, starting_indexes, exit)?; - self.indexes_to_supply_in_loss.compute_rest( - price, - starting_indexes, - exit, - Some(&self.dateindex_to_supply_in_loss), - )?; + self.indexes_to_supply_in_loss + .compute_rest(price, starting_indexes, exit)?; - self.indexes_to_unrealized_profit.compute_rest( - starting_indexes, - exit, - Some(&self.dateindex_to_unrealized_profit), - )?; - - self.indexes_to_unrealized_loss.compute_rest( - starting_indexes, - exit, - Some(&self.dateindex_to_unrealized_loss), - )?; + // indexes_to_unrealized_profit/loss are Derived - no compute needed (lazy only) // height_to_net/total are lazy, but indexes still need compute // total_unrealized_pnl = profit + loss diff --git a/crates/brk_computer/src/distribution/state/cohort/utxo.rs b/crates/brk_computer/src/distribution/state/cohort/utxo.rs index 4c564a9f6..eed6b08e9 100644 --- a/crates/brk_computer/src/distribution/state/cohort/utxo.rs +++ b/crates/brk_computer/src/distribution/state/cohort/utxo.rs @@ -2,12 +2,9 @@ use std::path::Path; use brk_error::Result; use brk_types::{Sats, SupplyState}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; -use super::{ - super::cost_basis::RealizedState, - base::CohortState, -}; +use super::{super::cost_basis::RealizedState, base::CohortState}; #[derive(Clone, Deref, DerefMut)] pub struct UTXOCohortState(CohortState); diff --git a/crates/brk_computer/src/distribution/state/cost_basis/price_to_amount.rs b/crates/brk_computer/src/distribution/state/cost_basis/price_to_amount.rs index fc07996fa..a5417d9a0 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/price_to_amount.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/price_to_amount.rs @@ -7,7 +7,7 @@ use std::{ use brk_error::{Error, Result}; use brk_types::{CentsCompact, Dollars, Height, Sats, SupplyState}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use pco::standalone::{simple_decompress, simpler_compress}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; diff --git a/crates/brk_computer/src/distribution/vecs.rs b/crates/brk_computer/src/distribution/vecs.rs index 0c42849fc..d6e522844 100644 --- a/crates/brk_computer/src/distribution/vecs.rs +++ b/crates/brk_computer/src/distribution/vecs.rs @@ -20,7 +20,7 @@ use crate::{ state::BlockState, }, indexes, inputs, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::ComputedBlockLast, outputs, price, transactions, }; @@ -49,8 +49,8 @@ pub struct Vecs { pub addresstype_to_indexes_to_addr_count: AddressTypeToIndexesToAddressCount, pub addresstype_to_indexes_to_empty_addr_count: AddressTypeToIndexesToAddressCount, - pub indexes_to_addr_count: ComputedVecsFromHeight, - pub indexes_to_empty_addr_count: ComputedVecsFromHeight, + pub indexes_to_addr_count: ComputedBlockLast, + pub indexes_to_empty_addr_count: ComputedBlockLast, pub loadedaddressindex_to_loadedaddressindex: LazyVecFrom1, pub emptyaddressindex_to_emptyaddressindex: @@ -123,21 +123,17 @@ impl Vecs { .with_saved_stamped_changes(SAVED_STAMPED_CHANGES), )?, - indexes_to_addr_count: ComputedVecsFromHeight::forced_import( + indexes_to_addr_count: ComputedBlockLast::forced_import( &db, "addr_count", - Source::Compute, version, indexes, - VecBuilderOptions::default().add_last(), )?, - indexes_to_empty_addr_count: ComputedVecsFromHeight::forced_import( + indexes_to_empty_addr_count: ComputedBlockLast::forced_import( &db, "empty_addr_count", - Source::Compute, version, indexes, - VecBuilderOptions::default().add_last(), )?, addresstype_to_indexes_to_addr_count: @@ -380,11 +376,12 @@ impl Vecs { .as_ref() .cloned(); + // KISS: dateindex is no longer Option, just clone directly let dateindex_to_market_cap = supply_metrics .indexes_to_supply .dollars .as_ref() - .and_then(|v| v.dateindex.as_ref().cloned()); + .map(|v| v.dateindex.clone()); let height_to_market_cap_ref = height_to_market_cap.as_ref(); let dateindex_to_market_cap_ref = dateindex_to_market_cap.as_ref(); diff --git a/crates/brk_computer/src/inputs/count/compute.rs b/crates/brk_computer/src/inputs/count/compute.rs index 1a875aa78..90dcbc690 100644 --- a/crates/brk_computer/src/inputs/count/compute.rs +++ b/crates/brk_computer/src/inputs/count/compute.rs @@ -13,12 +13,12 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_count.compute_rest( + self.indexes_to_count.derive_from( indexer, indexes, starting_indexes, + &indexes.transaction.txindex_to_input_count, exit, - Some(&indexes.transaction.txindex_to_input_count), )?; Ok(()) diff --git a/crates/brk_computer/src/inputs/count/import.rs b/crates/brk_computer/src/inputs/count/import.rs index f2b7d446d..1407f6814 100644 --- a/crates/brk_computer/src/inputs/count/import.rs +++ b/crates/brk_computer/src/inputs/count/import.rs @@ -1,33 +1,15 @@ use brk_error::Result; use brk_types::Version; -use vecdb::{Database, IterableCloneableVec}; +use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromTxindex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::DerivedTxFull}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; + let indexes_to_count = + DerivedTxFull::forced_import(db, "input_count", version, indexes)?; - Ok(Self { - indexes_to_count: ComputedVecsFromTxindex::forced_import( - db, - "input_count", - Source::Vec(indexes.transaction.txindex_to_input_count.boxed_clone()), - version, - indexes, - full_stats(), - )?, - }) + Ok(Self { indexes_to_count }) } } diff --git a/crates/brk_computer/src/inputs/count/vecs.rs b/crates/brk_computer/src/inputs/count/vecs.rs index f17fe94c6..855957b0d 100644 --- a/crates/brk_computer/src/inputs/count/vecs.rs +++ b/crates/brk_computer/src/inputs/count/vecs.rs @@ -1,9 +1,9 @@ use brk_traversable::Traversable; use brk_types::StoredU64; -use crate::internal::ComputedVecsFromTxindex; +use crate::internal::DerivedTxFull; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_count: ComputedVecsFromTxindex, + pub indexes_to_count: DerivedTxFull, } diff --git a/crates/brk_computer/src/internal/aggregation/average.rs b/crates/brk_computer/src/internal/aggregation/average.rs new file mode 100644 index 000000000..da50c2560 --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/average.rs @@ -0,0 +1,59 @@ +//! Lazy average-value aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "average")] +pub struct LazyAverage(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazyAverage +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + &format!("{name}_average"), + version + VERSION, + source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + let mut sum = T::from(0); + let mut len = 0usize; + for v in + S1I::inclusive_range_from(i, source.vec_len()).flat_map(|i| source.get_at(i)) + { + sum += v; + len += 1; + } + if len == 0 { + return None; + } + Some(sum / len) + }, + )) + } +} diff --git a/crates/brk_computer/src/internal/aggregation/cumulative.rs b/crates/brk_computer/src/internal/aggregation/cumulative.rs new file mode 100644 index 000000000..6913e1f13 --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/cumulative.rs @@ -0,0 +1,48 @@ +//! Lazy cumulative-only aggregation (takes last value from cumulative source). + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "cumulative")] +pub struct LazyCumulative(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazyCumulative +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + cumulative_source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + &format!("{name}_cumulative"), + version + VERSION, + cumulative_source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + source.get_at(S1I::max_from(i, source.vec_len())) + }, + )) + } +} diff --git a/crates/brk_computer/src/internal/aggregation/distribution.rs b/crates/brk_computer/src/internal/aggregation/distribution.rs new file mode 100644 index 000000000..468aeb4be --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/distribution.rs @@ -0,0 +1,52 @@ +//! Lazy distribution pattern (average, min, max). + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, VecIndex}; + +use super::{LazyAverage, LazyMax, LazyMin}; +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +pub struct LazyDistribution +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: ComputedVecValue, +{ + #[traversable(flatten)] + pub average: LazyAverage, + #[traversable(flatten)] + pub min: LazyMin, + #[traversable(flatten)] + pub max: LazyMax, +} + +impl LazyDistribution +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: ComputedVecValue, +{ + pub fn from_distribution( + name: &str, + version: Version, + source_average: IterableBoxedVec, + source_min: IterableBoxedVec, + source_max: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + let v = version + VERSION; + + Self { + average: LazyAverage::from_source(name, v, source_average, len_source.clone()), + min: LazyMin::from_source(name, v, source_min, len_source.clone()), + max: LazyMax::from_source(name, v, source_max, len_source), + } + } +} diff --git a/crates/brk_computer/src/internal/aggregation/first.rs b/crates/brk_computer/src/internal/aggregation/first.rs new file mode 100644 index 000000000..7021ca33e --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/first.rs @@ -0,0 +1,48 @@ +//! Lazy first-value aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "first")] +pub struct LazyFirst(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazyFirst +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + name, + version + VERSION, + source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + source.get_at(S1I::min_from(i)) + }, + )) + } +} diff --git a/crates/brk_computer/src/internal/aggregation/last.rs b/crates/brk_computer/src/internal/aggregation/last.rs new file mode 100644 index 000000000..9124b08d7 --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/last.rs @@ -0,0 +1,49 @@ +//! Lazy last-value aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "last")] +pub struct LazyLast(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazyLast +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + name, + version + VERSION, + source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + source.get_at(S1I::max_from(i, source.vec_len())) + }, + )) + } +} + diff --git a/crates/brk_computer/src/internal/aggregation/max.rs b/crates/brk_computer/src/internal/aggregation/max.rs new file mode 100644 index 000000000..836544ffd --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/max.rs @@ -0,0 +1,50 @@ +//! Lazy max-value aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "max")] +pub struct LazyMax(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazyMax +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + &format!("{name}_max"), + version + VERSION, + source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + S1I::inclusive_range_from(i, source.vec_len()) + .flat_map(|i| source.get_at(i)) + .max() + }, + )) + } +} diff --git a/crates/brk_computer/src/internal/aggregation/min.rs b/crates/brk_computer/src/internal/aggregation/min.rs new file mode 100644 index 000000000..7ae536cea --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/min.rs @@ -0,0 +1,50 @@ +//! Lazy min-value aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "min")] +pub struct LazyMin(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazyMin +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + &format!("{name}_min"), + version + VERSION, + source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + S1I::inclusive_range_from(i, source.vec_len()) + .flat_map(|i| source.get_at(i)) + .min() + }, + )) + } +} diff --git a/crates/brk_computer/src/internal/aggregation/mod.rs b/crates/brk_computer/src/internal/aggregation/mod.rs new file mode 100644 index 000000000..53cf7d46e --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/mod.rs @@ -0,0 +1,23 @@ +//! Lazy aggregation primitives (finer index → coarser index). + +mod average; +mod cumulative; +mod distribution; +mod first; +mod last; +mod max; +mod min; +mod stats_aggregate; +mod sum; +mod sum_cum; + +pub use average::*; +pub use cumulative::*; +pub use distribution::*; +pub use first::*; +pub use last::*; +pub use max::*; +pub use min::*; +pub use stats_aggregate::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/aggregation/stats_aggregate.rs b/crates/brk_computer/src/internal/aggregation/stats_aggregate.rs new file mode 100644 index 000000000..ad2aef93c --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/stats_aggregate.rs @@ -0,0 +1,61 @@ +//! Lazy stats aggregate pattern (average, min, max, sum, cumulative). + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, VecIndex, VecValue}; + +use super::{LazyAverage, LazyCumulative, LazyMax, LazyMin, LazySum}; +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +pub struct LazyFull +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue, +{ + #[traversable(flatten)] + pub average: LazyAverage, + #[traversable(flatten)] + pub min: LazyMin, + #[traversable(flatten)] + pub max: LazyMax, + #[traversable(flatten)] + pub sum: LazySum, + #[traversable(flatten)] + pub cumulative: LazyCumulative, +} + +impl LazyFull +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + #[allow(clippy::too_many_arguments)] + pub fn from_stats_aggregate( + name: &str, + version: Version, + source_average: IterableBoxedVec, + source_min: IterableBoxedVec, + source_max: IterableBoxedVec, + source_sum: IterableBoxedVec, + source_cumulative: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + let v = version + VERSION; + + Self { + average: LazyAverage::from_source(name, v, source_average, len_source.clone()), + min: LazyMin::from_source(name, v, source_min, len_source.clone()), + max: LazyMax::from_source(name, v, source_max, len_source.clone()), + sum: LazySum::from_source(name, v, source_sum, len_source.clone()), + cumulative: LazyCumulative::from_source(name, v, source_cumulative, len_source), + } + } +} diff --git a/crates/brk_computer/src/internal/aggregation/sum.rs b/crates/brk_computer/src/internal/aggregation/sum.rs new file mode 100644 index 000000000..f97dff1d2 --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/sum.rs @@ -0,0 +1,60 @@ +//! Lazy sum-value aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, LazyVecFrom2, VecIndex, VecValue}; + +use crate::internal::ComputedVecValue; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "sum")] +pub struct LazySum(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue; + +impl LazySum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_source( + name: &str, + version: Version, + source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::init( + &format!("{name}_sum"), + version + VERSION, + source, + len_source, + |i: I, source, len_source| { + if i.to_usize() >= len_source.vec_len() { + return None; + } + let mut sum = T::from(0); + let mut has_values = false; + for v in S1I::inclusive_range_from(i, source.vec_len()) + .flat_map(|i| source.get_at(i)) + { + sum += v; + has_values = true; + } + if !has_values { + return None; + } + Some(sum) + }, + )) + } +} + diff --git a/crates/brk_computer/src/internal/aggregation/sum_cum.rs b/crates/brk_computer/src/internal/aggregation/sum_cum.rs new file mode 100644 index 000000000..dcd6ad6b4 --- /dev/null +++ b/crates/brk_computer/src/internal/aggregation/sum_cum.rs @@ -0,0 +1,51 @@ +//! Lazy sum + cumulative aggregation. + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{FromCoarserIndex, IterableBoxedVec, VecIndex, VecValue}; + +use crate::internal::{ComputedVecValue, LazyCumulative, LazySum}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +pub struct LazySumCum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1I: VecIndex, + S2T: VecValue, +{ + #[traversable(flatten)] + pub sum: LazySum, + #[traversable(flatten)] + pub cumulative: LazyCumulative, +} + +impl LazySumCum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1I: VecIndex + 'static + FromCoarserIndex, + S2T: VecValue, +{ + pub fn from_sources( + name: &str, + version: Version, + sum_source: IterableBoxedVec, + cumulative_source: IterableBoxedVec, + len_source: IterableBoxedVec, + ) -> Self { + Self { + sum: LazySum::from_source(name, version + VERSION, sum_source, len_source.clone()), + cumulative: LazyCumulative::from_source( + name, + version + VERSION, + cumulative_source, + len_source, + ), + } + } +} + diff --git a/crates/brk_computer/src/internal/builder/eager.rs b/crates/brk_computer/src/internal/builder/eager.rs deleted file mode 100644 index 8b33ea171..000000000 --- a/crates/brk_computer/src/internal/builder/eager.rs +++ /dev/null @@ -1,843 +0,0 @@ -use brk_error::{Error, Result}; -use brk_traversable::Traversable; -use brk_types::{CheckedSub, StoredU64, Version}; -use schemars::JsonSchema; -use vecdb::{ - AnyStoredVec, Database, EagerVec, Exit, GenericStoredVec, ImportableVec, IterableVec, PcoVec, - VecIndex, VecValue, -}; - -use crate::utils::{OptionExt, get_percentile}; - -use super::super::ComputedVecValue; - -const VERSION: Version = Version::ZERO; - -#[derive(Clone, Debug, Traversable)] -pub struct EagerVecsBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema, -{ - pub first: Option>>>, - pub average: Option>>>, - pub sum: Option>>>, - pub max: Option>>>, - pub pct90: Option>>>, - pub pct75: Option>>>, - pub median: Option>>>, - pub pct25: Option>>>, - pub pct10: Option>>>, - pub min: Option>>>, - pub last: Option>>>, - pub cumulative: Option>>>, -} - -impl EagerVecsBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema, -{ - pub fn forced_import( - db: &Database, - name: &str, - version: Version, - options: VecBuilderOptions, - ) -> Result { - let only_one_active = options.is_only_one_active(); - let suffix = |s: &str| format!("{name}_{s}"); - let maybe_suffix = |s: &str| { - if only_one_active { - name.to_string() - } else { - suffix(s) - } - }; - let v = version + VERSION; - - macro_rules! import { - ($s:expr) => { - Box::new(EagerVec::forced_import(db, &maybe_suffix($s), v).unwrap()) - }; - } - - let s = Self { - first: options.first.then(|| import!("first")), - last: options - .last - .then(|| Box::new(EagerVec::forced_import(db, name, v).unwrap())), - min: options.min.then(|| import!("min")), - max: options.max.then(|| import!("max")), - median: options.median.then(|| import!("median")), - average: options.average.then(|| import!("avg")), - sum: options.sum.then(|| { - let sum_name = if !options.last && !options.average && !options.min && !options.max - { - name.to_string() - } else { - maybe_suffix("sum") - }; - Box::new(EagerVec::forced_import(db, &sum_name, v).unwrap()) - }), - cumulative: options - .cumulative - .then(|| Box::new(EagerVec::forced_import(db, &suffix("cumulative"), v).unwrap())), - pct90: options.pct90.then(|| import!("pct90")), - pct75: options.pct75.then(|| import!("pct75")), - pct25: options.pct25.then(|| import!("pct25")), - pct10: options.pct10.then(|| import!("pct10")), - }; - - Ok(s) - } - - #[inline] - fn needs_percentiles(&self) -> bool { - self.pct90.is_some() - || self.pct75.is_some() - || self.median.is_some() - || self.pct25.is_some() - || self.pct10.is_some() - } - - #[inline] - fn needs_minmax(&self) -> bool { - self.max.is_some() || self.min.is_some() - } - - #[inline] - fn needs_sum_or_cumulative(&self) -> bool { - self.sum.is_some() || self.cumulative.is_some() - } - - #[inline] - fn needs_average_sum_or_cumulative(&self) -> bool { - self.needs_sum_or_cumulative() || self.average.is_some() - } - - /// Compute min/max in O(n) without sorting or collecting - #[inline] - fn compute_minmax_streaming( - &mut self, - index: usize, - iter: impl Iterator, - ) -> Result<()> { - let mut min_val: Option = None; - let mut max_val: Option = None; - let need_min = self.min.is_some(); - let need_max = self.max.is_some(); - - for val in iter { - if need_min { - min_val = Some(min_val.map_or(val, |m| if val < m { val } else { m })); - } - if need_max { - max_val = Some(max_val.map_or(val, |m| if val > m { val } else { m })); - } - } - - if let Some(min) = self.min.as_mut() { - min.truncate_push_at(index, min_val.unwrap())?; - } - if let Some(max) = self.max.as_mut() { - max.truncate_push_at(index, max_val.unwrap())?; - } - Ok(()) - } - - /// Compute min/max from collected values in O(n) without sorting - #[inline] - fn compute_minmax_from_slice(&mut self, index: usize, values: &[T]) -> Result<()> { - if let Some(min) = self.min.as_mut() { - min.truncate_push_at(index, *values.iter().min().unwrap())?; - } - if let Some(max) = self.max.as_mut() { - max.truncate_push_at(index, *values.iter().max().unwrap())?; - } - Ok(()) - } - - /// Compute percentiles from sorted values (assumes values is already sorted) - fn compute_percentiles_from_sorted(&mut self, index: usize, values: &[T]) -> Result<()> { - if let Some(max) = self.max.as_mut() { - max.truncate_push_at( - index, - *values - .last() - .ok_or(Error::Internal("Empty values for percentiles"))?, - )?; - } - if let Some(pct90) = self.pct90.as_mut() { - pct90.truncate_push_at(index, get_percentile(values, 0.90))?; - } - if let Some(pct75) = self.pct75.as_mut() { - pct75.truncate_push_at(index, get_percentile(values, 0.75))?; - } - if let Some(median) = self.median.as_mut() { - median.truncate_push_at(index, get_percentile(values, 0.50))?; - } - if let Some(pct25) = self.pct25.as_mut() { - pct25.truncate_push_at(index, get_percentile(values, 0.25))?; - } - if let Some(pct10) = self.pct10.as_mut() { - pct10.truncate_push_at(index, get_percentile(values, 0.10))?; - } - if let Some(min) = self.min.as_mut() { - min.truncate_push_at(index, *values.first().unwrap())?; - } - Ok(()) - } - - /// Compute sum, average, and cumulative from values - fn compute_aggregates( - &mut self, - index: usize, - values: Vec, - cumulative: &mut Option, - ) -> Result<()> { - let len = values.len(); - let sum = values.into_iter().fold(T::from(0), |a, b| a + b); - - if let Some(average) = self.average.as_mut() { - // len == 0 handled by T's Div returning NaN - average.truncate_push_at(index, sum / len)?; - } - - if self.needs_sum_or_cumulative() { - if let Some(sum_vec) = self.sum.as_mut() { - sum_vec.truncate_push_at(index, sum)?; - } - if let Some(cumulative_vec) = self.cumulative.as_mut() { - let t = cumulative.unwrap() + sum; - cumulative.replace(t); - cumulative_vec.truncate_push_at(index, t)?; - } - } - Ok(()) - } - - pub fn extend( - &mut self, - max_from: I, - source: &impl IterableVec, - exit: &Exit, - ) -> Result<()> { - if self.cumulative.is_none() { - return Ok(()); - }; - - self.validate_computed_version_or_reset(source.version())?; - - let index = self.starting_index(max_from); - - let cumulative_vec = self.cumulative.um(); - - let mut cumulative = index.decremented().map_or(T::from(0_usize), |index| { - cumulative_vec.iter().get_unwrap(index) - }); - source - .iter() - .enumerate() - .skip(index.to_usize()) - .try_for_each(|(i, v)| -> Result<()> { - cumulative += v; - cumulative_vec.truncate_push_at(i, cumulative)?; - Ok(()) - })?; - - let _lock = exit.lock(); - self.write()?; - - Ok(()) - } - - pub fn compute( - &mut self, - max_from: I, - source: &impl IterableVec, - first_indexes: &impl IterableVec, - count_indexes: &impl IterableVec, - exit: &Exit, - ) -> Result<()> - where - A: VecIndex + VecValue + CheckedSub, - { - self.validate_computed_version_or_reset( - source.version() + first_indexes.version() + count_indexes.version(), - )?; - - let index = self.starting_index(max_from); - - let mut source_iter = source.iter(); - - let cumulative_vec = self.cumulative.as_mut(); - - let mut cumulative = cumulative_vec.map(|cumulative_vec| { - index.decremented().map_or(T::from(0_usize), |index| { - cumulative_vec.iter().get_unwrap(index) - }) - }); - - let mut count_indexes_iter = count_indexes.iter().skip(index.to_usize()); - - first_indexes - .iter() - .enumerate() - .skip(index.to_usize()) - .try_for_each(|(index, first_index)| -> Result<()> { - let count_index = count_indexes_iter.next().unwrap(); - - if let Some(first) = self.first.as_mut() { - let f = source_iter - .get(first_index) - .unwrap_or_else(|| T::from(0_usize)); - first.truncate_push_at(index, f)?; - } - - if let Some(last) = self.last.as_mut() { - let count_index = *count_index as usize; - if count_index == 0 { - panic!("should compute last if count can be 0") - } - let last_index = first_index + (count_index - 1); - let v = source_iter.get_unwrap(last_index); - // .context("to work") - // .inspect_err(|_| { - // dbg!(first_index, count_index, last_index); - // }) - // .unwrap() - // ; - last.truncate_push_at(index, v)?; - } - - let needs_percentiles = self.needs_percentiles(); - let needs_minmax = self.needs_minmax(); - let needs_aggregates = self.needs_average_sum_or_cumulative(); - - // Fast path: only min/max needed, no sorting or allocation required - if needs_minmax && !needs_percentiles && !needs_aggregates { - source_iter.set_position(first_index); - self.compute_minmax_streaming( - index, - (&mut source_iter).take(*count_index as usize), - )?; - } else if needs_percentiles || needs_aggregates { - source_iter.set_position(first_index); - let mut values = (&mut source_iter) - .take(*count_index as usize) - .collect::>(); - - if needs_percentiles { - values.sort_unstable(); - self.compute_percentiles_from_sorted(index, &values)?; - } else if needs_minmax { - // We have values collected but only need min/max (along with aggregates) - self.compute_minmax_from_slice(index, &values)?; - } - - if needs_aggregates { - self.compute_aggregates(index, values, &mut cumulative)?; - } - } - - Ok(()) - })?; - - let _lock = exit.lock(); - self.write()?; - - Ok(()) - } - - #[allow(clippy::wrong_self_convention)] - pub fn from_aligned( - &mut self, - max_from: I, - source: &EagerVecsBuilder, - first_indexes: &impl IterableVec, - count_indexes: &impl IterableVec, - exit: &Exit, - ) -> Result<()> - where - A: VecIndex + VecValue + CheckedSub, - { - if self.needs_percentiles() { - panic!("percentiles unsupported in from_aligned"); - } - - self.validate_computed_version_or_reset( - VERSION + first_indexes.version() + count_indexes.version(), - )?; - - let index = self.starting_index(max_from); - - let mut source_first_iter = source.first.as_ref().map(|f| f.iter()); - let mut source_last_iter = source.last.as_ref().map(|f| f.iter()); - let mut source_max_iter = source.max.as_ref().map(|f| f.iter()); - let mut source_min_iter = source.min.as_ref().map(|f| f.iter()); - let mut source_average_iter = source.average.as_ref().map(|f| f.iter()); - let mut source_sum_iter = source.sum.as_ref().map(|f| f.iter()); - - let mut cumulative = self.cumulative.as_mut().map(|cumulative_vec| { - index.decremented().map_or(T::from(0_usize), |index| { - cumulative_vec.iter().get_unwrap(index) - }) - }); - - let mut count_indexes_iter = count_indexes.iter().skip(index.to_usize()); - - first_indexes - .iter() - .enumerate() - .skip(index.to_usize()) - .try_for_each(|(index, first_index, ..)| -> Result<()> { - let count_index = count_indexes_iter.next().unwrap(); - - if let Some(first) = self.first.as_mut() { - let v = source_first_iter.um().get_unwrap(first_index); - first.truncate_push_at(index, v)?; - } - - if let Some(last) = self.last.as_mut() { - let count_index = *count_index as usize; - if count_index == 0 { - panic!("should compute last if count can be 0") - } - let last_index = first_index + (count_index - 1); - let v = source_last_iter.um().get_unwrap(last_index); - last.truncate_push_at(index, v)?; - } - - let needs_minmax = self.needs_minmax(); - let needs_aggregates = self.needs_average_sum_or_cumulative(); - - if needs_minmax || needs_aggregates { - // Min/max: use streaming O(n) instead of sort O(n log n) - if needs_minmax { - if let Some(max) = self.max.as_mut() { - let source_max_iter = source_max_iter.um(); - source_max_iter.set_position(first_index); - let max_val = - source_max_iter.take(*count_index as usize).max().unwrap(); - max.truncate_push_at(index, max_val)?; - } - - if let Some(min) = self.min.as_mut() { - let source_min_iter = source_min_iter.um(); - source_min_iter.set_position(first_index); - let min_val = - source_min_iter.take(*count_index as usize).min().unwrap(); - min.truncate_push_at(index, min_val)?; - } - } - - if needs_aggregates { - if let Some(average) = self.average.as_mut() { - let source_average_iter = source_average_iter.um(); - source_average_iter.set_position(first_index); - let mut len = 0usize; - let sum = (&mut *source_average_iter) - .take(*count_index as usize) - .inspect(|_| len += 1) - .fold(T::from(0), |a, b| a + b); - // TODO: Multiply by count then divide by cumulative - // Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example) - // len == 0 handled by T's Div returning NaN - let avg = sum / len; - average.truncate_push_at(index, avg)?; - } - - if self.needs_sum_or_cumulative() { - let source_sum_iter = source_sum_iter.um(); - source_sum_iter.set_position(first_index); - let sum = source_sum_iter - .take(*count_index as usize) - .fold(T::from(0), |a, b| a + b); - - if let Some(sum_vec) = self.sum.as_mut() { - sum_vec.truncate_push_at(index, sum)?; - } - - if let Some(cumulative_vec) = self.cumulative.as_mut() { - let t = cumulative.unwrap() + sum; - cumulative.replace(t); - cumulative_vec.truncate_push_at(index, t)?; - } - } - } - } - - Ok(()) - })?; - - let _lock = exit.lock(); - self.write()?; - - Ok(()) - } - - pub fn starting_index(&self, max_from: I) -> I { - max_from.min(I::from( - self.iter_any_exportable().map(|v| v.len()).min().unwrap(), - )) - } - - #[inline] - pub fn unwrap_first(&self) -> &EagerVec> { - self.first.u() - } - #[inline] - pub fn unwrap_average(&self) -> &EagerVec> { - self.average.u() - } - #[inline] - pub fn unwrap_sum(&self) -> &EagerVec> { - self.sum.u() - } - #[inline] - pub fn unwrap_max(&self) -> &EagerVec> { - self.max.u() - } - #[inline] - pub fn unwrap_pct90(&self) -> &EagerVec> { - self.pct90.u() - } - #[inline] - pub fn unwrap_pct75(&self) -> &EagerVec> { - self.pct75.u() - } - #[inline] - pub fn unwrap_median(&self) -> &EagerVec> { - self.median.u() - } - #[inline] - pub fn unwrap_pct25(&self) -> &EagerVec> { - self.pct25.u() - } - #[inline] - pub fn unwrap_pct10(&self) -> &EagerVec> { - self.pct10.u() - } - #[inline] - pub fn unwrap_min(&self) -> &EagerVec> { - self.min.u() - } - #[inline] - pub fn unwrap_last(&self) -> &EagerVec> { - self.last.u() - } - #[inline] - pub fn unwrap_cumulative(&self) -> &EagerVec> { - self.cumulative.u() - } - - pub fn write(&mut self) -> Result<()> { - if let Some(first) = self.first.as_mut() { - first.write()?; - } - if let Some(last) = self.last.as_mut() { - last.write()?; - } - if let Some(min) = self.min.as_mut() { - min.write()?; - } - if let Some(max) = self.max.as_mut() { - max.write()?; - } - if let Some(median) = self.median.as_mut() { - median.write()?; - } - if let Some(average) = self.average.as_mut() { - average.write()?; - } - if let Some(sum) = self.sum.as_mut() { - sum.write()?; - } - if let Some(cumulative) = self.cumulative.as_mut() { - cumulative.write()?; - } - if let Some(pct90) = self.pct90.as_mut() { - pct90.write()?; - } - if let Some(pct75) = self.pct75.as_mut() { - pct75.write()?; - } - if let Some(pct25) = self.pct25.as_mut() { - pct25.write()?; - } - if let Some(pct10) = self.pct10.as_mut() { - pct10.write()?; - } - - Ok(()) - } - - pub fn validate_computed_version_or_reset(&mut self, dep_version: Version) -> Result<()> { - if let Some(first) = self.first.as_mut() { - first.validate_computed_version_or_reset(dep_version)?; - } - if let Some(last) = self.last.as_mut() { - last.validate_computed_version_or_reset(dep_version)?; - } - if let Some(min) = self.min.as_mut() { - min.validate_computed_version_or_reset(dep_version)?; - } - if let Some(max) = self.max.as_mut() { - max.validate_computed_version_or_reset(dep_version)?; - } - if let Some(median) = self.median.as_mut() { - median.validate_computed_version_or_reset(dep_version)?; - } - if let Some(average) = self.average.as_mut() { - average.validate_computed_version_or_reset(dep_version)?; - } - if let Some(sum) = self.sum.as_mut() { - sum.validate_computed_version_or_reset(dep_version)?; - } - if let Some(cumulative) = self.cumulative.as_mut() { - cumulative.validate_computed_version_or_reset(dep_version)?; - } - if let Some(pct90) = self.pct90.as_mut() { - pct90.validate_computed_version_or_reset(dep_version)?; - } - if let Some(pct75) = self.pct75.as_mut() { - pct75.validate_computed_version_or_reset(dep_version)?; - } - if let Some(pct25) = self.pct25.as_mut() { - pct25.validate_computed_version_or_reset(dep_version)?; - } - if let Some(pct10) = self.pct10.as_mut() { - pct10.validate_computed_version_or_reset(dep_version)?; - } - - Ok(()) - } -} - -#[derive(Default, Clone, Copy)] -pub struct VecBuilderOptions { - average: bool, - sum: bool, - max: bool, - pct90: bool, - pct75: bool, - median: bool, - pct25: bool, - pct10: bool, - min: bool, - first: bool, - last: bool, - cumulative: bool, -} - -impl VecBuilderOptions { - pub fn average(&self) -> bool { - self.average - } - - pub fn sum(&self) -> bool { - self.sum - } - - pub fn max(&self) -> bool { - self.max - } - - pub fn pct90(&self) -> bool { - self.pct90 - } - - pub fn pct75(&self) -> bool { - self.pct75 - } - - pub fn median(&self) -> bool { - self.median - } - - pub fn pct25(&self) -> bool { - self.pct25 - } - - pub fn pct10(&self) -> bool { - self.pct10 - } - - pub fn min(&self) -> bool { - self.min - } - - pub fn first(&self) -> bool { - self.first - } - - pub fn last(&self) -> bool { - self.last - } - - pub fn cumulative(&self) -> bool { - self.cumulative - } - - pub fn add_first(mut self) -> Self { - self.first = true; - self - } - - pub fn add_last(mut self) -> Self { - self.last = true; - self - } - - pub fn add_min(mut self) -> Self { - self.min = true; - self - } - - pub fn add_max(mut self) -> Self { - self.max = true; - self - } - - pub fn add_median(mut self) -> Self { - self.median = true; - self - } - - pub fn add_average(mut self) -> Self { - self.average = true; - self - } - - pub fn add_sum(mut self) -> Self { - self.sum = true; - self - } - - pub fn add_pct90(mut self) -> Self { - self.pct90 = true; - self - } - - pub fn add_pct75(mut self) -> Self { - self.pct75 = true; - self - } - - pub fn add_pct25(mut self) -> Self { - self.pct25 = true; - self - } - - pub fn add_pct10(mut self) -> Self { - self.pct10 = true; - self - } - - pub fn add_cumulative(mut self) -> Self { - self.cumulative = true; - self - } - - pub fn rm_min(mut self) -> Self { - self.min = false; - self - } - - pub fn rm_max(mut self) -> Self { - self.max = false; - self - } - - pub fn rm_median(mut self) -> Self { - self.median = false; - self - } - - pub fn rm_average(mut self) -> Self { - self.average = false; - self - } - - pub fn rm_sum(mut self) -> Self { - self.sum = false; - self - } - - pub fn rm_pct90(mut self) -> Self { - self.pct90 = false; - self - } - - pub fn rm_pct75(mut self) -> Self { - self.pct75 = false; - self - } - - pub fn rm_pct25(mut self) -> Self { - self.pct25 = false; - self - } - - pub fn rm_pct10(mut self) -> Self { - self.pct10 = false; - self - } - - pub fn rm_cumulative(mut self) -> Self { - self.cumulative = false; - self - } - - pub fn add_minmax(mut self) -> Self { - self.min = true; - self.max = true; - self - } - - pub fn add_percentiles(mut self) -> Self { - self.pct90 = true; - self.pct75 = true; - self.median = true; - self.pct25 = true; - self.pct10 = true; - self - } - - pub fn remove_percentiles(mut self) -> Self { - self.pct90 = false; - self.pct75 = false; - self.median = false; - self.pct25 = false; - self.pct10 = false; - self - } - - pub fn is_only_one_active(&self) -> bool { - [ - self.average, - self.sum, - self.max, - self.pct90, - self.pct75, - self.median, - self.pct25, - self.pct10, - self.min, - self.first, - self.last, - self.cumulative, - ] - .iter() - .filter(|b| **b) - .count() - == 1 - } - - pub fn copy_self_extra(&self) -> Self { - Self { - cumulative: self.cumulative, - ..Self::default() - } - } -} diff --git a/crates/brk_computer/src/internal/builder/lazy.rs b/crates/brk_computer/src/internal/builder/lazy.rs deleted file mode 100644 index 11dfe886b..000000000 --- a/crates/brk_computer/src/internal/builder/lazy.rs +++ /dev/null @@ -1,361 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::Version; -use schemars::JsonSchema; -use vecdb::{FromCoarserIndex, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2, VecIndex}; - -use crate::internal::{EagerVecsBuilder, VecBuilderOptions}; -use crate::utils::OptionExt; - -use super::super::ComputedVecValue; - -#[allow(clippy::type_complexity)] -#[derive(Clone, Traversable)] -pub struct LazyVecsBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema, - S1I: VecIndex, - S2T: ComputedVecValue, -{ - pub first: Option>>, - pub average: Option>>, - pub sum: Option>>, - pub max: Option>>, - pub min: Option>>, - pub last: Option>>, - pub cumulative: Option>>, -} - -const VERSION: Version = Version::ZERO; - -impl LazyVecsBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema + 'static, - S1I: VecIndex + 'static + FromCoarserIndex, - S2T: ComputedVecValue, -{ - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - name: &str, - version: Version, - source: Option>, - source_extra: &EagerVecsBuilder, - len_source: IterableBoxedVec, - options: LazyVecBuilderOptions, - ) -> Self { - let only_one_active = options.is_only_one_active(); - - let suffix = |s: &str| format!("{name}_{s}"); - - let maybe_suffix = |s: &str| { - if only_one_active { - name.to_string() - } else { - suffix(s) - } - }; - - Self { - first: options.first.then(|| { - Box::new(LazyVecFrom2::init( - &maybe_suffix("first"), - version + VERSION, - source_extra - .first - .as_ref() - .map_or_else(|| source.u().clone(), |v| v.clone()), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - source.get_at(S1I::min_from(i)) - }, - )) - }), - last: options.last.then(|| { - Box::new(LazyVecFrom2::init( - name, - version + VERSION, - source_extra.last.as_ref().map_or_else( - || { - source - .as_ref() - .unwrap_or_else(|| { - dbg!(name, I::to_string()); - panic!() - }) - .clone() - }, - |v| v.clone(), - ), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - source.get_at(S1I::max_from(i, source.vec_len())) - }, - )) - }), - min: options.min.then(|| { - Box::new(LazyVecFrom2::init( - &maybe_suffix("min"), - version + VERSION, - source_extra - .min - .as_ref() - .map_or_else(|| source.u().clone(), |v| v.clone()), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - S1I::inclusive_range_from(i, source.vec_len()) - .flat_map(|i| source.get_at(i)) - .min() - }, - )) - }), - max: options.max.then(|| { - Box::new(LazyVecFrom2::init( - &maybe_suffix("max"), - version + VERSION, - source_extra - .max - .as_ref() - .map_or_else(|| source.u().clone(), |v| v.clone()), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - S1I::inclusive_range_from(i, source.vec_len()) - .flat_map(|i| source.get_at(i)) - .max() - }, - )) - }), - average: options.average.then(|| { - Box::new(LazyVecFrom2::init( - &maybe_suffix("avg"), - version + VERSION, - source_extra - .average - .as_ref() - .map_or_else(|| source.u().clone(), |v| v.clone()), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - let mut sum = T::from(0); - let mut len = 0usize; - for v in S1I::inclusive_range_from(i, source.vec_len()) - .flat_map(|i| source.get_at(i)) - { - sum += v; - len += 1; - } - if len == 0 { - return None; - } - Some(sum / len) - }, - )) - }), - sum: options.sum.then(|| { - Box::new(LazyVecFrom2::init( - &(if !options.last && !options.average && !options.min && !options.max { - name.to_string() - } else { - maybe_suffix("sum") - }), - version + VERSION, - source_extra - .sum - .as_ref() - .map_or_else(|| source.u().clone(), |v| v.clone()), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - let mut sum = T::from(0); - let mut has_values = false; - for v in S1I::inclusive_range_from(i, source.vec_len()) - .flat_map(|i| source.get_at(i)) - { - sum += v; - has_values = true; - } - if !has_values { - return None; - } - Some(sum) - }, - )) - }), - cumulative: options.cumulative.then(|| { - Box::new(LazyVecFrom2::init( - &suffix("cumulative"), - version + VERSION, - source_extra.cumulative.u().boxed_clone(), - len_source.clone(), - |i: I, source, len_source| { - if i.to_usize() >= len_source.vec_len() { - return None; - } - source.get_at(S1I::max_from(i, source.vec_len())) - }, - )) - }), - } - } - - pub fn starting_index(&self, max_from: I) -> I { - max_from.min(I::from( - self.iter_any_exportable().map(|v| v.len()).min().unwrap(), - )) - } - - pub fn unwrap_first(&self) -> &LazyVecFrom2 { - self.first.u() - } - pub fn unwrap_average(&self) -> &LazyVecFrom2 { - self.average.u() - } - pub fn unwrap_sum(&self) -> &LazyVecFrom2 { - self.sum.u() - } - pub fn unwrap_max(&self) -> &LazyVecFrom2 { - self.max.u() - } - pub fn unwrap_min(&self) -> &LazyVecFrom2 { - self.min.u() - } - pub fn unwrap_last(&self) -> &LazyVecFrom2 { - self.last.u() - } - pub fn unwrap_cumulative(&self) -> &LazyVecFrom2 { - self.cumulative.u() - } -} - -#[derive(Default, Clone, Copy)] -pub struct LazyVecBuilderOptions { - average: bool, - sum: bool, - max: bool, - min: bool, - first: bool, - last: bool, - cumulative: bool, -} - -impl From for LazyVecBuilderOptions { - #[inline] - fn from(value: VecBuilderOptions) -> Self { - Self { - average: value.average(), - sum: value.sum(), - max: value.max(), - min: value.min(), - first: value.first(), - last: value.last(), - cumulative: value.cumulative(), - } - } -} - -impl LazyVecBuilderOptions { - pub fn add_first(mut self) -> Self { - self.first = true; - self - } - - pub fn add_last(mut self) -> Self { - self.last = true; - self - } - - pub fn add_min(mut self) -> Self { - self.min = true; - self - } - - pub fn add_max(mut self) -> Self { - self.max = true; - self - } - - pub fn add_average(mut self) -> Self { - self.average = true; - self - } - - pub fn add_sum(mut self) -> Self { - self.sum = true; - self - } - - pub fn add_cumulative(mut self) -> Self { - self.cumulative = true; - self - } - - pub fn rm_min(mut self) -> Self { - self.min = false; - self - } - - pub fn rm_max(mut self) -> Self { - self.max = false; - self - } - - pub fn rm_average(mut self) -> Self { - self.average = false; - self - } - - pub fn rm_sum(mut self) -> Self { - self.sum = false; - self - } - - pub fn rm_cumulative(mut self) -> Self { - self.cumulative = false; - self - } - - pub fn add_minmax(mut self) -> Self { - self.min = true; - self.max = true; - self - } - - pub fn is_only_one_active(&self) -> bool { - [ - self.average, - self.sum, - self.max, - self.min, - self.first, - self.last, - self.cumulative, - ] - .iter() - .filter(|b| **b) - .count() - == 1 - } - - pub fn copy_self_extra(&self) -> Self { - Self { - cumulative: self.cumulative, - ..Self::default() - } - } -} diff --git a/crates/brk_computer/src/internal/builder/mod.rs b/crates/brk_computer/src/internal/builder/mod.rs deleted file mode 100644 index 43bac8ca2..000000000 --- a/crates/brk_computer/src/internal/builder/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod eager; -mod lazy; -mod transform; -mod transform2; - -pub use eager::*; -pub use lazy::*; -pub use transform::*; -pub use transform2::*; diff --git a/crates/brk_computer/src/internal/builder/transform.rs b/crates/brk_computer/src/internal/builder/transform.rs deleted file mode 100644 index d27b260ce..000000000 --- a/crates/brk_computer/src/internal/builder/transform.rs +++ /dev/null @@ -1,224 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::Version; -use schemars::JsonSchema; -use vecdb::{IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex}; - -use super::{ - super::ComputedVecValue, - eager::EagerVecsBuilder, - lazy::LazyVecsBuilder, -}; - -const VERSION: Version = Version::ZERO; - -/// Lazy transform version of `EagerVecsBuilder`. -/// Each group is a `LazyVecFrom1` that transforms from the corresponding stored group. -/// S1T is the source type, T is the output type (can be the same for transforms like negation). -#[derive(Clone, Traversable)] -pub struct LazyTransformBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, -{ - pub first: Option>>, - pub average: Option>>, - pub sum: Option>>, - pub max: Option>>, - pub pct90: Option>>, - pub pct75: Option>>, - pub median: Option>>, - pub pct25: Option>>, - pub pct10: Option>>, - pub min: Option>>, - pub last: Option>>, - pub cumulative: Option>>, -} - -impl LazyTransformBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, -{ - /// Create a lazy transform from a stored `EagerVecsBuilder`. - /// F is the transform type (e.g., `Negate`, `Halve`). - pub fn from_eager>( - name: &str, - version: Version, - source: &EagerVecsBuilder, - ) -> Self { - let v = version + VERSION; - let suffix = |s: &str| format!("{name}_{s}"); - Self { - first: source.first.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("first"), - v, - s.boxed_clone(), - )) - }), - average: source.average.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("avg"), - v, - s.boxed_clone(), - )) - }), - sum: source.sum.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("sum"), - v, - s.boxed_clone(), - )) - }), - max: source.max.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("max"), - v, - s.boxed_clone(), - )) - }), - pct90: source.pct90.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("pct90"), - v, - s.boxed_clone(), - )) - }), - pct75: source.pct75.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("pct75"), - v, - s.boxed_clone(), - )) - }), - median: source.median.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("median"), - v, - s.boxed_clone(), - )) - }), - pct25: source.pct25.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("pct25"), - v, - s.boxed_clone(), - )) - }), - pct10: source.pct10.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("pct10"), - v, - s.boxed_clone(), - )) - }), - min: source.min.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("min"), - v, - s.boxed_clone(), - )) - }), - last: source - .last - .as_ref() - .map(|s| Box::new(LazyVecFrom1::transformed::(name, v, s.boxed_clone()))), - cumulative: source.cumulative.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("cumulative"), - v, - s.boxed_clone(), - )) - }), - } - } -} - -impl LazyTransformBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, -{ - pub fn unwrap_sum(&self) -> &LazyVecFrom1 { - self.sum.as_ref().unwrap() - } - - pub fn unwrap_cumulative(&self) -> &LazyVecFrom1 { - self.cumulative.as_ref().unwrap() - } -} - -impl LazyTransformBuilder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, -{ - /// Create a lazy transform from a `LazyVecsBuilder`. - /// Note: LazyVecsBuilder doesn't have percentiles, so those will be None. - pub fn from_lazy, S1I: VecIndex, S2T: ComputedVecValue>( - name: &str, - version: Version, - source: &LazyVecsBuilder, - ) -> Self { - let v = version + VERSION; - // Use same suffix pattern as EagerVecsBuilder - let suffix = |s: &str| format!("{name}_{s}"); - Self { - first: source.first.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("first"), - v, - s.boxed_clone(), - )) - }), - average: source.average.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("avg"), - v, - s.boxed_clone(), - )) - }), - sum: source.sum.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("sum"), - v, - s.boxed_clone(), - )) - }), - max: source.max.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("max"), - v, - s.boxed_clone(), - )) - }), - pct90: None, - pct75: None, - median: None, - pct25: None, - pct10: None, - min: source.min.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("min"), - v, - s.boxed_clone(), - )) - }), - last: source - .last - .as_ref() - .map(|s| Box::new(LazyVecFrom1::transformed::(name, v, s.boxed_clone()))), - cumulative: source.cumulative.as_ref().map(|s| { - Box::new(LazyVecFrom1::transformed::( - &suffix("cumulative"), - v, - s.boxed_clone(), - )) - }), - } - } -} diff --git a/crates/brk_computer/src/internal/builder/transform2.rs b/crates/brk_computer/src/internal/builder/transform2.rs deleted file mode 100644 index 88d5321d9..000000000 --- a/crates/brk_computer/src/internal/builder/transform2.rs +++ /dev/null @@ -1,240 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::Version; -use schemars::JsonSchema; -use vecdb::{BinaryTransform, IterableCloneableVec, LazyVecFrom2, VecIndex}; - -use super::{ - super::ComputedVecValue, - eager::EagerVecsBuilder, - lazy::LazyVecsBuilder, -}; - -const VERSION: Version = Version::ZERO; - -/// Lazy binary transform builder. -/// Each group is a `LazyVecFrom2` that transforms from two corresponding stored groups. -#[derive(Clone, Traversable)] -#[allow(clippy::type_complexity)] -pub struct LazyTransform2Builder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, - S2T: ComputedVecValue, -{ - pub first: Option>>, - pub average: Option>>, - pub sum: Option>>, - pub max: Option>>, - pub min: Option>>, - pub last: Option>>, - pub cumulative: Option>>, -} - -impl LazyTransform2Builder -where - I: VecIndex, - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, - S2T: ComputedVecValue + JsonSchema, -{ - /// Create a lazy binary transform from two stored `EagerVecsBuilder`. - pub fn from_eager>( - name: &str, - version: Version, - source1: &EagerVecsBuilder, - source2: &EagerVecsBuilder, - ) -> Self { - let v = version + VERSION; - let suffix = |s: &str| format!("{name}_{s}"); - Self { - first: source1 - .first - .as_ref() - .zip(source2.first.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("first"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - average: source1 - .average - .as_ref() - .zip(source2.average.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("avg"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - sum: source1 - .sum - .as_ref() - .zip(source2.sum.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("sum"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - max: source1 - .max - .as_ref() - .zip(source2.max.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("max"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - min: source1 - .min - .as_ref() - .zip(source2.min.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("min"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - last: source1 - .last - .as_ref() - .zip(source2.last.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - name, - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - cumulative: source1 - .cumulative - .as_ref() - .zip(source2.cumulative.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("cumulative"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - } - } - - /// Create a lazy binary transform from two `LazyVecsBuilder`. - pub fn from_lazy< - F: BinaryTransform, - S1I: VecIndex, - S1E: ComputedVecValue, - S2I: VecIndex, - S2E: ComputedVecValue, - >( - name: &str, - version: Version, - source1: &LazyVecsBuilder, - source2: &LazyVecsBuilder, - ) -> Self { - let v = version + VERSION; - let suffix = |s: &str| format!("{name}_{s}"); - Self { - first: source1 - .first - .as_ref() - .zip(source2.first.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("first"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - average: source1 - .average - .as_ref() - .zip(source2.average.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("avg"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - sum: source1 - .sum - .as_ref() - .zip(source2.sum.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("sum"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - max: source1 - .max - .as_ref() - .zip(source2.max.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("max"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - min: source1 - .min - .as_ref() - .zip(source2.min.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("min"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - last: source1 - .last - .as_ref() - .zip(source2.last.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - name, - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - cumulative: source1 - .cumulative - .as_ref() - .zip(source2.cumulative.as_ref()) - .map(|(s1, s2)| { - Box::new(LazyVecFrom2::transformed::( - &suffix("cumulative"), - v, - s1.boxed_clone(), - s2.boxed_clone(), - )) - }), - } - } -} diff --git a/crates/brk_computer/src/internal/compute.rs b/crates/brk_computer/src/internal/compute.rs new file mode 100644 index 000000000..e6312045b --- /dev/null +++ b/crates/brk_computer/src/internal/compute.rs @@ -0,0 +1,521 @@ +//! Compute functions for aggregation - take optional vecs, compute what's needed. +//! +//! These functions replace the Option-based compute logic in flexible builders. +//! Each function takes optional mutable references and computes only for Some() vecs. + +use brk_error::{Error, Result}; +use brk_types::{CheckedSub, StoredU64}; +use schemars::JsonSchema; +use vecdb::{ + AnyStoredVec, AnyVec, EagerVec, Exit, GenericStoredVec, IterableVec, PcoVec, VecIndex, VecValue, +}; + +use crate::utils::get_percentile; + +use super::ComputedVecValue; + +/// Helper to validate and get starting index for a single vec +fn validate_and_start( + vec: &mut EagerVec>, + combined_version: vecdb::Version, + current_start: I, +) -> Result { + vec.validate_computed_version_or_reset(combined_version)?; + Ok(current_start.min(I::from(vec.len()))) +} + +/// Compute aggregations from a source vec into target vecs. +/// +/// This function computes all requested aggregations in a single pass when possible, +/// optimizing for the common case where multiple aggregations are needed. +#[allow(clippy::too_many_arguments)] +pub fn compute_aggregations( + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + mut first: Option<&mut EagerVec>>, + mut last: Option<&mut EagerVec>>, + mut min: Option<&mut EagerVec>>, + mut max: Option<&mut EagerVec>>, + mut average: Option<&mut EagerVec>>, + mut sum: Option<&mut EagerVec>>, + mut cumulative: Option<&mut EagerVec>>, + mut median: Option<&mut EagerVec>>, + mut pct10: Option<&mut EagerVec>>, + mut pct25: Option<&mut EagerVec>>, + mut pct75: Option<&mut EagerVec>>, + mut pct90: Option<&mut EagerVec>>, +) -> Result<()> +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + A: VecIndex + VecValue + CheckedSub, +{ + let combined_version = source.version() + first_indexes.version() + count_indexes.version(); + + let mut starting_index = max_from; + + if let Some(ref mut v) = first { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = last { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = min { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = max { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = average { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = sum { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = cumulative { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = median { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = pct10 { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = pct25 { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = pct75 { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = pct90 { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + + let index = starting_index; + + let needs_first = first.is_some(); + let needs_last = last.is_some(); + let needs_min = min.is_some(); + let needs_max = max.is_some(); + let needs_average = average.is_some(); + let needs_sum = sum.is_some(); + let needs_cumulative = cumulative.is_some(); + let needs_percentiles = median.is_some() + || pct10.is_some() + || pct25.is_some() + || pct75.is_some() + || pct90.is_some(); + let needs_minmax = needs_min || needs_max; + let needs_sum_or_cumulative = needs_sum || needs_cumulative; + let needs_aggregates = needs_sum_or_cumulative || needs_average; + + if !needs_first && !needs_last && !needs_minmax && !needs_aggregates && !needs_percentiles { + return Ok(()); + } + + let mut source_iter = source.iter(); + + let mut cumulative_val = cumulative.as_ref().map(|cumulative_vec| { + index.decremented().map_or(T::from(0_usize), |idx| { + cumulative_vec.iter().get_unwrap(idx) + }) + }); + + let mut count_indexes_iter = count_indexes.iter().skip(index.to_usize()); + + first_indexes + .iter() + .enumerate() + .skip(index.to_usize()) + .try_for_each(|(idx, first_index)| -> Result<()> { + let count_index = count_indexes_iter.next().unwrap(); + let count = *count_index as usize; + + if let Some(ref mut first_vec) = first { + let f = source_iter + .get(first_index) + .unwrap_or_else(|| T::from(0_usize)); + first_vec.truncate_push_at(idx, f)?; + } + + if let Some(ref mut last_vec) = last { + if count == 0 { + panic!("should not compute last if count can be 0"); + } + let last_index = first_index + (count - 1); + let v = source_iter.get_unwrap(last_index); + last_vec.truncate_push_at(idx, v)?; + } + + // Fast path: only min/max needed, no sorting or allocation required + if needs_minmax && !needs_percentiles && !needs_aggregates { + source_iter.set_position(first_index); + let mut min_val: Option = None; + let mut max_val: Option = None; + + for val in (&mut source_iter).take(count) { + if needs_min { + min_val = Some(min_val.map_or(val, |m| if val < m { val } else { m })); + } + if needs_max { + max_val = Some(max_val.map_or(val, |m| if val > m { val } else { m })); + } + } + + if let Some(ref mut min_vec) = min { + min_vec.truncate_push_at(idx, min_val.unwrap())?; + } + if let Some(ref mut max_vec) = max { + max_vec.truncate_push_at(idx, max_val.unwrap())?; + } + } else if needs_percentiles || needs_aggregates || needs_minmax { + source_iter.set_position(first_index); + let mut values: Vec = (&mut source_iter).take(count).collect(); + + if needs_percentiles { + values.sort_unstable(); + + if let Some(ref mut max_vec) = max { + max_vec.truncate_push_at( + idx, + *values + .last() + .ok_or(Error::Internal("Empty values for percentiles"))?, + )?; + } + if let Some(ref mut pct90_vec) = pct90 { + pct90_vec.truncate_push_at(idx, get_percentile(&values, 0.90))?; + } + if let Some(ref mut pct75_vec) = pct75 { + pct75_vec.truncate_push_at(idx, get_percentile(&values, 0.75))?; + } + if let Some(ref mut median_vec) = median { + median_vec.truncate_push_at(idx, get_percentile(&values, 0.50))?; + } + if let Some(ref mut pct25_vec) = pct25 { + pct25_vec.truncate_push_at(idx, get_percentile(&values, 0.25))?; + } + if let Some(ref mut pct10_vec) = pct10 { + pct10_vec.truncate_push_at(idx, get_percentile(&values, 0.10))?; + } + if let Some(ref mut min_vec) = min { + min_vec.truncate_push_at(idx, *values.first().unwrap())?; + } + } else if needs_minmax { + if let Some(ref mut min_vec) = min { + min_vec.truncate_push_at(idx, *values.iter().min().unwrap())?; + } + if let Some(ref mut max_vec) = max { + max_vec.truncate_push_at(idx, *values.iter().max().unwrap())?; + } + } + + if needs_aggregates { + let len = values.len(); + let sum_val = values.into_iter().fold(T::from(0), |a, b| a + b); + + if let Some(ref mut average_vec) = average { + average_vec.truncate_push_at(idx, sum_val / len)?; + } + + if needs_sum_or_cumulative { + if let Some(ref mut sum_vec) = sum { + sum_vec.truncate_push_at(idx, sum_val)?; + } + if let Some(ref mut cumulative_vec) = cumulative { + let t = cumulative_val.unwrap() + sum_val; + cumulative_val.replace(t); + cumulative_vec.truncate_push_at(idx, t)?; + } + } + } + } + + Ok(()) + })?; + + let _lock = exit.lock(); + + if let Some(v) = first { + v.write()?; + } + if let Some(v) = last { + v.write()?; + } + if let Some(v) = min { + v.write()?; + } + if let Some(v) = max { + v.write()?; + } + if let Some(v) = average { + v.write()?; + } + if let Some(v) = sum { + v.write()?; + } + if let Some(v) = cumulative { + v.write()?; + } + if let Some(v) = median { + v.write()?; + } + if let Some(v) = pct10 { + v.write()?; + } + if let Some(v) = pct25 { + v.write()?; + } + if let Some(v) = pct75 { + v.write()?; + } + if let Some(v) = pct90 { + v.write()?; + } + + Ok(()) +} + +/// Compute cumulative extension from a source vec. +/// +/// Used when only cumulative needs to be extended from an existing source. +pub fn compute_cumulative_extend( + max_from: I, + source: &impl IterableVec, + cumulative: &mut EagerVec>, + exit: &Exit, +) -> Result<()> +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, +{ + cumulative.validate_computed_version_or_reset(source.version())?; + + let index = max_from.min(I::from(cumulative.len())); + + let mut cumulative_val = index + .decremented() + .map_or(T::from(0_usize), |idx| cumulative.iter().get_unwrap(idx)); + + source + .iter() + .enumerate() + .skip(index.to_usize()) + .try_for_each(|(i, v)| -> Result<()> { + cumulative_val += v; + cumulative.truncate_push_at(i, cumulative_val)?; + Ok(()) + })?; + + let _lock = exit.lock(); + cumulative.write()?; + + Ok(()) +} + +/// Compute coarser aggregations from already-aggregated source data. +/// +/// This is used for dateindex → weekindex, monthindex, etc. where we derive +/// coarser aggregations from finer ones. +/// +/// NOTE: Percentiles are NOT supported - they cannot be derived from finer percentiles. +#[allow(clippy::too_many_arguments)] +pub fn compute_aggregations_from_aligned( + max_from: I, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + // Source vecs (already aggregated at finer level) + source_first: Option<&EagerVec>>, + source_last: Option<&EagerVec>>, + source_min: Option<&EagerVec>>, + source_max: Option<&EagerVec>>, + source_average: Option<&EagerVec>>, + source_sum: Option<&EagerVec>>, + // Target vecs + mut first: Option<&mut EagerVec>>, + mut last: Option<&mut EagerVec>>, + mut min: Option<&mut EagerVec>>, + mut max: Option<&mut EagerVec>>, + mut average: Option<&mut EagerVec>>, + mut sum: Option<&mut EagerVec>>, + mut cumulative: Option<&mut EagerVec>>, +) -> Result<()> +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + A: VecIndex + VecValue + CheckedSub, +{ + let combined_version = first_indexes.version() + count_indexes.version(); + + let mut starting_index = max_from; + + if let Some(ref mut v) = first { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = last { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = min { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = max { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = average { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = sum { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + if let Some(ref mut v) = cumulative { + starting_index = validate_and_start(v, combined_version, starting_index)?; + } + + let index = starting_index; + + let needs_first = first.is_some(); + let needs_last = last.is_some(); + let needs_min = min.is_some(); + let needs_max = max.is_some(); + let needs_average = average.is_some(); + let needs_sum = sum.is_some(); + let needs_cumulative = cumulative.is_some(); + + if !needs_first + && !needs_last + && !needs_min + && !needs_max + && !needs_average + && !needs_sum + && !needs_cumulative + { + return Ok(()); + } + + let mut source_first_iter = source_first.map(|f| f.iter()); + let mut source_last_iter = source_last.map(|f| f.iter()); + let mut source_min_iter = source_min.map(|f| f.iter()); + let mut source_max_iter = source_max.map(|f| f.iter()); + let mut source_average_iter = source_average.map(|f| f.iter()); + let mut source_sum_iter = source_sum.map(|f| f.iter()); + + let mut cumulative_val = cumulative.as_ref().map(|cumulative_vec| { + index.decremented().map_or(T::from(0_usize), |idx| { + cumulative_vec.iter().get_unwrap(idx) + }) + }); + + let mut count_indexes_iter = count_indexes.iter().skip(index.to_usize()); + + first_indexes + .iter() + .enumerate() + .skip(index.to_usize()) + .try_for_each(|(idx, first_index)| -> Result<()> { + let count_index = count_indexes_iter.next().unwrap(); + let count = *count_index as usize; + + if let Some(ref mut first_vec) = first { + let source_iter = source_first_iter + .as_mut() + .expect("source_first required for first"); + let v = source_iter.get_unwrap(first_index); + first_vec.truncate_push_at(idx, v)?; + } + + if let Some(ref mut last_vec) = last { + if count == 0 { + panic!("should not compute last if count can be 0"); + } + let last_index = first_index + (count - 1); + let source_iter = source_last_iter + .as_mut() + .expect("source_last required for last"); + let v = source_iter.get_unwrap(last_index); + last_vec.truncate_push_at(idx, v)?; + } + + if let Some(ref mut min_vec) = min { + let source_iter = source_min_iter + .as_mut() + .expect("source_min required for min"); + source_iter.set_position(first_index); + let min_val = source_iter.take(count).min().unwrap(); + min_vec.truncate_push_at(idx, min_val)?; + } + + if let Some(ref mut max_vec) = max { + let source_iter = source_max_iter + .as_mut() + .expect("source_max required for max"); + source_iter.set_position(first_index); + let max_val = source_iter.take(count).max().unwrap(); + max_vec.truncate_push_at(idx, max_val)?; + } + + if let Some(ref mut average_vec) = average { + let source_iter = source_average_iter + .as_mut() + .expect("source_average required for average"); + source_iter.set_position(first_index); + let mut len = 0usize; + let sum_val = (&mut *source_iter) + .take(count) + .inspect(|_| len += 1) + .fold(T::from(0), |a, b| a + b); + // TODO: Multiply by count then divide by cumulative for accuracy + let average = sum_val / len; + average_vec.truncate_push_at(idx, average)?; + } + + if needs_sum || needs_cumulative { + let source_iter = source_sum_iter + .as_mut() + .expect("source_sum required for sum/cumulative"); + source_iter.set_position(first_index); + let sum_val = source_iter.take(count).fold(T::from(0), |a, b| a + b); + + if let Some(ref mut sum_vec) = sum { + sum_vec.truncate_push_at(idx, sum_val)?; + } + + if let Some(ref mut cumulative_vec) = cumulative { + let t = cumulative_val.unwrap() + sum_val; + cumulative_val.replace(t); + cumulative_vec.truncate_push_at(idx, t)?; + } + } + + Ok(()) + })?; + + let _lock = exit.lock(); + + if let Some(v) = first { + v.write()?; + } + if let Some(v) = last { + v.write()?; + } + if let Some(v) = min { + v.write()?; + } + if let Some(v) = max { + v.write()?; + } + if let Some(v) = average { + v.write()?; + } + if let Some(v) = sum { + v.write()?; + } + if let Some(v) = cumulative { + v.write()?; + } + + Ok(()) +} diff --git a/crates/brk_computer/src/internal/computed/block/full.rs b/crates/brk_computer/src/internal/computed/block/full.rs new file mode 100644 index 000000000..a563e44b6 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/block/full.rs @@ -0,0 +1,69 @@ +//! ComputedBlock with full stats aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockFull, NumericValue}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedBlockFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + #[traversable(wrap = "base")] + pub height: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedComputedBlockFull, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedBlockFull +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let rest = DerivedComputedBlockFull::forced_import( + db, + name, + height.boxed_clone(), + v, + indexes, + )?; + + Ok(Self { height, rest }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + self.rest.derive_from(indexes, starting_indexes, &self.height, exit) + } +} diff --git a/crates/brk_computer/src/internal/computed/block/last.rs b/crates/brk_computer/src/internal/computed/block/last.rs new file mode 100644 index 000000000..0919fcf67 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/block/last.rs @@ -0,0 +1,64 @@ +//! ComputedBlock using only LastVec aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockLast, NumericValue}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedBlockLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedComputedBlockLast, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedBlockLast +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let rest = + DerivedComputedBlockLast::forced_import(db, name, height.boxed_clone(), v, indexes)?; + + Ok(Self { height, rest }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + self.rest + .derive_from(indexes, starting_indexes, &self.height, exit) + } +} diff --git a/crates/brk_computer/src/internal/computed/block/mod.rs b/crates/brk_computer/src/internal/computed/block/mod.rs new file mode 100644 index 000000000..f51ca8c58 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/block/mod.rs @@ -0,0 +1,13 @@ +//! Block-level computed types (height + dateindex + periods + difficultyepoch). +//! +//! For simpler chain-level types (height + difficultyepoch only), see `chain/`. + +mod full; +mod last; +mod sum; +mod sum_cum; + +pub use full::*; +pub use last::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/computed/block/sum.rs b/crates/brk_computer/src/internal/computed/block/sum.rs new file mode 100644 index 000000000..6af803919 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/block/sum.rs @@ -0,0 +1,69 @@ +//! ComputedBlock using Sum-only aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockSum, NumericValue}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedBlockSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + #[traversable(wrap = "base")] + pub height: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedComputedBlockSum, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedBlockSum +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let rest = DerivedComputedBlockSum::forced_import( + db, + name, + height.boxed_clone(), + v, + indexes, + )?; + + Ok(Self { height, rest }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + self.rest.derive_from(indexes, starting_indexes, &self.height, exit) + } +} diff --git a/crates/brk_computer/src/internal/computed/block/sum_cum.rs b/crates/brk_computer/src/internal/computed/block/sum_cum.rs new file mode 100644 index 000000000..e2e899bc2 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/block/sum_cum.rs @@ -0,0 +1,97 @@ +//! ComputedBlock using SumCum aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{ + AnyStoredVec, AnyVec, Database, EagerVec, Exit, GenericStoredVec, ImportableVec, + IterableCloneableVec, IterableVec, PcoVec, VecIndex, +}; + +use crate::{indexes, ComputeIndexes}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockSumCum, NumericValue}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedBlockSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + #[traversable(wrap = "base")] + pub height: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedComputedBlockSumCum, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedBlockSumCum +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let rest = DerivedComputedBlockSumCum::forced_import( + db, + name, + height.boxed_clone(), + v, + indexes, + )?; + + Ok(Self { height, rest }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + self.rest.derive_from(indexes, starting_indexes, &self.height, exit) + } + + /// Derive from an external height source (e.g., a LazyVec). + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + let target_len = source.len(); + let starting_height = starting_indexes.height.to_usize().min(self.height.len()); + + self.height + .validate_computed_version_or_reset(source.version())?; + + let mut source_iter = source.iter(); + for h_idx in starting_height..target_len { + let height = Height::from(h_idx); + let value = source_iter.get_unwrap(height); + self.height.truncate_push(height, value)?; + } + self.height.write()?; + + self.rest.derive_from(indexes, starting_indexes, &self.height, exit) + } +} diff --git a/crates/brk_computer/src/internal/computed/chain/first.rs b/crates/brk_computer/src/internal/computed/chain/first.rs new file mode 100644 index 000000000..b2d68d8a0 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/chain/first.rs @@ -0,0 +1,68 @@ +//! ComputedChain for first-value aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Height, Version}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, LazyFirst, NumericValue}; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct ComputedChainFirst +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: EagerVec>, + pub difficultyepoch: LazyFirst, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedChainFirst +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let difficultyepoch = LazyFirst::from_source( + name, + v, + height.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + Ok(Self { + height, + difficultyepoch, + }) + } + + pub fn compute( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/chain/last.rs b/crates/brk_computer/src/internal/computed/chain/last.rs new file mode 100644 index 000000000..bd3a0b90c --- /dev/null +++ b/crates/brk_computer/src/internal/computed/chain/last.rs @@ -0,0 +1,68 @@ +//! ComputedChain for last-value aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Height, Version}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, LazyLast, NumericValue}; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct ComputedChainLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: EagerVec>, + pub difficultyepoch: LazyLast, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedChainLast +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let difficultyepoch = LazyLast::from_source( + name, + v, + height.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + Ok(Self { + height, + difficultyepoch, + }) + } + + pub fn compute( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/chain/max.rs b/crates/brk_computer/src/internal/computed/chain/max.rs new file mode 100644 index 000000000..3308641b7 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/chain/max.rs @@ -0,0 +1,68 @@ +//! ComputedChain for max-value aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Height, Version}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, LazyMax, NumericValue}; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct ComputedChainMax +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: EagerVec>, + pub difficultyepoch: LazyMax, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedChainMax +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let difficultyepoch = LazyMax::from_source( + name, + v, + height.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + Ok(Self { + height, + difficultyepoch, + }) + } + + pub fn compute( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/chain/min.rs b/crates/brk_computer/src/internal/computed/chain/min.rs new file mode 100644 index 000000000..f71569941 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/chain/min.rs @@ -0,0 +1,68 @@ +//! ComputedChain for min-value aggregation. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Height, Version}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, LazyMin, NumericValue}; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct ComputedChainMin +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: EagerVec>, + pub difficultyepoch: LazyMin, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedChainMin +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height: EagerVec> = EagerVec::forced_import(db, name, v)?; + + let difficultyepoch = LazyMin::from_source( + name, + v, + height.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + Ok(Self { + height, + difficultyepoch, + }) + } + + pub fn compute( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.height)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/chain/mod.rs b/crates/brk_computer/src/internal/computed/chain/mod.rs new file mode 100644 index 000000000..660f8353a --- /dev/null +++ b/crates/brk_computer/src/internal/computed/chain/mod.rs @@ -0,0 +1,13 @@ +//! Chain-level computed types (height + difficultyepoch only). +//! +//! These are simpler than block-level types which include dateindex + periods. + +mod first; +mod last; +mod max; +mod min; + +pub use first::*; +pub use last::*; +pub use max::*; +pub use min::*; diff --git a/crates/brk_computer/src/internal/computed/date/average.rs b/crates/brk_computer/src/internal/computed/date/average.rs new file mode 100644 index 000000000..b337f5737 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/date/average.rs @@ -0,0 +1,64 @@ +//! ComputedVecsDate using only average-value aggregation. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedDateAverage}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedVecsDateAverage +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedDateAverage, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedVecsDateAverage +where + T: ComputedVecValue + JsonSchema + 'static, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = EagerVec::forced_import(db, name, version + VERSION)?; + + Ok(Self { + rest: DerivedDateAverage::from_source( + name, + version + VERSION, + dateindex.boxed_clone(), + indexes, + ), + dateindex, + }) + } + + pub fn compute_all( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.dateindex)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/date/first.rs b/crates/brk_computer/src/internal/computed/date/first.rs new file mode 100644 index 000000000..63e0bb3df --- /dev/null +++ b/crates/brk_computer/src/internal/computed/date/first.rs @@ -0,0 +1,64 @@ +//! ComputedVecsDate using only first-value aggregation. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedDateFirst}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedVecsDateFirst +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedDateFirst, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedVecsDateFirst +where + T: ComputedVecValue + JsonSchema + 'static, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = EagerVec::forced_import(db, name, version + VERSION)?; + + Ok(Self { + rest: DerivedDateFirst::from_source( + name, + version + VERSION, + dateindex.boxed_clone(), + indexes, + ), + dateindex, + }) + } + + pub fn compute_all( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.dateindex)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/date/last.rs b/crates/brk_computer/src/internal/computed/date/last.rs new file mode 100644 index 000000000..720261ac1 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/date/last.rs @@ -0,0 +1,73 @@ +//! ComputedVecsDate using only last-value aggregation. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, IterableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedDateLast}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedDateLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedDateLast, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedDateLast +where + T: ComputedVecValue + JsonSchema + 'static, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = EagerVec::forced_import(db, name, version + VERSION)?; + + Ok(Self { + rest: DerivedDateLast::from_source( + name, + version + VERSION, + dateindex.boxed_clone(), + indexes, + ), + dateindex, + }) + } + + pub fn compute_all( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.dateindex)?; + Ok(()) + } + + pub fn compute_rest( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + _dateindex: Option<&impl IterableVec>, + ) -> Result<()> { + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/date/max.rs b/crates/brk_computer/src/internal/computed/date/max.rs new file mode 100644 index 000000000..865a1e00e --- /dev/null +++ b/crates/brk_computer/src/internal/computed/date/max.rs @@ -0,0 +1,64 @@ +//! ComputedVecsDate using only max-value aggregation. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedDateMax}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedVecsDateMax +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedDateMax, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedVecsDateMax +where + T: ComputedVecValue + JsonSchema + 'static, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = EagerVec::forced_import(db, name, version + VERSION)?; + + Ok(Self { + rest: DerivedDateMax::from_source( + name, + version + VERSION, + dateindex.boxed_clone(), + indexes, + ), + dateindex, + }) + } + + pub fn compute_all( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.dateindex)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/date/min.rs b/crates/brk_computer/src/internal/computed/date/min.rs new file mode 100644 index 000000000..1fc1d8dbc --- /dev/null +++ b/crates/brk_computer/src/internal/computed/date/min.rs @@ -0,0 +1,64 @@ +//! ComputedVecsDate using only min-value aggregation. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes}; + +use crate::internal::{ComputedVecValue, DerivedDateMin}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedVecsDateMin +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: DerivedDateMin, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedVecsDateMin +where + T: ComputedVecValue + JsonSchema + 'static, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = EagerVec::forced_import(db, name, version + VERSION)?; + + Ok(Self { + rest: DerivedDateMin::from_source( + name, + version + VERSION, + dateindex.boxed_clone(), + indexes, + ), + dateindex, + }) + } + + pub fn compute_all( + &mut self, + _starting_indexes: &ComputeIndexes, + _exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.dateindex)?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/date/mod.rs b/crates/brk_computer/src/internal/computed/date/mod.rs new file mode 100644 index 000000000..bbebb8746 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/date/mod.rs @@ -0,0 +1,11 @@ +mod average; +mod first; +mod last; +mod max; +mod min; + +pub use average::*; +pub use first::*; +pub use last::*; +pub use max::*; +pub use min::*; diff --git a/crates/brk_computer/src/internal/computed/derived_block/distribution.rs b/crates/brk_computer/src/internal/computed/derived_block/distribution.rs new file mode 100644 index 000000000..2c24d4131 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/derived_block/distribution.rs @@ -0,0 +1,93 @@ +//! DerivedComputedBlockDistribution - dateindex storage + lazy time periods + difficultyepoch. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, Exit, IterableBoxedVec, IterableCloneableVec, IterableVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ + ComputedVecValue, DerivedDateDistribution, Distribution, LazyDistribution, NumericValue, + }, +}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DerivedComputedBlockDistribution +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: Distribution, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateDistribution, + pub difficultyepoch: LazyDistribution, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedComputedBlockDistribution +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + height_source: IterableBoxedVec, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = Distribution::forced_import(db, name, version + VERSION)?; + let v = version + VERSION; + + let dates = DerivedDateDistribution::from_sources( + name, + v, + dateindex.average.0.boxed_clone(), + dateindex.minmax.min.0.boxed_clone(), + dateindex.minmax.max.0.boxed_clone(), + indexes, + ); + + let difficultyepoch = LazyDistribution::from_distribution( + name, + v, + height_source.boxed_clone(), + height_source.boxed_clone(), + height_source, + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + Ok(Self { + dateindex, + dates, + difficultyepoch, + }) + } + + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + height_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + self.dateindex.compute( + starting_indexes.dateindex, + height_source, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/derived_block/full.rs b/crates/brk_computer/src/internal/computed/derived_block/full.rs new file mode 100644 index 000000000..9affef961 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/derived_block/full.rs @@ -0,0 +1,110 @@ +//! DerivedComputedBlockFull - height_cumulative + dateindex storage + difficultyepoch + lazy time periods. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, Exit, IterableBoxedVec, IterableCloneableVec, IterableVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ + ComputedVecValue, CumulativeVec, DerivedDateFull, Full, LazyFull, NumericValue, + compute_cumulative_extend, + }, +}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DerivedComputedBlockFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height_cumulative: CumulativeVec, + pub dateindex: Full, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateFull, + pub difficultyepoch: LazyFull, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedComputedBlockFull +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + height_source: IterableBoxedVec, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + let height_cumulative = CumulativeVec::forced_import(db, name, v)?; + let dateindex = Full::forced_import(db, name, v)?; + + Ok(Self { + dates: DerivedDateFull::from_sources( + name, + v, + dateindex.distribution.average.0.boxed_clone(), + dateindex.distribution.minmax.min.0.boxed_clone(), + dateindex.distribution.minmax.max.0.boxed_clone(), + dateindex.sum_cum.sum.0.boxed_clone(), + dateindex.sum_cum.cumulative.0.boxed_clone(), + indexes, + ), + difficultyepoch: LazyFull::from_stats_aggregate( + name, + v, + height_source.boxed_clone(), + height_source.boxed_clone(), + height_source.boxed_clone(), + height_source.boxed_clone(), + height_cumulative.0.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ), + height_cumulative, + dateindex, + }) + } + + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + height_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + // Compute height_cumulative from external source + self.compute_height_cumulative(starting_indexes.height, height_source, exit)?; + + // Compute dateindex aggregations + self.dateindex.compute( + starting_indexes.dateindex, + height_source, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + )?; + + Ok(()) + } + + fn compute_height_cumulative( + &mut self, + max_from: Height, + height_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + compute_cumulative_extend(max_from, height_source, &mut self.height_cumulative.0, exit) + } +} diff --git a/crates/brk_computer/src/internal/computed/derived_block/last.rs b/crates/brk_computer/src/internal/computed/derived_block/last.rs new file mode 100644 index 000000000..f10d06557 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/derived_block/last.rs @@ -0,0 +1,77 @@ +//! DerivedComputedBlockLast - dateindex storage + difficultyepoch + lazy time periods. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, Exit, IterableBoxedVec, IterableCloneableVec, IterableVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedVecValue, DerivedDateLast, LastVec, LazyLast, NumericValue}, +}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DerivedComputedBlockLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: LastVec, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateLast, + pub difficultyepoch: LazyLast, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedComputedBlockLast +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + height_source: IterableBoxedVec, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = LastVec::forced_import(db, name, version + VERSION)?; + let v = version + VERSION; + + Ok(Self { + dates: DerivedDateLast::from_source(name, v, dateindex.0.boxed_clone(), indexes), + difficultyepoch: LazyLast::from_source( + name, + v, + height_source, + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ), + dateindex, + }) + } + + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + height_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + self.dateindex.compute_last( + starting_indexes.dateindex, + height_source, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + )?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/derived_block/mod.rs b/crates/brk_computer/src/internal/computed/derived_block/mod.rs new file mode 100644 index 000000000..33607db76 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/derived_block/mod.rs @@ -0,0 +1,11 @@ +mod distribution; +mod full; +mod last; +mod sum; +mod sum_cum; + +pub use distribution::*; +pub use full::*; +pub use last::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/computed/derived_block/sum.rs b/crates/brk_computer/src/internal/computed/derived_block/sum.rs new file mode 100644 index 000000000..a7ce93d90 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/derived_block/sum.rs @@ -0,0 +1,119 @@ +//! DerivedComputedBlockSum - dateindex storage + difficultyepoch + lazy time periods. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, StoredU64, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{ + AnyStoredVec, AnyVec, Database, Exit, GenericStoredVec, IterableBoxedVec, IterableCloneableVec, + IterableVec, VecIndex, +}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedVecValue, DerivedDateSum, LazySum, NumericValue, SumVec}, +}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DerivedComputedBlockSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub dateindex: SumVec, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateSum, + pub difficultyepoch: LazySum, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedComputedBlockSum +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + height_source: IterableBoxedVec, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dateindex = SumVec::forced_import(db, name, version + VERSION)?; + let v = version + VERSION; + + Ok(Self { + dates: DerivedDateSum::from_source(name, v, dateindex.0.boxed_clone(), indexes), + difficultyepoch: LazySum::from_source( + name, + v, + height_source, + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ), + dateindex, + }) + } + + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + height_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + self.compute_from( + starting_indexes.dateindex, + height_source, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + ) + } + + fn compute_from( + &mut self, + starting_dateindex: DateIndex, + height_source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + let sum_vec = &mut self.dateindex.0; + + let combined_version = + height_source.version() + first_indexes.version() + count_indexes.version(); + sum_vec.validate_computed_version_or_reset(combined_version)?; + + let index = starting_dateindex.to_usize().min(sum_vec.len()); + + let mut source_iter = height_source.iter(); + let mut count_iter = count_indexes.iter().skip(index); + + first_indexes.iter().enumerate().skip(index).try_for_each( + |(idx, first_height)| -> Result<()> { + let count = *count_iter.next().unwrap() as usize; + + source_iter.set_position(first_height); + let sum: T = (&mut source_iter) + .take(count) + .fold(T::from(0_usize), |acc, v| acc + v); + + sum_vec.truncate_push_at(idx, sum)?; + + Ok(()) + }, + )?; + + let _lock = exit.lock(); + sum_vec.write()?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/derived_block/sum_cum.rs b/crates/brk_computer/src/internal/computed/derived_block/sum_cum.rs new file mode 100644 index 000000000..66e755467 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/derived_block/sum_cum.rs @@ -0,0 +1,161 @@ +//! DerivedComputedBlockSumCum - aggregates derived from an external height source. + +use brk_error::Result; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, StoredU64, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{ + AnyStoredVec, AnyVec, Database, Exit, GenericStoredVec, IterableBoxedVec, IterableCloneableVec, + IterableVec, VecIndex, +}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ + ComputedVecValue, CumulativeVec, DerivedDateSumCum, LazySumCum, NumericValue, SumCum, + compute_cumulative_extend, + }, +}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DerivedComputedBlockSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height_cumulative: CumulativeVec, + pub dateindex: SumCum, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateSumCum, + pub difficultyepoch: LazySumCum, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedComputedBlockSumCum +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + height_source: IterableBoxedVec, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let v = version + VERSION; + + let height_cumulative = CumulativeVec::forced_import(db, name, v)?; + let dateindex = SumCum::forced_import(db, name, v)?; + + let dates = DerivedDateSumCum::from_sources( + name, + v, + dateindex.sum.0.boxed_clone(), + dateindex.cumulative.0.boxed_clone(), + indexes, + ); + + let difficultyepoch = LazySumCum::from_sources( + name, + v, + height_source.boxed_clone(), + height_cumulative.0.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + Ok(Self { + height_cumulative, + dateindex, + dates, + difficultyepoch, + }) + } + + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + height_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + self.compute_height_cumulative(starting_indexes.height, height_source, exit)?; + self.compute_dateindex_sum_cum( + starting_indexes.dateindex, + height_source, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + ) + } + + fn compute_height_cumulative( + &mut self, + max_from: Height, + source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + compute_cumulative_extend(max_from, source, &mut self.height_cumulative.0, exit) + } + + fn compute_dateindex_sum_cum( + &mut self, + starting_dateindex: DateIndex, + height_source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + let sum_vec = &mut self.dateindex.sum.0; + let cumulative_vec = &mut self.dateindex.cumulative.0; + + let combined_version = + height_source.version() + first_indexes.version() + count_indexes.version(); + sum_vec.validate_computed_version_or_reset(combined_version)?; + cumulative_vec.validate_computed_version_or_reset(combined_version)?; + + let index = starting_dateindex + .to_usize() + .min(sum_vec.len()) + .min(cumulative_vec.len()); + + let mut cumulative = if index > 0 { + cumulative_vec.iter().get_unwrap((index - 1).into()) + } else { + T::from(0_usize) + }; + + let mut source_iter = height_source.iter(); + let mut count_iter = count_indexes.iter().skip(index); + + first_indexes.iter().enumerate().skip(index).try_for_each( + |(idx, first_height)| -> Result<()> { + let count = *count_iter.next().unwrap() as usize; + + source_iter.set_position(first_height); + let sum: T = (&mut source_iter) + .take(count) + .fold(T::from(0_usize), |acc, v| acc + v); + + cumulative += sum; + sum_vec.truncate_push_at(idx, sum)?; + cumulative_vec.truncate_push_at(idx, cumulative)?; + + Ok(()) + }, + )?; + + let _lock = exit.lock(); + sum_vec.write()?; + cumulative_vec.write()?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/from_dateindex.rs b/crates/brk_computer/src/internal/computed/from_dateindex.rs deleted file mode 100644 index 06f533042..000000000 --- a/crates/brk_computer/src/internal/computed/from_dateindex.rs +++ /dev/null @@ -1,199 +0,0 @@ -use brk_error::Result; -use brk_traversable::Traversable; -use brk_types::{ - DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, TreeNode, Version, WeekIndex, - YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{ - AnyExportableVec, Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, IterableVec, - PcoVec, -}; - -use crate::{ComputeIndexes, indexes, internal::LazyVecsBuilder, utils::OptionExt}; - -use crate::internal::{ComputedVecValue, EagerVecsBuilder, Source, VecBuilderOptions}; - -#[derive(Clone)] -pub struct ComputedVecsFromDateIndex -where - T: ComputedVecValue + PartialOrd + JsonSchema, -{ - pub dateindex: Option>>, - pub dateindex_extra: EagerVecsBuilder, - pub weekindex: LazyVecsBuilder, - pub monthindex: LazyVecsBuilder, - pub quarterindex: LazyVecsBuilder, - pub semesterindex: LazyVecsBuilder, - pub yearindex: LazyVecsBuilder, - pub decadeindex: LazyVecsBuilder, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedVecsFromDateIndex -where - T: ComputedVecValue + JsonSchema + 'static, -{ - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - db: &Database, - name: &str, - source: Source, - version: Version, - indexes: &indexes::Vecs, - options: VecBuilderOptions, - ) -> Result { - let dateindex = source - .is_compute() - .then(|| EagerVec::forced_import(db, name, version + VERSION).unwrap()); - - let dateindex_extra = EagerVecsBuilder::forced_import( - db, - name, - version + VERSION, - options.copy_self_extra(), - )?; - - let options = options.remove_percentiles(); - - let dateindex_source = source.vec().or(dateindex.as_ref().map(|v| v.boxed_clone())); - - Ok(Self { - weekindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - dateindex_source.clone(), - &dateindex_extra, - indexes.time.weekindex_to_weekindex.boxed_clone(), - options.into(), - ), - monthindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - dateindex_source.clone(), - &dateindex_extra, - indexes.time.monthindex_to_monthindex.boxed_clone(), - options.into(), - ), - quarterindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - dateindex_source.clone(), - &dateindex_extra, - indexes.time.quarterindex_to_quarterindex.boxed_clone(), - options.into(), - ), - semesterindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - dateindex_source.clone(), - &dateindex_extra, - indexes.time.semesterindex_to_semesterindex.boxed_clone(), - options.into(), - ), - yearindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - dateindex_source.clone(), - &dateindex_extra, - indexes.time.yearindex_to_yearindex.boxed_clone(), - options.into(), - ), - decadeindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - dateindex_source.clone(), - &dateindex_extra, - indexes.time.decadeindex_to_decadeindex.boxed_clone(), - options.into(), - ), - dateindex, - dateindex_extra, - }) - } - - pub fn compute_all( - &mut self, - starting_indexes: &ComputeIndexes, - exit: &Exit, - mut compute: F, - ) -> Result<()> - where - F: FnMut(&mut EagerVec>) -> Result<()>, - { - compute(self.dateindex.um())?; - - let dateindex: Option<&EagerVec>> = None; - self.compute_rest(starting_indexes, exit, dateindex) - } - - pub fn compute_rest( - &mut self, - starting_indexes: &ComputeIndexes, - exit: &Exit, - dateindex: Option<&impl IterableVec>, - ) -> Result<()> { - if let Some(dateindex) = dateindex { - self.dateindex_extra - .extend(starting_indexes.dateindex, dateindex, exit)?; - } else { - let dateindex = self.dateindex.u(); - - self.dateindex_extra - .extend(starting_indexes.dateindex, dateindex, exit)?; - } - - Ok(()) - } -} - -impl Traversable for ComputedVecsFromDateIndex -where - T: ComputedVecValue + JsonSchema, -{ - fn to_tree_node(&self) -> TreeNode { - let dateindex_extra_node = self.dateindex_extra.to_tree_node(); - TreeNode::Branch( - [ - self.dateindex - .as_ref() - .map(|nested| ("dateindex".to_string(), nested.to_tree_node())), - if dateindex_extra_node.is_empty() { - None - } else { - Some(("dateindex_extra".to_string(), dateindex_extra_node)) - }, - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(self.dateindex_extra.iter_any_exportable()); - regular_iter = Box::new(regular_iter.chain(self.weekindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.monthindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.quarterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.semesterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.yearindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.decadeindex.iter_any_exportable())); - if let Some(ref x) = self.dateindex { - regular_iter = Box::new(regular_iter.chain(x.iter_any_exportable())); - } - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/computed/from_height/mod.rs b/crates/brk_computer/src/internal/computed/from_height/mod.rs deleted file mode 100644 index 3b6a0f081..000000000 --- a/crates/brk_computer/src/internal/computed/from_height/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod standard; -mod strict; - -pub use standard::*; -pub use strict::*; diff --git a/crates/brk_computer/src/internal/computed/from_height/standard.rs b/crates/brk_computer/src/internal/computed/from_height/standard.rs deleted file mode 100644 index 5c2056afe..000000000 --- a/crates/brk_computer/src/internal/computed/from_height/standard.rs +++ /dev/null @@ -1,248 +0,0 @@ -use brk_error::Result; - -use brk_traversable::Traversable; -use brk_types::{ - DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex, - TreeNode, Version, WeekIndex, YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{ - AnyExportableVec, Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, IterableVec, - PcoVec, -}; - -use crate::{ - ComputeIndexes, indexes, - internal::{LazyVecsBuilder, Source}, - utils::OptionExt, -}; - -use crate::internal::{ComputedVecValue, EagerVecsBuilder, VecBuilderOptions}; - -#[derive(Clone)] -pub struct ComputedVecsFromHeight -where - T: ComputedVecValue + PartialOrd + JsonSchema, -{ - pub height: Option>>, - pub height_extra: EagerVecsBuilder, - pub dateindex: EagerVecsBuilder, - pub weekindex: LazyVecsBuilder, - pub difficultyepoch: LazyVecsBuilder, - pub monthindex: LazyVecsBuilder, - pub quarterindex: LazyVecsBuilder, - pub semesterindex: LazyVecsBuilder, - pub yearindex: LazyVecsBuilder, - // TODO: pub halvingepoch: StorableVecGeneator, - pub decadeindex: LazyVecsBuilder, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedVecsFromHeight -where - T: ComputedVecValue + Ord + From + JsonSchema + 'static, - f64: From, -{ - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - db: &Database, - name: &str, - source: Source, - version: Version, - indexes: &indexes::Vecs, - options: VecBuilderOptions, - ) -> Result { - let height = source - .is_compute() - .then(|| EagerVec::forced_import(db, name, version + VERSION).unwrap()); - - let height_extra = EagerVecsBuilder::forced_import( - db, - name, - version + VERSION, - options.copy_self_extra(), - )?; - - let dateindex = EagerVecsBuilder::forced_import(db, name, version + VERSION, options)?; - - let options = options.remove_percentiles(); - - let height_source = source.vec().or(height.as_ref().map(|v| v.boxed_clone())); - - Ok(Self { - weekindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.weekindex_to_weekindex.boxed_clone(), - options.into(), - ), - monthindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.monthindex_to_monthindex.boxed_clone(), - options.into(), - ), - quarterindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.quarterindex_to_quarterindex.boxed_clone(), - options.into(), - ), - semesterindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.semesterindex_to_semesterindex.boxed_clone(), - options.into(), - ), - yearindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.yearindex_to_yearindex.boxed_clone(), - options.into(), - ), - decadeindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.decadeindex_to_decadeindex.boxed_clone(), - options.into(), - ), - // halvingepoch: StorableVecGeneator::forced_import(db, name, version + VERSION , format, options)?, - difficultyepoch: LazyVecsBuilder::forced_import( - name, - version + VERSION, - height_source, - &height_extra, - indexes - .block - .difficultyepoch_to_difficultyepoch - .boxed_clone(), - options.into(), - ), - height, - height_extra, - dateindex, - }) - } - - pub fn compute_all( - &mut self, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - mut compute: F, - ) -> Result<()> - where - F: FnMut(&mut EagerVec>) -> Result<()>, - { - compute(self.height.um())?; - - let height: Option<&EagerVec>> = None; - self.compute_rest(indexes, starting_indexes, exit, height) - } - - pub fn compute_rest( - &mut self, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - height_vec: Option<&impl IterableVec>, - ) -> Result<()> { - if let Some(height) = height_vec { - self.height_extra - .extend(starting_indexes.height, height, exit)?; - - self.dateindex.compute( - starting_indexes.dateindex, - height, - &indexes.time.dateindex_to_first_height, - &indexes.time.dateindex_to_height_count, - exit, - )?; - } else { - let height = self.height.u(); - - self.height_extra - .extend(starting_indexes.height, height, exit)?; - - self.dateindex.compute( - starting_indexes.dateindex, - height, - &indexes.time.dateindex_to_first_height, - &indexes.time.dateindex_to_height_count, - exit, - )?; - } - - Ok(()) - } -} - -impl Traversable for ComputedVecsFromHeight -where - T: ComputedVecValue + JsonSchema, -{ - fn to_tree_node(&self) -> TreeNode { - let height_extra_node = self.height_extra.to_tree_node(); - TreeNode::Branch( - [ - self.height - .as_ref() - .map(|nested| ("height".to_string(), nested.to_tree_node())), - if height_extra_node.is_empty() { - None - } else { - Some(("height_extra".to_string(), height_extra_node)) - }, - Some(("dateindex".to_string(), self.dateindex.to_tree_node())), - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(( - "difficultyepoch".to_string(), - self.difficultyepoch.to_tree_node(), - )), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(self.height_extra.iter_any_exportable()); - regular_iter = Box::new(regular_iter.chain(self.dateindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.weekindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.difficultyepoch.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.monthindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.quarterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.semesterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.yearindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.decadeindex.iter_any_exportable())); - if let Some(ref x) = self.height { - regular_iter = Box::new(regular_iter.chain(x.iter_any_exportable())); - } - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/computed/from_height/strict.rs b/crates/brk_computer/src/internal/computed/from_height/strict.rs deleted file mode 100644 index 177169d86..000000000 --- a/crates/brk_computer/src/internal/computed/from_height/strict.rs +++ /dev/null @@ -1,120 +0,0 @@ -use brk_error::Result; - -use brk_traversable::Traversable; -use brk_types::{DifficultyEpoch, Height, TreeNode, Version}; -use schemars::JsonSchema; -use vecdb::{ - AnyExportableVec, Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec, -}; - -use crate::{ComputeIndexes, indexes}; - -use crate::internal::{ComputedVecValue, EagerVecsBuilder, LazyVecsBuilder, VecBuilderOptions}; - -#[derive(Clone)] -pub struct ComputedVecsFromHeightStrict -where - T: ComputedVecValue + PartialOrd + JsonSchema, -{ - pub height: EagerVec>, - pub height_extra: EagerVecsBuilder, - pub difficultyepoch: LazyVecsBuilder, - // TODO: pub halvingepoch: StorableVecGeneator, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedVecsFromHeightStrict -where - T: ComputedVecValue + Ord + From + JsonSchema, - f64: From, -{ - pub fn forced_import( - db: &Database, - name: &str, - version: Version, - indexes: &indexes::Vecs, - options: VecBuilderOptions, - ) -> Result { - let height = EagerVec::forced_import(db, name, version + VERSION)?; - - let height_extra = EagerVecsBuilder::forced_import( - db, - name, - version + VERSION, - options.copy_self_extra(), - )?; - - let options = options.remove_percentiles(); - - Ok(Self { - difficultyepoch: LazyVecsBuilder::forced_import( - name, - version + VERSION, - Some(height.boxed_clone()), - &height_extra, - indexes - .block - .difficultyepoch_to_difficultyepoch - .boxed_clone(), - options.into(), - ), - height, - height_extra, - // halvingepoch: StorableVecGeneator::forced_import(db, name, version + VERSION , format, options)?, - }) - } - - pub fn compute( - &mut self, - starting_indexes: &ComputeIndexes, - exit: &Exit, - mut compute: F, - ) -> Result<()> - where - F: FnMut(&mut EagerVec>) -> Result<()>, - { - compute(&mut self.height)?; - - self.height_extra - .extend(starting_indexes.height, &self.height, exit)?; - - Ok(()) - } -} - -impl Traversable for ComputedVecsFromHeightStrict -where - T: ComputedVecValue + JsonSchema, -{ - fn to_tree_node(&self) -> TreeNode { - let height_extra_node = self.height_extra.to_tree_node(); - TreeNode::Branch( - [ - Some(("height".to_string(), self.height.to_tree_node())), - if height_extra_node.is_empty() { - None - } else { - Some(("height_extra".to_string(), height_extra_node)) - }, - Some(( - "difficultyepoch".to_string(), - self.difficultyepoch.to_tree_node(), - )), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(self.height.iter_any_exportable()); - regular_iter = Box::new(regular_iter.chain(self.height_extra.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.difficultyepoch.iter_any_exportable())); - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/computed/from_txindex.rs b/crates/brk_computer/src/internal/computed/from_txindex.rs deleted file mode 100644 index c91ff4f26..000000000 --- a/crates/brk_computer/src/internal/computed/from_txindex.rs +++ /dev/null @@ -1,452 +0,0 @@ -use brk_error::Result; -use brk_indexer::Indexer; -use brk_traversable::Traversable; -use brk_types::{ - Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, MonthIndex, QuarterIndex, - Sats, SemesterIndex, TreeNode, TxIndex, Version, WeekIndex, YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{ - AnyExportableVec, AnyVec, CollectableVec, Database, EagerVec, Exit, GenericStoredVec, - ImportableVec, IterableCloneableVec, PcoVec, TypedVecIterator, VecIndex, -}; - -use crate::{ - ComputeIndexes, indexes, - internal::{LazyVecsBuilder, Source}, - price, - utils::OptionExt, -}; - -use crate::internal::{ComputedVecValue, EagerVecsBuilder, VecBuilderOptions}; - -#[derive(Clone)] -pub struct ComputedVecsFromTxindex -where - T: ComputedVecValue + PartialOrd + JsonSchema, -{ - pub txindex: Option>>>, - pub height: EagerVecsBuilder, - pub dateindex: EagerVecsBuilder, - pub weekindex: LazyVecsBuilder, - pub difficultyepoch: LazyVecsBuilder, - pub monthindex: LazyVecsBuilder, - pub quarterindex: LazyVecsBuilder, - pub semesterindex: LazyVecsBuilder, - pub yearindex: LazyVecsBuilder, - // TODO: pub halvingepoch: StorableVecGeneator, - pub decadeindex: LazyVecsBuilder, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedVecsFromTxindex -where - T: ComputedVecValue + Ord + From + JsonSchema + 'static, - f64: From, -{ - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - db: &Database, - name: &str, - source: Source, - version: Version, - indexes: &indexes::Vecs, - options: VecBuilderOptions, - ) -> Result { - let txindex = source - .is_compute() - .then(|| Box::new(EagerVec::forced_import(db, name, version + VERSION).unwrap())); - - let height = EagerVecsBuilder::forced_import(db, name, version + VERSION, options)?; - - let options = options.remove_percentiles(); - - let dateindex = EagerVecsBuilder::forced_import(db, name, version + VERSION, options)?; - - Ok(Self { - weekindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.weekindex_to_weekindex.boxed_clone(), - options.into(), - ), - difficultyepoch: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &height, - indexes - .block - .difficultyepoch_to_difficultyepoch - .boxed_clone(), - options.into(), - ), - monthindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.monthindex_to_monthindex.boxed_clone(), - options.into(), - ), - quarterindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.quarterindex_to_quarterindex.boxed_clone(), - options.into(), - ), - semesterindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.semesterindex_to_semesterindex.boxed_clone(), - options.into(), - ), - yearindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.yearindex_to_yearindex.boxed_clone(), - options.into(), - ), - decadeindex: LazyVecsBuilder::forced_import( - name, - version + VERSION, - None, - &dateindex, - indexes.time.decadeindex_to_decadeindex.boxed_clone(), - options.into(), - ), - - txindex, - height, - dateindex, - // halvingepoch: StorableVecGeneator::forced_import(db, name, version + VERSION , format, options)?, - }) - } - - // pub fn compute_all( - // &mut self, - // indexer: &Indexer, - // indexes: &indexes::Vecs, - // starting_indexes: &ComputeIndexes, - // exit: &Exit, - // mut compute: F, - // ) -> Result<()> - // where - // F: FnMut( - // &mut EagerVec>, - // &Indexer, - // &indexes::Vecs, - // &Indexes, - // &Exit, - // ) -> Result<()>, - // { - // compute( - // self.txindex.um(), - // indexer, - // indexes, - // starting_indexes, - // exit, - // )?; - - // let txindex: Option<&StoredVec> = None; - // self.compute_rest(indexer, indexes, starting_indexes, exit, txindex)?; - - // Ok(()) - // } - - pub fn compute_rest( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - txindex: Option<&impl CollectableVec>, - ) -> Result<()> { - if let Some(txindex) = txindex { - self.height.compute( - starting_indexes.height, - txindex, - &indexer.vecs.tx.height_to_first_txindex, - &indexes.block.height_to_txindex_count, - exit, - )?; - } else { - let txindex = self.txindex.u().as_ref(); - - self.height.compute( - starting_indexes.height, - txindex, - &indexer.vecs.tx.height_to_first_txindex, - &indexes.block.height_to_txindex_count, - exit, - )?; - } - - self.compute_after_height(indexes, starting_indexes, exit) - } - - fn compute_after_height( - &mut self, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - ) -> Result<()> { - self.dateindex.from_aligned( - starting_indexes.dateindex, - &self.height, - &indexes.time.dateindex_to_first_height, - &indexes.time.dateindex_to_height_count, - exit, - )?; - - Ok(()) - } -} - -impl ComputedVecsFromTxindex { - pub fn compute_rest_from_sats( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - sats: &ComputedVecsFromTxindex, - txindex: Option<&impl CollectableVec>, - ) -> Result<()> { - let txindex_version = if let Some(txindex) = txindex { - txindex.version() - } else { - self.txindex.u().as_ref().version() - }; - - self.height - .validate_computed_version_or_reset(txindex_version)?; - - let starting_index = self.height.starting_index(starting_indexes.height); - - // Create iterators once before the loop to avoid repeated iterator creation - let mut first_iter = sats.height.first.as_ref().map(|v| v.into_iter()); - let mut average_iter = sats.height.average.as_ref().map(|v| v.into_iter()); - let mut sum_iter = sats.height.sum.as_ref().map(|v| v.into_iter()); - let mut max_iter = sats.height.max.as_ref().map(|v| v.into_iter()); - let mut pct90_iter = sats.height.pct90.as_ref().map(|v| v.into_iter()); - let mut pct75_iter = sats.height.pct75.as_ref().map(|v| v.into_iter()); - let mut median_iter = sats.height.median.as_ref().map(|v| v.into_iter()); - let mut pct25_iter = sats.height.pct25.as_ref().map(|v| v.into_iter()); - let mut pct10_iter = sats.height.pct10.as_ref().map(|v| v.into_iter()); - let mut min_iter = sats.height.min.as_ref().map(|v| v.into_iter()); - let mut last_iter = sats.height.last.as_ref().map(|v| v.into_iter()); - let mut cumulative_iter = sats.height.cumulative.as_ref().map(|v| v.into_iter()); - - (starting_index.to_usize()..indexer.vecs.block.height_to_weight.len()) - .map(Height::from) - .try_for_each(|height| -> Result<()> { - if let Some(first) = self.height.first.as_mut() { - first - .truncate_push(height, Bitcoin::from(first_iter.um().get_unwrap(height)))?; - } - if let Some(average) = self.height.average.as_mut() { - average.truncate_push( - height, - Bitcoin::from(average_iter.um().get_unwrap(height)), - )?; - } - if let Some(sum) = self.height.sum.as_mut() { - sum.truncate_push(height, Bitcoin::from(sum_iter.um().get_unwrap(height)))?; - } - if let Some(max) = self.height.max.as_mut() { - max.truncate_push(height, Bitcoin::from(max_iter.um().get_unwrap(height)))?; - } - if let Some(pct90) = self.height.pct90.as_mut() { - pct90 - .truncate_push(height, Bitcoin::from(pct90_iter.um().get_unwrap(height)))?; - } - if let Some(pct75) = self.height.pct75.as_mut() { - pct75 - .truncate_push(height, Bitcoin::from(pct75_iter.um().get_unwrap(height)))?; - } - if let Some(median) = self.height.median.as_mut() { - median.truncate_push( - height, - Bitcoin::from(median_iter.um().get_unwrap(height)), - )?; - } - if let Some(pct25) = self.height.pct25.as_mut() { - pct25 - .truncate_push(height, Bitcoin::from(pct25_iter.um().get_unwrap(height)))?; - } - if let Some(pct10) = self.height.pct10.as_mut() { - pct10 - .truncate_push(height, Bitcoin::from(pct10_iter.um().get_unwrap(height)))?; - } - if let Some(min) = self.height.min.as_mut() { - min.truncate_push(height, Bitcoin::from(min_iter.um().get_unwrap(height)))?; - } - if let Some(last) = self.height.last.as_mut() { - last.truncate_push(height, Bitcoin::from(last_iter.um().get_unwrap(height)))?; - } - if let Some(cumulative) = self.height.cumulative.as_mut() { - cumulative.truncate_push( - height, - Bitcoin::from(cumulative_iter.um().get_unwrap(height)), - )?; - } - Ok(()) - })?; - - self.height.write()?; - - self.compute_after_height(indexes, starting_indexes, exit) - } -} - -impl ComputedVecsFromTxindex { - #[allow(clippy::too_many_arguments)] - pub fn compute_rest_from_bitcoin( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - bitcoin: &ComputedVecsFromTxindex, - txindex: Option<&impl CollectableVec>, - price: &price::Vecs, - ) -> Result<()> { - let txindex_version = if let Some(txindex) = txindex { - txindex.version() - } else { - self.txindex.u().as_ref().version() - }; - - self.height - .validate_computed_version_or_reset(txindex_version)?; - - let starting_index = self.height.starting_index(starting_indexes.height); - - let mut close_iter = price.usd.chainindexes_to_price_close.height.into_iter(); - - // Create iterators once before the loop to avoid repeated iterator creation - let mut first_iter = bitcoin.height.first.as_ref().map(|v| v.into_iter()); - let mut average_iter = bitcoin.height.average.as_ref().map(|v| v.into_iter()); - let mut sum_iter = bitcoin.height.sum.as_ref().map(|v| v.into_iter()); - let mut max_iter = bitcoin.height.max.as_ref().map(|v| v.into_iter()); - let mut pct90_iter = bitcoin.height.pct90.as_ref().map(|v| v.into_iter()); - let mut pct75_iter = bitcoin.height.pct75.as_ref().map(|v| v.into_iter()); - let mut median_iter = bitcoin.height.median.as_ref().map(|v| v.into_iter()); - let mut pct25_iter = bitcoin.height.pct25.as_ref().map(|v| v.into_iter()); - let mut pct10_iter = bitcoin.height.pct10.as_ref().map(|v| v.into_iter()); - let mut min_iter = bitcoin.height.min.as_ref().map(|v| v.into_iter()); - let mut last_iter = bitcoin.height.last.as_ref().map(|v| v.into_iter()); - let mut cumulative_iter = bitcoin.height.cumulative.as_ref().map(|v| v.into_iter()); - - (starting_index.to_usize()..indexer.vecs.block.height_to_weight.len()) - .map(Height::from) - .try_for_each(|height| -> Result<()> { - let price = *close_iter.get_unwrap(height); - - if let Some(first) = self.height.first.as_mut() { - first.truncate_push(height, price * first_iter.um().get_unwrap(height))?; - } - if let Some(average) = self.height.average.as_mut() { - average.truncate_push(height, price * average_iter.um().get_unwrap(height))?; - } - if let Some(sum) = self.height.sum.as_mut() { - sum.truncate_push(height, price * sum_iter.um().get_unwrap(height))?; - } - if let Some(max) = self.height.max.as_mut() { - max.truncate_push(height, price * max_iter.um().get_unwrap(height))?; - } - if let Some(pct90) = self.height.pct90.as_mut() { - pct90.truncate_push(height, price * pct90_iter.um().get_unwrap(height))?; - } - if let Some(pct75) = self.height.pct75.as_mut() { - pct75.truncate_push(height, price * pct75_iter.um().get_unwrap(height))?; - } - if let Some(median) = self.height.median.as_mut() { - median.truncate_push(height, price * median_iter.um().get_unwrap(height))?; - } - if let Some(pct25) = self.height.pct25.as_mut() { - pct25.truncate_push(height, price * pct25_iter.um().get_unwrap(height))?; - } - if let Some(pct10) = self.height.pct10.as_mut() { - pct10.truncate_push(height, price * pct10_iter.um().get_unwrap(height))?; - } - if let Some(min) = self.height.min.as_mut() { - min.truncate_push(height, price * min_iter.um().get_unwrap(height))?; - } - if let Some(last) = self.height.last.as_mut() { - last.truncate_push(height, price * last_iter.um().get_unwrap(height))?; - } - if let Some(cumulative) = self.height.cumulative.as_mut() { - cumulative - .truncate_push(height, price * cumulative_iter.um().get_unwrap(height))?; - } - Ok(()) - })?; - - self.height.write()?; - - self.compute_after_height(indexes, starting_indexes, exit) - } -} - -impl Traversable for ComputedVecsFromTxindex -where - T: ComputedVecValue + JsonSchema, -{ - fn to_tree_node(&self) -> TreeNode { - TreeNode::Branch( - [ - self.txindex - .as_ref() - .map(|nested| ("txindex".to_string(), nested.to_tree_node())), - Some(("height".to_string(), self.height.to_tree_node())), - Some(("dateindex".to_string(), self.dateindex.to_tree_node())), - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(( - "difficultyepoch".to_string(), - self.difficultyepoch.to_tree_node(), - )), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(self.height.iter_any_exportable()); - regular_iter = Box::new(regular_iter.chain(self.dateindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.weekindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.difficultyepoch.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.monthindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.quarterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.semesterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.yearindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.decadeindex.iter_any_exportable())); - if let Some(ref x) = self.txindex { - regular_iter = Box::new(regular_iter.chain(x.iter_any_exportable())); - } - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/computed/mod.rs b/crates/brk_computer/src/internal/computed/mod.rs index 4d06981a1..43b86efdc 100644 --- a/crates/brk_computer/src/internal/computed/mod.rs +++ b/crates/brk_computer/src/internal/computed/mod.rs @@ -1,9 +1,11 @@ -mod from_dateindex; -mod from_height; -mod from_txindex; -mod traits; +mod block; +mod chain; +mod date; +mod derived_block; +mod tx; -pub use from_dateindex::*; -pub use from_height::*; -pub use from_txindex::*; -pub use traits::*; +pub use block::*; +pub use chain::*; +pub use date::*; +pub use derived_block::*; +pub use tx::*; diff --git a/crates/brk_computer/src/internal/computed/tx/distribution.rs b/crates/brk_computer/src/internal/computed/tx/distribution.rs new file mode 100644 index 000000000..4f632de97 --- /dev/null +++ b/crates/brk_computer/src/internal/computed/tx/distribution.rs @@ -0,0 +1,111 @@ +//! ComputedTxDistribution - computes TxIndex data to height Distribution + dateindex MinMaxAverage + lazy aggregations. +//! +//! Note: Percentiles are computed at height level only. DateIndex and coarser +//! periods only have average+min+max since computing percentiles across all +//! transactions per day would be expensive. + +use brk_error::Result; +use brk_indexer::Indexer; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, TxIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ + ComputedVecValue, DerivedDateDistribution, Distribution, LazyDistribution, MinMaxAverage, + NumericValue, + }, +}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct ComputedTxDistribution +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: Distribution, + pub difficultyepoch: LazyDistribution, + pub dateindex: MinMaxAverage, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateDistribution, +} + +const VERSION: Version = Version::ZERO; + +impl ComputedTxDistribution +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let height = Distribution::forced_import(db, name, version + VERSION)?; + let dateindex = MinMaxAverage::forced_import(db, name, version + VERSION)?; + let v = version + VERSION; + + let difficultyepoch = + LazyDistribution::::from_distribution( + name, + v, + height.average.0.boxed_clone(), + height.minmax.min.0.boxed_clone(), + height.minmax.max.0.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + let dates = DerivedDateDistribution::from_sources( + name, + v, + dateindex.average.0.boxed_clone(), + dateindex.minmax.min.0.boxed_clone(), + dateindex.minmax.max.0.boxed_clone(), + indexes, + ); + + Ok(Self { + height, + difficultyepoch, + dateindex, + dates, + }) + } + + pub fn derive_from( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + txindex_source: &impl CollectableVec, + exit: &Exit, + ) -> Result<()> { + self.height.compute( + starting_indexes.height, + txindex_source, + &indexer.vecs.tx.height_to_first_txindex, + &indexes.block.height_to_txindex_count, + exit, + )?; + + self.dateindex.compute( + starting_indexes.dateindex, + &self.height.average.0, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/tx/full.rs b/crates/brk_computer/src/internal/computed/tx/full.rs new file mode 100644 index 000000000..20f8101ef --- /dev/null +++ b/crates/brk_computer/src/internal/computed/tx/full.rs @@ -0,0 +1,106 @@ +//! DerivedTxFull - aggregates from TxIndex to height Full + dateindex Stats + lazy date periods. + +use brk_error::Result; +use brk_indexer::Indexer; + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, TxIndex, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec}; + +use crate::{ + indexes, ComputeIndexes, + internal::{ComputedVecValue, DerivedDateFull, Full, LazyFull, NumericValue, Stats}, +}; + +/// Aggregates from TxIndex to height/dateindex with full stats. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DerivedTxFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub height: Full, + pub difficultyepoch: LazyFull, + pub dateindex: Stats, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateFull, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedTxFull +where + T: NumericValue + JsonSchema, +{ + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let height = Full::forced_import(db, name, version + VERSION)?; + let dateindex = Stats::forced_import(db, name, version + VERSION)?; + let v = version + VERSION; + + let difficultyepoch = + LazyFull::::from_stats_aggregate( + name, + v, + height.distribution.average.0.boxed_clone(), + height.distribution.minmax.min.0.boxed_clone(), + height.distribution.minmax.max.0.boxed_clone(), + height.sum_cum.sum.0.boxed_clone(), + height.sum_cum.cumulative.0.boxed_clone(), + indexes.block.difficultyepoch_to_difficultyepoch.boxed_clone(), + ); + + let dates = DerivedDateFull::from_sources( + name, + v, + dateindex.average.0.boxed_clone(), + dateindex.minmax.min.0.boxed_clone(), + dateindex.minmax.max.0.boxed_clone(), + dateindex.sum_cum.sum.0.boxed_clone(), + dateindex.sum_cum.cumulative.0.boxed_clone(), + indexes, + ); + + Ok(Self { + height, + difficultyepoch, + dateindex, + dates, + }) + } + + pub fn derive_from( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + txindex_source: &impl CollectableVec, + exit: &Exit, + ) -> Result<()> { + self.height.compute( + starting_indexes.height, + txindex_source, + &indexer.vecs.tx.height_to_first_txindex, + &indexes.block.height_to_txindex_count, + exit, + )?; + + self.dateindex.compute( + starting_indexes.dateindex, + &self.height.distribution.average.0, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/computed/tx/mod.rs b/crates/brk_computer/src/internal/computed/tx/mod.rs new file mode 100644 index 000000000..b0d01da0e --- /dev/null +++ b/crates/brk_computer/src/internal/computed/tx/mod.rs @@ -0,0 +1,5 @@ +mod distribution; +mod full; + +pub use distribution::*; +pub use full::*; diff --git a/crates/brk_computer/src/internal/derived/date/average.rs b/crates/brk_computer/src/internal/derived/date/average.rs new file mode 100644 index 000000000..d2a226538 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/average.rs @@ -0,0 +1,80 @@ +//! Derived date periods with average-value aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyAverage}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateAverage +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyAverage, + pub monthindex: LazyAverage, + pub quarterindex: LazyAverage, + pub semesterindex: LazyAverage, + pub yearindex: LazyAverage, + pub decadeindex: LazyAverage, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateAverage +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from an external dateindex source. + pub fn from_source( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyAverage::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyAverage::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyAverage::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyAverage::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyAverage::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyAverage::from_source( + name, + version + VERSION, + dateindex_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/distribution.rs b/crates/brk_computer/src/internal/derived/date/distribution.rs new file mode 100644 index 000000000..26fd5b263 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/distribution.rs @@ -0,0 +1,94 @@ +//! Derived date periods with distribution aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyDistribution}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateDistribution +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyDistribution, + pub monthindex: LazyDistribution, + pub quarterindex: LazyDistribution, + pub semesterindex: LazyDistribution, + pub yearindex: LazyDistribution, + pub decadeindex: LazyDistribution, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateDistribution +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from external dateindex sources for distribution stats. + pub fn from_sources( + name: &str, + version: Version, + average_source: IterableBoxedVec, + min_source: IterableBoxedVec, + max_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyDistribution::from_distribution( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyDistribution::from_distribution( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyDistribution::from_distribution( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyDistribution::from_distribution( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyDistribution::from_distribution( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyDistribution::from_distribution( + name, + version + VERSION, + average_source, + min_source, + max_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/first.rs b/crates/brk_computer/src/internal/derived/date/first.rs new file mode 100644 index 000000000..1d0adba6b --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/first.rs @@ -0,0 +1,80 @@ +//! Derived date periods with first-value aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyFirst}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateFirst +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyFirst, + pub monthindex: LazyFirst, + pub quarterindex: LazyFirst, + pub semesterindex: LazyFirst, + pub yearindex: LazyFirst, + pub decadeindex: LazyFirst, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateFirst +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from an external dateindex source. + pub fn from_source( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyFirst::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyFirst::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyFirst::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyFirst::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyFirst::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyFirst::from_source( + name, + version + VERSION, + dateindex_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/full.rs b/crates/brk_computer/src/internal/derived/date/full.rs new file mode 100644 index 000000000..8f1500141 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/full.rs @@ -0,0 +1,109 @@ +//! Derived date periods with full stats aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyFull}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyFull, + pub monthindex: LazyFull, + pub quarterindex: LazyFull, + pub semesterindex: LazyFull, + pub yearindex: LazyFull, + pub decadeindex: LazyFull, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateFull +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from external dateindex sources for full stats. + #[allow(clippy::too_many_arguments)] + pub fn from_sources( + name: &str, + version: Version, + average_source: IterableBoxedVec, + min_source: IterableBoxedVec, + max_source: IterableBoxedVec, + sum_source: IterableBoxedVec, + cumulative_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyFull::from_stats_aggregate( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + sum_source.clone(), + cumulative_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyFull::from_stats_aggregate( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + sum_source.clone(), + cumulative_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyFull::from_stats_aggregate( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + sum_source.clone(), + cumulative_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyFull::from_stats_aggregate( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + sum_source.clone(), + cumulative_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyFull::from_stats_aggregate( + name, + version + VERSION, + average_source.clone(), + min_source.clone(), + max_source.clone(), + sum_source.clone(), + cumulative_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyFull::from_stats_aggregate( + name, + version + VERSION, + average_source, + min_source, + max_source, + sum_source, + cumulative_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/last.rs b/crates/brk_computer/src/internal/derived/date/last.rs new file mode 100644 index 000000000..f73b4f9d7 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/last.rs @@ -0,0 +1,80 @@ +//! Derived date periods with last-value aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyLast}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyLast, + pub monthindex: LazyLast, + pub quarterindex: LazyLast, + pub semesterindex: LazyLast, + pub yearindex: LazyLast, + pub decadeindex: LazyLast, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateLast +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from an external dateindex source. + pub fn from_source( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyLast::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyLast::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyLast::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyLast::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyLast::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyLast::from_source( + name, + version + VERSION, + dateindex_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/max.rs b/crates/brk_computer/src/internal/derived/date/max.rs new file mode 100644 index 000000000..d28512f3b --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/max.rs @@ -0,0 +1,80 @@ +//! Derived date periods with max-value aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyMax}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateMax +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyMax, + pub monthindex: LazyMax, + pub quarterindex: LazyMax, + pub semesterindex: LazyMax, + pub yearindex: LazyMax, + pub decadeindex: LazyMax, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateMax +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from an external dateindex source. + pub fn from_source( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyMax::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyMax::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyMax::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyMax::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyMax::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyMax::from_source( + name, + version + VERSION, + dateindex_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/min.rs b/crates/brk_computer/src/internal/derived/date/min.rs new file mode 100644 index 000000000..2af382b52 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/min.rs @@ -0,0 +1,80 @@ +//! Derived date periods with min-value aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazyMin}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateMin +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazyMin, + pub monthindex: LazyMin, + pub quarterindex: LazyMin, + pub semesterindex: LazyMin, + pub yearindex: LazyMin, + pub decadeindex: LazyMin, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateMin +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from an external dateindex source. + pub fn from_source( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazyMin::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazyMin::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazyMin::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazyMin::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazyMin::from_source( + name, + version + VERSION, + dateindex_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazyMin::from_source( + name, + version + VERSION, + dateindex_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/mod.rs b/crates/brk_computer/src/internal/derived/date/mod.rs new file mode 100644 index 000000000..2061797f6 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/mod.rs @@ -0,0 +1,19 @@ +mod average; +mod distribution; +mod first; +mod full; +mod last; +mod max; +mod min; +mod sum; +mod sum_cum; + +pub use average::*; +pub use distribution::*; +pub use first::*; +pub use full::*; +pub use last::*; +pub use max::*; +pub use min::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/derived/date/sum.rs b/crates/brk_computer/src/internal/derived/date/sum.rs new file mode 100644 index 000000000..c31fa8f2a --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/sum.rs @@ -0,0 +1,81 @@ +//! Derived date periods with sum aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazySum}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazySum, + pub monthindex: LazySum, + pub quarterindex: LazySum, + pub semesterindex: LazySum, + pub yearindex: LazySum, + pub decadeindex: LazySum, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateSum +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from an external dateindex source. + pub fn from_source( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + let v = version + VERSION; + Self { + weekindex: LazySum::from_source( + name, + v, + dateindex_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazySum::from_source( + name, + v, + dateindex_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazySum::from_source( + name, + v, + dateindex_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazySum::from_source( + name, + v, + dateindex_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazySum::from_source( + name, + v, + dateindex_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazySum::from_source( + name, + v, + dateindex_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/date/sum_cum.rs b/crates/brk_computer/src/internal/derived/date/sum_cum.rs new file mode 100644 index 000000000..712c2639c --- /dev/null +++ b/crates/brk_computer/src/internal/derived/date/sum_cum.rs @@ -0,0 +1,87 @@ +//! Derived date periods with sum+cumulative aggregation. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec}; + +use crate::{indexes, internal::LazySumCum}; + +use crate::internal::ComputedVecValue; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct DerivedDateSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, +{ + pub weekindex: LazySumCum, + pub monthindex: LazySumCum, + pub quarterindex: LazySumCum, + pub semesterindex: LazySumCum, + pub yearindex: LazySumCum, + pub decadeindex: LazySumCum, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedDateSumCum +where + T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from external dateindex sum and cumulative sources. + pub fn from_sources( + name: &str, + version: Version, + sum_source: IterableBoxedVec, + cumulative_source: IterableBoxedVec, + indexes: &indexes::Vecs, + ) -> Self { + Self { + weekindex: LazySumCum::from_sources( + name, + version + VERSION, + sum_source.clone(), + cumulative_source.clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), + ), + monthindex: LazySumCum::from_sources( + name, + version + VERSION, + sum_source.clone(), + cumulative_source.clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), + ), + quarterindex: LazySumCum::from_sources( + name, + version + VERSION, + sum_source.clone(), + cumulative_source.clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + ), + semesterindex: LazySumCum::from_sources( + name, + version + VERSION, + sum_source.clone(), + cumulative_source.clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + ), + yearindex: LazySumCum::from_sources( + name, + version + VERSION, + sum_source.clone(), + cumulative_source.clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), + ), + decadeindex: LazySumCum::from_sources( + name, + version + VERSION, + sum_source, + cumulative_source, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/derived/mod.rs b/crates/brk_computer/src/internal/derived/mod.rs new file mode 100644 index 000000000..477f89b19 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/mod.rs @@ -0,0 +1,5 @@ +mod date; + +pub use date::*; + +// tx derived types have been moved to computed/tx/ diff --git a/crates/brk_computer/src/internal/group/distribution.rs b/crates/brk_computer/src/internal/group/distribution.rs new file mode 100644 index 000000000..f32eb3faf --- /dev/null +++ b/crates/brk_computer/src/internal/group/distribution.rs @@ -0,0 +1,81 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{AnyVec, Database, Exit, IterableVec, VecIndex, VecValue, Version}; + +use crate::internal::ComputedVecValue; +use crate::internal::vec::AverageVec; + +use super::{MinMax, Percentiles}; + +/// Distribution stats (average + minmax + percentiles) +#[derive(Clone, Traversable)] +pub struct Distribution { + #[traversable(flatten)] + pub average: AverageVec, + #[traversable(flatten)] + pub minmax: MinMax, + pub percentiles: Percentiles, +} + +impl Distribution { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + average: AverageVec::forced_import(db, name, version)?, + minmax: MinMax::forced_import(db, name, version)?, + percentiles: Percentiles::forced_import(db, name, version)?, + }) + } + + /// Compute distribution stats from source data. + /// + /// This computes: average, min, max, percentiles (pct10, pct25, median, pct75, pct90) + pub fn compute( + &mut self, + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations( + max_from, + source, + first_indexes, + count_indexes, + exit, + None, // first + None, // last + Some(&mut self.minmax.min.0), + Some(&mut self.minmax.max.0), + Some(&mut self.average.0), + None, // sum + None, // cumulative + Some(&mut self.percentiles.median.0), + Some(&mut self.percentiles.pct10.0), + Some(&mut self.percentiles.pct25.0), + Some(&mut self.percentiles.pct75.0), + Some(&mut self.percentiles.pct90.0), + ) + } + + pub fn len(&self) -> usize { + self.average + .0 + .len() + .min(self.minmax.min.0.len()) + .min(self.minmax.max.0.len()) + .min(self.percentiles.pct10.0.len()) + .min(self.percentiles.pct25.0.len()) + .min(self.percentiles.median.0.len()) + .min(self.percentiles.pct75.0.len()) + .min(self.percentiles.pct90.0.len()) + } + + pub fn starting_index(&self, max_from: I) -> I { + max_from.min(I::from(self.len())) + } +} diff --git a/crates/brk_computer/src/internal/group/full.rs b/crates/brk_computer/src/internal/group/full.rs new file mode 100644 index 000000000..8f65185a6 --- /dev/null +++ b/crates/brk_computer/src/internal/group/full.rs @@ -0,0 +1,106 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{Database, Exit, IterableVec, VecIndex, VecValue, Version}; + +use crate::internal::ComputedVecValue; + +use super::{Distribution, SumCum}; + +/// Full stats aggregate: distribution + sum_cum +/// Matches the common full_stats() pattern: average + minmax + percentiles + sum + cumulative +#[derive(Clone, Traversable)] +pub struct Full { + pub distribution: Distribution, + pub sum_cum: SumCum, +} + +impl Full { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + distribution: Distribution::forced_import(db, name, version)?, + sum_cum: SumCum::forced_import(db, name, version)?, + }) + } + + /// Compute all stats from source data. + /// + /// This computes: average, min, max, percentiles (pct10, pct25, median, pct75, pct90), sum, cumulative + pub fn compute( + &mut self, + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations( + max_from, + source, + first_indexes, + count_indexes, + exit, + None, // first + None, // last + Some(&mut self.distribution.minmax.min.0), + Some(&mut self.distribution.minmax.max.0), + Some(&mut self.distribution.average.0), + Some(&mut self.sum_cum.sum.0), + Some(&mut self.sum_cum.cumulative.0), + Some(&mut self.distribution.percentiles.median.0), + Some(&mut self.distribution.percentiles.pct10.0), + Some(&mut self.distribution.percentiles.pct25.0), + Some(&mut self.distribution.percentiles.pct75.0), + Some(&mut self.distribution.percentiles.pct90.0), + ) + } + + pub fn len(&self) -> usize { + self.distribution.len().min(self.sum_cum.len()) + } + + pub fn starting_index(&self, max_from: I) -> I { + max_from.min(I::from(self.len())) + } + + /// Compute from aligned source (for coarser time periods like week from dateindex). + /// + /// NOTE: Percentiles cannot be derived from finer percentiles - they are skipped. + pub fn compute_from_aligned( + &mut self, + max_from: I, + source: &Full, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + // Note: Percentiles cannot be derived from finer percentiles, so we skip them + crate::internal::compute_aggregations_from_aligned( + max_from, + first_indexes, + count_indexes, + exit, + // Source vecs + None, // first not in Full + None, // last not in Full + Some(&source.distribution.minmax.min.0), + Some(&source.distribution.minmax.max.0), + Some(&source.distribution.average.0), + Some(&source.sum_cum.sum.0), + // Target vecs + None, // first + None, // last + Some(&mut self.distribution.minmax.min.0), + Some(&mut self.distribution.minmax.max.0), + Some(&mut self.distribution.average.0), + Some(&mut self.sum_cum.sum.0), + Some(&mut self.sum_cum.cumulative.0), + ) + } +} diff --git a/crates/brk_computer/src/internal/group/min_max.rs b/crates/brk_computer/src/internal/group/min_max.rs new file mode 100644 index 000000000..2e464664d --- /dev/null +++ b/crates/brk_computer/src/internal/group/min_max.rs @@ -0,0 +1,25 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{Database, VecIndex, Version}; + +use crate::internal::vec::{MaxVec, MinVec}; +use crate::internal::ComputedVecValue; + +/// Min + Max +#[derive(Clone, Traversable)] +pub struct MinMax { + #[traversable(flatten)] + pub min: MinVec, + #[traversable(flatten)] + pub max: MaxVec, +} + +impl MinMax { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + min: MinVec::forced_import(db, name, version)?, + max: MaxVec::forced_import(db, name, version)?, + }) + } +} diff --git a/crates/brk_computer/src/internal/group/min_max_average.rs b/crates/brk_computer/src/internal/group/min_max_average.rs new file mode 100644 index 000000000..4aa02f976 --- /dev/null +++ b/crates/brk_computer/src/internal/group/min_max_average.rs @@ -0,0 +1,106 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{AnyVec, Database, Exit, IterableVec, VecIndex, VecValue, Version}; + +use crate::internal::ComputedVecValue; +use crate::internal::vec::AverageVec; + +use super::MinMax; + +/// Average + MinMax (for TxIndex dateindex aggregation - no percentiles) +#[derive(Clone, Traversable)] +pub struct MinMaxAverage { + pub average: AverageVec, + #[traversable(flatten)] + pub minmax: MinMax, +} + +impl MinMaxAverage { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + average: AverageVec::forced_import(db, name, version)?, + minmax: MinMax::forced_import(db, name, version)?, + }) + } + + /// Compute average and minmax from source data. + pub fn compute( + &mut self, + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations( + max_from, + source, + first_indexes, + count_indexes, + exit, + None, // first + None, // last + Some(&mut self.minmax.min.0), + Some(&mut self.minmax.max.0), + Some(&mut self.average.0), + None, // sum + None, // cumulative + None, // median + None, // pct10 + None, // pct25 + None, // pct75 + None, // pct90 + ) + } + + /// Compute from aligned source (for coarser time periods). + pub fn compute_from_aligned( + &mut self, + max_from: I, + source: &MinMaxAverage, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations_from_aligned( + max_from, + first_indexes, + count_indexes, + exit, + // Source vecs + None, // first + None, // last + Some(&source.minmax.min.0), + Some(&source.minmax.max.0), + Some(&source.average.0), + None, // sum + // Target vecs + None, // first + None, // last + Some(&mut self.minmax.min.0), + Some(&mut self.minmax.max.0), + Some(&mut self.average.0), + None, // sum + None, // cumulative + ) + } + + pub fn len(&self) -> usize { + self.average + .0 + .len() + .min(self.minmax.min.0.len()) + .min(self.minmax.max.0.len()) + } + + pub fn starting_index(&self, max_from: I) -> I { + max_from.min(I::from(self.len())) + } +} diff --git a/crates/brk_computer/src/internal/group/mod.rs b/crates/brk_computer/src/internal/group/mod.rs new file mode 100644 index 000000000..a67e20f9d --- /dev/null +++ b/crates/brk_computer/src/internal/group/mod.rs @@ -0,0 +1,15 @@ +mod distribution; +mod full; +mod min_max; +mod min_max_average; +mod percentiles; +mod stats; +mod sum_cum; + +pub use distribution::*; +pub use full::*; +pub use min_max::*; +pub use min_max_average::*; +pub use percentiles::*; +pub use stats::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/group/percentiles.rs b/crates/brk_computer/src/internal/group/percentiles.rs new file mode 100644 index 000000000..3c8970474 --- /dev/null +++ b/crates/brk_computer/src/internal/group/percentiles.rs @@ -0,0 +1,29 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{Database, VecIndex, Version}; + +use crate::internal::vec::{MedianVec, Pct10Vec, Pct25Vec, Pct75Vec, Pct90Vec}; +use crate::internal::ComputedVecValue; + +/// All percentiles (pct10, pct25, median, pct75, pct90) +#[derive(Clone, Traversable)] +pub struct Percentiles { + pub pct10: Pct10Vec, + pub pct25: Pct25Vec, + pub median: MedianVec, + pub pct75: Pct75Vec, + pub pct90: Pct90Vec, +} + +impl Percentiles { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + pct10: Pct10Vec::forced_import(db, name, version)?, + pct25: Pct25Vec::forced_import(db, name, version)?, + median: MedianVec::forced_import(db, name, version)?, + pct75: Pct75Vec::forced_import(db, name, version)?, + pct90: Pct90Vec::forced_import(db, name, version)?, + }) + } +} diff --git a/crates/brk_computer/src/internal/group/stats.rs b/crates/brk_computer/src/internal/group/stats.rs new file mode 100644 index 000000000..fd796b2ff --- /dev/null +++ b/crates/brk_computer/src/internal/group/stats.rs @@ -0,0 +1,72 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{AnyVec, Database, Exit, IterableVec, VecIndex, VecValue, Version}; + +use crate::internal::vec::AverageVec; +use crate::internal::ComputedVecValue; + +use super::{MinMax, SumCum}; + +/// Sum + Cumulative + Average + Min + Max. Like `Full` but without percentiles. +#[derive(Clone, Traversable)] +pub struct Stats { + pub sum_cum: SumCum, + pub average: AverageVec, + pub minmax: MinMax, +} + +impl Stats { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + sum_cum: SumCum::forced_import(db, name, version)?, + average: AverageVec::forced_import(db, name, version)?, + minmax: MinMax::forced_import(db, name, version)?, + }) + } + + /// Compute sum, cumulative, average, and minmax from source data. + pub fn compute( + &mut self, + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations( + max_from, + source, + first_indexes, + count_indexes, + exit, + None, // first + None, // last + Some(&mut self.minmax.min.0), + Some(&mut self.minmax.max.0), + Some(&mut self.average.0), + Some(&mut self.sum_cum.sum.0), + Some(&mut self.sum_cum.cumulative.0), + None, // median + None, // pct10 + None, // pct25 + None, // pct75 + None, // pct90 + ) + } + + pub fn len(&self) -> usize { + self.sum_cum + .len() + .min(self.average.0.len()) + .min(self.minmax.min.0.len()) + .min(self.minmax.max.0.len()) + } + + pub fn starting_index(&self, max_from: I) -> I { + max_from.min(I::from(self.len())) + } +} diff --git a/crates/brk_computer/src/internal/group/sum_cum.rs b/crates/brk_computer/src/internal/group/sum_cum.rs new file mode 100644 index 000000000..463cc0dc3 --- /dev/null +++ b/crates/brk_computer/src/internal/group/sum_cum.rs @@ -0,0 +1,111 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use schemars::JsonSchema; +use vecdb::{AnyVec, Database, Exit, IterableVec, VecIndex, VecValue, Version}; + +use crate::internal::vec::{CumulativeVec, SumVec}; +use crate::internal::ComputedVecValue; + +/// Sum + Cumulative (12% of usage) +#[derive(Clone, Traversable)] +pub struct SumCum { + #[traversable(flatten)] + pub sum: SumVec, + #[traversable(flatten)] + pub cumulative: CumulativeVec, +} + +impl SumCum { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self { + sum: SumVec::forced_import(db, name, version)?, + cumulative: CumulativeVec::forced_import(db, name, version)?, + }) + } + + /// Compute sum and cumulative from source data. + pub fn compute( + &mut self, + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations( + max_from, + source, + first_indexes, + count_indexes, + exit, + None, // first + None, // last + None, // min + None, // max + None, // average + Some(&mut self.sum.0), + Some(&mut self.cumulative.0), + None, // median + None, // pct10 + None, // pct25 + None, // pct75 + None, // pct90 + ) + } + + /// Extend cumulative from an existing source vec. + pub fn extend_cumulative( + &mut self, + max_from: I, + source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + crate::internal::compute_cumulative_extend(max_from, source, &mut self.cumulative.0, exit) + } + + pub fn len(&self) -> usize { + self.sum.0.len().min(self.cumulative.0.len()) + } + + pub fn starting_index(&self, max_from: I) -> I { + max_from.min(I::from(self.len())) + } + + /// Compute from aligned source (for coarser time periods like week from dateindex). + pub fn compute_from_aligned( + &mut self, + max_from: I, + source: &SumCum, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + brk_types::CheckedSub, + { + crate::internal::compute_aggregations_from_aligned( + max_from, + first_indexes, + count_indexes, + exit, + // Source vecs + None, // first + None, // last + None, // min + None, // max + None, // average + Some(&source.sum.0), + // Target vecs + None, // first + None, // last + None, // min + None, // max + None, // average + Some(&mut self.sum.0), + Some(&mut self.cumulative.0), + ) + } +} diff --git a/crates/brk_computer/src/internal/lazy/binary/from_dateindex.rs b/crates/brk_computer/src/internal/lazy/binary/from_dateindex.rs deleted file mode 100644 index 590bd1d0d..000000000 --- a/crates/brk_computer/src/internal/lazy/binary/from_dateindex.rs +++ /dev/null @@ -1,259 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::{ - DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, TreeNode, Version, WeekIndex, - YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{AnyExportableVec, BinaryTransform, IterableCloneableVec, LazyVecFrom2}; - -use crate::internal::{ - ComputedVecValue, ComputedVecsFromDateIndex, ComputedVecsFromHeight, LazyTransform2Builder, -}; - -const VERSION: Version = Version::ZERO; - -/// Lazy binary transform from two `ComputedVecsFromDateIndex` sources. -#[derive(Clone)] -pub struct LazyVecsFrom2FromDateIndex -where - T: ComputedVecValue + PartialOrd + JsonSchema, - S1T: ComputedVecValue, - S2T: ComputedVecValue, -{ - pub dateindex: Option>, - pub weekindex: LazyTransform2Builder, - pub monthindex: LazyTransform2Builder, - pub quarterindex: LazyTransform2Builder, - pub semesterindex: LazyTransform2Builder, - pub yearindex: LazyTransform2Builder, - pub decadeindex: LazyTransform2Builder, -} - -impl LazyVecsFrom2FromDateIndex -where - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, - S2T: ComputedVecValue + JsonSchema, -{ - /// Create from two `ComputedVecsFromDateIndex` sources. - pub fn from_computed>( - name: &str, - version: Version, - source1: &ComputedVecsFromDateIndex, - source2: &ComputedVecsFromDateIndex, - ) -> Self { - let v = version + VERSION; - - Self { - dateindex: source1 - .dateindex - .as_ref() - .zip(source2.dateindex.as_ref()) - .map(|(s1, s2)| { - LazyVecFrom2::transformed::(name, v, s1.boxed_clone(), s2.boxed_clone()) - }), - weekindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.weekindex, - &source2.weekindex, - ), - monthindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.monthindex, - &source2.monthindex, - ), - quarterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.quarterindex, - &source2.quarterindex, - ), - semesterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.semesterindex, - &source2.semesterindex, - ), - yearindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.yearindex, - &source2.yearindex, - ), - decadeindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.decadeindex, - &source2.decadeindex, - ), - } - } - - /// Create from a `ComputedVecsFromHeight` (first source) and `ComputedVecsFromDateIndex` (second source). - /// Used for computing USD values from price (Height-based) and ratio (DateIndex-based). - pub fn from_height_and_dateindex>( - name: &str, - version: Version, - source1: &ComputedVecsFromHeight, - source2: &ComputedVecsFromDateIndex, - ) -> Self { - let v = version + VERSION; - - Self { - dateindex: source2.dateindex.as_ref().map(|s2| { - LazyVecFrom2::transformed::( - name, - v, - source1.dateindex.unwrap_last().boxed_clone(), - s2.boxed_clone(), - ) - }), - weekindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.weekindex, - &source2.weekindex, - ), - monthindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.monthindex, - &source2.monthindex, - ), - quarterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.quarterindex, - &source2.quarterindex, - ), - semesterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.semesterindex, - &source2.semesterindex, - ), - yearindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.yearindex, - &source2.yearindex, - ), - decadeindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.decadeindex, - &source2.decadeindex, - ), - } - } - - /// Create from a `ComputedVecsFromDateIndex` (first source) and `ComputedVecsFromHeight` (second source). - /// Used for ratios like NVT where numerator is from dateindex (market cap) and denominator from height (volume sum). - pub fn from_dateindex_and_height>( - name: &str, - version: Version, - source1: &ComputedVecsFromDateIndex, - source2: &ComputedVecsFromHeight, - ) -> Self - where - S2T: Ord + From + 'static, - f64: From, - { - let v = version + VERSION; - - Self { - dateindex: source1.dateindex.as_ref().map(|s1| { - LazyVecFrom2::transformed::( - name, - v, - s1.boxed_clone(), - source2.dateindex.unwrap_sum().boxed_clone(), - ) - }), - weekindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.weekindex, - &source2.weekindex, - ), - monthindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.monthindex, - &source2.monthindex, - ), - quarterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.quarterindex, - &source2.quarterindex, - ), - semesterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.semesterindex, - &source2.semesterindex, - ), - yearindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.yearindex, - &source2.yearindex, - ), - decadeindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.decadeindex, - &source2.decadeindex, - ), - } - } -} - -impl Traversable for LazyVecsFrom2FromDateIndex -where - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, - S2T: ComputedVecValue, -{ - fn to_tree_node(&self) -> TreeNode { - TreeNode::Branch( - [ - self.dateindex - .as_ref() - .map(|v| ("dateindex".to_string(), v.to_tree_node())), - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut iter: Box> = - Box::new(std::iter::empty()); - if let Some(ref v) = self.dateindex { - iter = Box::new(iter.chain(v.iter_any_exportable())); - } - iter = Box::new(iter.chain(self.weekindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.monthindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.quarterindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.semesterindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.yearindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.decadeindex.iter_any_exportable())); - iter - } -} diff --git a/crates/brk_computer/src/internal/lazy/binary/from_height.rs b/crates/brk_computer/src/internal/lazy/binary/from_height.rs deleted file mode 100644 index 7a65eaa3f..000000000 --- a/crates/brk_computer/src/internal/lazy/binary/from_height.rs +++ /dev/null @@ -1,242 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::{ - DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex, - TreeNode, Version, WeekIndex, YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{AnyExportableVec, BinaryTransform, IterableBoxedVec, LazyVecFrom2}; - -use crate::internal::{ - ComputedVecValue, ComputedVecsFromHeight, ComputedVecsFromTxindex, LazyTransform2Builder, -}; - -const VERSION: Version = Version::ZERO; - -/// Lazy binary transform from two `ComputedVecsFromHeight` sources. -#[derive(Clone)] -pub struct LazyVecsFrom2FromHeight -where - T: ComputedVecValue + PartialOrd + JsonSchema, - S1T: ComputedVecValue, - S2T: ComputedVecValue, -{ - pub height: LazyVecFrom2, - pub height_extra: LazyTransform2Builder, - pub dateindex: LazyTransform2Builder, - pub weekindex: LazyTransform2Builder, - pub difficultyepoch: LazyTransform2Builder, - pub monthindex: LazyTransform2Builder, - pub quarterindex: LazyTransform2Builder, - pub semesterindex: LazyTransform2Builder, - pub yearindex: LazyTransform2Builder, - pub decadeindex: LazyTransform2Builder, -} - -impl LazyVecsFrom2FromHeight -where - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, - S2T: ComputedVecValue + JsonSchema, -{ - /// Create from two `ComputedVecsFromHeight` sources with explicit height sources. - pub fn from_computed>( - name: &str, - version: Version, - height_source1: IterableBoxedVec, - height_source2: IterableBoxedVec, - source1: &ComputedVecsFromHeight, - source2: &ComputedVecsFromHeight, - ) -> Self { - let v = version + VERSION; - - Self { - height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), - height_extra: LazyTransform2Builder::from_eager::( - name, - v, - &source1.height_extra, - &source2.height_extra, - ), - dateindex: LazyTransform2Builder::from_eager::( - name, - v, - &source1.dateindex, - &source2.dateindex, - ), - weekindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.weekindex, - &source2.weekindex, - ), - difficultyepoch: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.difficultyepoch, - &source2.difficultyepoch, - ), - monthindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.monthindex, - &source2.monthindex, - ), - quarterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.quarterindex, - &source2.quarterindex, - ), - semesterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.semesterindex, - &source2.semesterindex, - ), - yearindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.yearindex, - &source2.yearindex, - ), - decadeindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.decadeindex, - &source2.decadeindex, - ), - } - } - - /// Create from a `ComputedVecsFromHeight` and a `ComputedVecsFromTxindex`. - /// Used for ratios like type_count / total_output_count where the denominator - /// comes from txindex-aggregated data. - pub fn from_height_and_txindex>( - name: &str, - version: Version, - height_source1: IterableBoxedVec, - height_source2: IterableBoxedVec, - source1: &ComputedVecsFromHeight, - source2: &ComputedVecsFromTxindex, - ) -> Self - where - S2T: Ord + From + 'static, - f64: From, - { - let v = version + VERSION; - - Self { - height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), - // For height_extra, source2 uses .height (EagerVecsBuilder) instead of .height_extra - height_extra: LazyTransform2Builder::from_eager::( - name, - v, - &source1.height_extra, - &source2.height, - ), - dateindex: LazyTransform2Builder::from_eager::( - name, - v, - &source1.dateindex, - &source2.dateindex, - ), - weekindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.weekindex, - &source2.weekindex, - ), - difficultyepoch: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.difficultyepoch, - &source2.difficultyepoch, - ), - monthindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.monthindex, - &source2.monthindex, - ), - quarterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.quarterindex, - &source2.quarterindex, - ), - semesterindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.semesterindex, - &source2.semesterindex, - ), - yearindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.yearindex, - &source2.yearindex, - ), - decadeindex: LazyTransform2Builder::from_lazy::( - name, - v, - &source1.decadeindex, - &source2.decadeindex, - ), - } - } -} - -impl Traversable for LazyVecsFrom2FromHeight -where - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, - S2T: ComputedVecValue, -{ - fn to_tree_node(&self) -> TreeNode { - let height_extra_node = self.height_extra.to_tree_node(); - TreeNode::Branch( - [ - Some(("height".to_string(), self.height.to_tree_node())), - if height_extra_node.is_empty() { - None - } else { - Some(("height_extra".to_string(), height_extra_node)) - }, - Some(("dateindex".to_string(), self.dateindex.to_tree_node())), - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(( - "difficultyepoch".to_string(), - self.difficultyepoch.to_tree_node(), - )), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut iter: Box> = - Box::new(self.height.iter_any_exportable()); - iter = Box::new(iter.chain(self.height_extra.iter_any_exportable())); - iter = Box::new(iter.chain(self.dateindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.weekindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.difficultyepoch.iter_any_exportable())); - iter = Box::new(iter.chain(self.monthindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.quarterindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.semesterindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.yearindex.iter_any_exportable())); - iter = Box::new(iter.chain(self.decadeindex.iter_any_exportable())); - iter - } -} diff --git a/crates/brk_computer/src/internal/lazy/binary/mod.rs b/crates/brk_computer/src/internal/lazy/binary/mod.rs deleted file mode 100644 index df9caa6e0..000000000 --- a/crates/brk_computer/src/internal/lazy/binary/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod from_dateindex; -mod from_height; - -pub use from_dateindex::*; -pub use from_height::*; diff --git a/crates/brk_computer/src/internal/lazy/block/binary_full.rs b/crates/brk_computer/src/internal/lazy/block/binary_full.rs new file mode 100644 index 000000000..bb9e3d57a --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/binary_full.rs @@ -0,0 +1,61 @@ +//! Lazy binary transform from Full sources. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, LazyVecFrom2}; + +use crate::internal::{ComputedBlockFull, ComputedVecValue, DerivedTxFull, NumericValue}; + +use super::super::derived_block::LazyDerivedBlock2SumCum; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct BinaryBlockFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom2, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlock2SumCum, +} + +const VERSION: Version = Version::ZERO; + +impl BinaryBlockFull +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: NumericValue + JsonSchema, + S2T: NumericValue + JsonSchema, +{ + pub fn from_height_and_txindex>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &ComputedBlockFull, + source2: &DerivedTxFull, + ) -> Self { + let v = version + VERSION; + + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyDerivedBlock2SumCum::from_derived_full::( + name, + v, + &source1.dateindex.sum_cum, + &source1.rest, + &source1.difficultyepoch, + &source2.dateindex.sum_cum, + &source2.dates, + &source2.difficultyepoch, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/binary_sum.rs b/crates/brk_computer/src/internal/lazy/block/binary_sum.rs new file mode 100644 index 000000000..41c03752b --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/binary_sum.rs @@ -0,0 +1,52 @@ +//! Lazy binary transform from two Sum-only sources with height level. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, LazyVecFrom2}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockSum, NumericValue}; + +use super::super::derived_block::LazyDerivedBlock2Sum; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct BinaryBlockSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom2, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlock2Sum, +} + +impl BinaryBlockSum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: NumericValue + JsonSchema, + S2T: NumericValue + JsonSchema, +{ + pub fn from_derived>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &DerivedComputedBlockSum, + source2: &DerivedComputedBlockSum, + ) -> Self { + let v = version + VERSION; + + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyDerivedBlock2Sum::from_derived::(name, v, source1, source2), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/binary_sum_cum.rs b/crates/brk_computer/src/internal/lazy/block/binary_sum_cum.rs new file mode 100644 index 000000000..65f45a61a --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/binary_sum_cum.rs @@ -0,0 +1,108 @@ +//! Lazy binary transform from two SumCum sources. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2}; + +use crate::internal::{ComputedBlockSumCum, ComputedVecValue, DerivedComputedBlockSumCum}; + +use super::super::derived_block::LazyDerivedBlock2SumCum; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct BinaryBlockSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom2, + #[traversable(wrap = "cumulative")] + pub height_cumulative: LazyVecFrom2, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlock2SumCum, +} + +const VERSION: Version = Version::ZERO; + +impl BinaryBlockSumCum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &ComputedBlockSumCum, + source2: &ComputedBlockSumCum, + ) -> Self + where + S1T: PartialOrd, + S2T: PartialOrd, + { + let v = version + VERSION; + + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + height_cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + v, + source1.height_cumulative.0.boxed_clone(), + source2.height_cumulative.0.boxed_clone(), + ), + rest: LazyDerivedBlock2SumCum::from_computed::( + name, + v, + &source1.dateindex, + &source1.rest, + &source1.difficultyepoch, + &source2.dateindex, + &source2.rest, + &source2.difficultyepoch, + ), + } + } + + pub fn from_derived>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &DerivedComputedBlockSumCum, + source2: &DerivedComputedBlockSumCum, + ) -> Self + where + S1T: PartialOrd, + S2T: PartialOrd, + { + let v = version + VERSION; + + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + height_cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + v, + source1.height_cumulative.0.boxed_clone(), + source2.height_cumulative.0.boxed_clone(), + ), + rest: LazyDerivedBlock2SumCum::from_computed::( + name, + v, + &source1.dateindex, + source1, + &source1.difficultyepoch, + &source2.dateindex, + source2, + &source2.difficultyepoch, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/binary_sum_cum_last.rs b/crates/brk_computer/src/internal/lazy/block/binary_sum_cum_last.rs new file mode 100644 index 000000000..7411061dd --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/binary_sum_cum_last.rs @@ -0,0 +1,121 @@ +//! Lazy binary transform from SumCum + Last sources. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, LazyVecFrom2}; + +use crate::internal::{ + ComputedBlockLast, ComputedBlockSumCum, ComputedVecValue, DerivedComputedBlockLast, + DerivedComputedBlockSumCum, NumericValue, +}; + +use super::super::derived_block::LazyDerivedBlock2SumCumLast; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct BinaryBlockSumCumLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom2, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlock2SumCumLast, +} + +const VERSION: Version = Version::ZERO; + +impl BinaryBlockSumCumLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &ComputedBlockSumCum, + source2: &ComputedBlockLast, + ) -> Self + where + S1T: PartialOrd, + S2T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyDerivedBlock2SumCumLast::from_computed::(name, v, source1, source2), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &DerivedComputedBlockSumCum, + source2: &ComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + S2T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyDerivedBlock2SumCumLast::from_derived_computed_full::( + name, v, source1, source2, + ), + } + } + + pub fn from_derived>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &DerivedComputedBlockSumCum, + source2: &DerivedComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + S2T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyDerivedBlock2SumCumLast::from_derived_computed::( + name, v, source1, source2, + ), + } + } + + pub fn from_computed_derived>( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &ComputedBlockSumCum, + source2: &DerivedComputedBlockLast, + ) -> Self + where + S1T: PartialOrd, + S2T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom2::transformed::(name, v, height_source1, height_source2), + rest: LazyDerivedBlock2SumCumLast::from_computed_derived_computed::( + name, v, source1, source2, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/full.rs b/crates/brk_computer/src/internal/lazy/block/full.rs new file mode 100644 index 000000000..d45bb8a7d --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/full.rs @@ -0,0 +1,70 @@ +//! Lazy unary transform from height with Full aggregation. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ + ComputedBlockFull, ComputedVecValue, DerivedComputedBlockFull, NumericValue, +}; + +use super::super::derived_block::LazyDerivedBlockFull; +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyBlockFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom1, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlockFull, +} + +const VERSION: Version = Version::ZERO; + +impl LazyBlockFull +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &ComputedBlockFull, + ) -> Self { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockFull::from_computed::( + name, + v, + &source.dateindex, + &source.rest, + &source.difficultyepoch, + ), + } + } + + pub fn from_derived>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &DerivedComputedBlockFull, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockFull::from_derived_computed::(name, v, source), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/last.rs b/crates/brk_computer/src/internal/lazy/block/last.rs new file mode 100644 index 000000000..24c6f25c1 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/last.rs @@ -0,0 +1,66 @@ +//! Lazy unary transform from height with Last aggregation. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ + ComputedBlockLast, ComputedVecValue, DerivedComputedBlockLast, NumericValue, +}; + +use super::super::derived_block::LazyDerivedBlockLast; +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyBlockLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub height: LazyVecFrom1, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlockLast, +} + +const VERSION: Version = Version::ZERO; + +impl LazyBlockLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &ComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockLast::from_computed::(name, v, source), + } + } + + pub fn from_derived>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &DerivedComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockLast::from_derived_computed::(name, v, source), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/mod.rs b/crates/brk_computer/src/internal/lazy/block/mod.rs new file mode 100644 index 000000000..710b64349 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/mod.rs @@ -0,0 +1,17 @@ +mod binary_full; +mod binary_sum; +mod binary_sum_cum; +mod binary_sum_cum_last; +mod full; +mod last; +mod sum; +mod sum_cum; + +pub use binary_full::*; +pub use binary_sum::*; +pub use binary_sum_cum::*; +pub use binary_sum_cum_last::*; +pub use full::*; +pub use last::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/lazy/block/sum.rs b/crates/brk_computer/src/internal/lazy/block/sum.rs new file mode 100644 index 000000000..655289428 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/sum.rs @@ -0,0 +1,68 @@ +//! Lazy unary transform from height with Sum aggregation. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ComputedBlockSum, ComputedVecValue, DerivedComputedBlockSum, NumericValue}; + +use super::super::derived_block::LazyDerivedBlockSum; +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyBlockSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom1, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlockSum, +} + +const VERSION: Version = Version::ZERO; + +impl LazyBlockSum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &ComputedBlockSum, + ) -> Self { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockSum::from_computed::( + name, + v, + &source.dateindex, + &source.rest, + &source.difficultyepoch, + ), + } + } + + pub fn from_derived>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &DerivedComputedBlockSum, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockSum::from_derived_computed::(name, v, source), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/block/sum_cum.rs b/crates/brk_computer/src/internal/lazy/block/sum_cum.rs new file mode 100644 index 000000000..6b88f0d0f --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/block/sum_cum.rs @@ -0,0 +1,70 @@ +//! Lazy unary transform from height with SumCum aggregation. + +use brk_traversable::Traversable; +use brk_types::{Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ + ComputedBlockSumCum, ComputedVecValue, DerivedComputedBlockSumCum, NumericValue, +}; + +use super::super::derived_block::LazyDerivedBlockSumCum; +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyBlockSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[traversable(wrap = "base")] + pub height: LazyVecFrom1, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlockSumCum, +} + +const VERSION: Version = Version::ZERO; + +impl LazyBlockSumCum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &ComputedBlockSumCum, + ) -> Self { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockSumCum::from_computed::( + name, + v, + &source.dateindex, + &source.rest, + &source.difficultyepoch, + ), + } + } + + pub fn from_derived>( + name: &str, + version: Version, + height_source: IterableBoxedVec, + source: &DerivedComputedBlockSumCum, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + Self { + height: LazyVecFrom1::transformed::(name, v, height_source), + rest: LazyDerivedBlockSumCum::from_derived_computed::(name, v, source), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/date/binary_last.rs b/crates/brk_computer/src/internal/lazy/date/binary_last.rs new file mode 100644 index 000000000..35543fa93 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/binary_last.rs @@ -0,0 +1,320 @@ +//! Binary transform composite from DateIndex - Last aggregation only. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2}; + +use crate::internal::{ + ComputedBlockLast, ComputedBlockSum, ComputedDateLast, ComputedVecValue, DerivedDateLast, + NumericValue, +}; + +use super::super::transform::LazyTransform2Last; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct BinaryDateLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub dateindex: LazyVecFrom2, + pub weekindex: LazyTransform2Last, + pub monthindex: LazyTransform2Last, + pub quarterindex: LazyTransform2Last, + pub semesterindex: LazyTransform2Last, + pub yearindex: LazyTransform2Last, + pub decadeindex: LazyTransform2Last, +} + +impl BinaryDateLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed_both_last>( + name: &str, + version: Version, + source1: &ComputedDateLast, + source2: &ComputedDateLast, + ) -> Self { + let v = version + VERSION; + + Self { + dateindex: LazyVecFrom2::transformed::( + name, + v, + source1.dateindex.boxed_clone(), + source2.dateindex.boxed_clone(), + ), + weekindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.weekindex, + &source2.weekindex, + ), + monthindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.monthindex, + &source2.monthindex, + ), + quarterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.quarterindex, + &source2.quarterindex, + ), + semesterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.semesterindex, + &source2.semesterindex, + ), + yearindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.yearindex, + &source2.yearindex, + ), + decadeindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.decadeindex, + &source2.decadeindex, + ), + } + } + + pub fn from_derived_last_and_computed_last>( + name: &str, + version: Version, + dateindex_source1: IterableBoxedVec, + source1: &DerivedDateLast, + source2: &ComputedDateLast, + ) -> Self { + let v = version + VERSION; + + Self { + dateindex: LazyVecFrom2::transformed::( + name, + v, + dateindex_source1, + source2.dateindex.boxed_clone(), + ), + weekindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.weekindex, + &source2.weekindex, + ), + monthindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.monthindex, + &source2.monthindex, + ), + quarterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.quarterindex, + &source2.quarterindex, + ), + semesterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.semesterindex, + &source2.semesterindex, + ), + yearindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.yearindex, + &source2.yearindex, + ), + decadeindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.decadeindex, + &source2.decadeindex, + ), + } + } + + pub fn from_both_derived_last>( + name: &str, + version: Version, + dateindex_source1: IterableBoxedVec, + source1: &DerivedDateLast, + dateindex_source2: IterableBoxedVec, + source2: &DerivedDateLast, + ) -> Self { + let v = version + VERSION; + + Self { + dateindex: LazyVecFrom2::transformed::( + name, + v, + dateindex_source1, + dateindex_source2, + ), + weekindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.weekindex, + &source2.weekindex, + ), + monthindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.monthindex, + &source2.monthindex, + ), + quarterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.quarterindex, + &source2.quarterindex, + ), + semesterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.semesterindex, + &source2.semesterindex, + ), + yearindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.yearindex, + &source2.yearindex, + ), + decadeindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.decadeindex, + &source2.decadeindex, + ), + } + } + + pub fn from_height_and_dateindex_last>( + name: &str, + version: Version, + source1: &ComputedBlockLast, + source2: &ComputedDateLast, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + + Self { + dateindex: LazyVecFrom2::transformed::( + name, + v, + source1.dateindex.0.boxed_clone(), + source2.dateindex.boxed_clone(), + ), + weekindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.weekindex, + &source2.weekindex, + ), + monthindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.monthindex, + &source2.monthindex, + ), + quarterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.quarterindex, + &source2.quarterindex, + ), + semesterindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.semesterindex, + &source2.semesterindex, + ), + yearindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.yearindex, + &source2.yearindex, + ), + decadeindex: LazyTransform2Last::from_lazy_last::( + name, + v, + &source1.decadeindex, + &source2.decadeindex, + ), + } + } + + pub fn from_dateindex_last_and_height_sum>( + name: &str, + version: Version, + source1: &ComputedDateLast, + source2: &ComputedBlockSum, + ) -> Self + where + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dateindex: LazyVecFrom2::transformed::( + name, + v, + source1.dateindex.boxed_clone(), + source2.dateindex.0.boxed_clone(), + ), + weekindex: LazyTransform2Last::from_vecs::( + name, + v, + source1.weekindex.boxed_clone(), + source2.weekindex.boxed_clone(), + ), + monthindex: LazyTransform2Last::from_vecs::( + name, + v, + source1.monthindex.boxed_clone(), + source2.monthindex.boxed_clone(), + ), + quarterindex: LazyTransform2Last::from_vecs::( + name, + v, + source1.quarterindex.boxed_clone(), + source2.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransform2Last::from_vecs::( + name, + v, + source1.semesterindex.boxed_clone(), + source2.semesterindex.boxed_clone(), + ), + yearindex: LazyTransform2Last::from_vecs::( + name, + v, + source1.yearindex.boxed_clone(), + source2.yearindex.boxed_clone(), + ), + decadeindex: LazyTransform2Last::from_vecs::( + name, + v, + source1.decadeindex.boxed_clone(), + source2.decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/date/binary_sum.rs b/crates/brk_computer/src/internal/lazy/date/binary_sum.rs new file mode 100644 index 000000000..1c8befc8b --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/binary_sum.rs @@ -0,0 +1,90 @@ +//! Binary transform for Sum-only pattern across date periods. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockSum, LazyTransform2Sum, NumericValue}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDate2Sum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub dateindex: LazyTransform2Sum, + pub weekindex: LazyTransform2Sum, + pub monthindex: LazyTransform2Sum, + pub quarterindex: LazyTransform2Sum, + pub semesterindex: LazyTransform2Sum, + pub yearindex: LazyTransform2Sum, + pub decadeindex: LazyTransform2Sum, +} + +impl LazyDate2Sum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: NumericValue + JsonSchema, + S2T: NumericValue + JsonSchema, +{ + pub fn from_derived>( + name: &str, + version: Version, + source1: &DerivedComputedBlockSum, + source2: &DerivedComputedBlockSum, + ) -> Self { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2Sum::from_sum::( + name, + v, + &source1.dateindex, + &source2.dateindex, + ), + weekindex: LazyTransform2Sum::from_boxed::( + name, + v, + source1.weekindex.boxed_clone(), + source2.weekindex.boxed_clone(), + ), + monthindex: LazyTransform2Sum::from_boxed::( + name, + v, + source1.monthindex.boxed_clone(), + source2.monthindex.boxed_clone(), + ), + quarterindex: LazyTransform2Sum::from_boxed::( + name, + v, + source1.quarterindex.boxed_clone(), + source2.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransform2Sum::from_boxed::( + name, + v, + source1.semesterindex.boxed_clone(), + source2.semesterindex.boxed_clone(), + ), + yearindex: LazyTransform2Sum::from_boxed::( + name, + v, + source1.yearindex.boxed_clone(), + source2.yearindex.boxed_clone(), + ), + decadeindex: LazyTransform2Sum::from_boxed::( + name, + v, + source1.decadeindex.boxed_clone(), + source2.decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/date/binary_sum_cum.rs b/crates/brk_computer/src/internal/lazy/date/binary_sum_cum.rs new file mode 100644 index 000000000..a31026d6f --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/binary_sum_cum.rs @@ -0,0 +1,153 @@ +//! Binary transform for SumCum pattern across date periods. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec}; + +use crate::internal::{ComputedVecValue, DerivedDateFull, DerivedDateSumCum, SumCum}; + +use super::super::transform::LazyTransform2SumCum; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDate2SumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub dateindex: LazyTransform2SumCum, + pub weekindex: LazyTransform2SumCum, + pub monthindex: LazyTransform2SumCum, + pub quarterindex: LazyTransform2SumCum, + pub semesterindex: LazyTransform2SumCum, + pub yearindex: LazyTransform2SumCum, + pub decadeindex: LazyTransform2SumCum, +} + +impl LazyDate2SumCum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + #[allow(clippy::too_many_arguments)] + pub fn from_computed>( + name: &str, + version: Version, + dateindex1: &SumCum, + periods1: &DerivedDateSumCum, + dateindex2: &SumCum, + periods2: &DerivedDateSumCum, + ) -> Self { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2SumCum::from_sum_cum::(name, v, dateindex1, dateindex2), + weekindex: LazyTransform2SumCum::from_sources::( + name, + v, + periods1.weekindex.sum.boxed_clone(), + periods2.weekindex.sum.boxed_clone(), + periods1.weekindex.cumulative.boxed_clone(), + periods2.weekindex.cumulative.boxed_clone(), + ), + monthindex: LazyTransform2SumCum::from_sources::( + name, + v, + periods1.monthindex.sum.boxed_clone(), + periods2.monthindex.sum.boxed_clone(), + periods1.monthindex.cumulative.boxed_clone(), + periods2.monthindex.cumulative.boxed_clone(), + ), + quarterindex: LazyTransform2SumCum::from_sources::( + name, + v, + periods1.quarterindex.sum.boxed_clone(), + periods2.quarterindex.sum.boxed_clone(), + periods1.quarterindex.cumulative.boxed_clone(), + periods2.quarterindex.cumulative.boxed_clone(), + ), + semesterindex: LazyTransform2SumCum::from_sources::( + name, + v, + periods1.semesterindex.sum.boxed_clone(), + periods2.semesterindex.sum.boxed_clone(), + periods1.semesterindex.cumulative.boxed_clone(), + periods2.semesterindex.cumulative.boxed_clone(), + ), + yearindex: LazyTransform2SumCum::from_sources::( + name, + v, + periods1.yearindex.sum.boxed_clone(), + periods2.yearindex.sum.boxed_clone(), + periods1.yearindex.cumulative.boxed_clone(), + periods2.yearindex.cumulative.boxed_clone(), + ), + decadeindex: LazyTransform2SumCum::from_sources::( + name, + v, + periods1.decadeindex.sum.boxed_clone(), + periods2.decadeindex.sum.boxed_clone(), + periods1.decadeindex.cumulative.boxed_clone(), + periods2.decadeindex.cumulative.boxed_clone(), + ), + } + } + + pub fn from_derived_full>( + name: &str, + version: Version, + dateindex1: &SumCum, + dates1: &DerivedDateFull, + dateindex2: &SumCum, + dates2: &DerivedDateFull, + ) -> Self { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2SumCum::from_sum_cum::(name, v, dateindex1, dateindex2), + weekindex: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + &dates1.weekindex, + &dates2.weekindex, + ), + monthindex: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + &dates1.monthindex, + &dates2.monthindex, + ), + quarterindex: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + &dates1.quarterindex, + &dates2.quarterindex, + ), + semesterindex: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + &dates1.semesterindex, + &dates2.semesterindex, + ), + yearindex: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + &dates1.yearindex, + &dates2.yearindex, + ), + decadeindex: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + &dates1.decadeindex, + &dates2.decadeindex, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/date/binary_sum_cum_last.rs b/crates/brk_computer/src/internal/lazy/date/binary_sum_cum_last.rs new file mode 100644 index 000000000..e82b456b6 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/binary_sum_cum_last.rs @@ -0,0 +1,297 @@ +//! Binary transform for SumCum + Last pattern across date periods. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec}; + +use crate::internal::{ + ComputedBlockLast, ComputedBlockSumCum, ComputedVecValue, DerivedComputedBlockLast, + DerivedComputedBlockSumCum, NumericValue, +}; + +use super::super::transform::LazyTransform2SumCumLast; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDate2SumCumLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub dateindex: LazyTransform2SumCumLast, + pub weekindex: LazyTransform2SumCumLast, + pub monthindex: LazyTransform2SumCumLast, + pub quarterindex: LazyTransform2SumCumLast, + pub semesterindex: LazyTransform2SumCumLast, + pub yearindex: LazyTransform2SumCumLast, + pub decadeindex: LazyTransform2SumCumLast, +} + +impl LazyDate2SumCumLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + source1: &ComputedBlockSumCum, + source2: &ComputedBlockLast, + ) -> Self + where + S1T: PartialOrd, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2SumCumLast::from_sources::( + name, + v, + &source1.dateindex, + &source2.dateindex, + ), + weekindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.weekindex.sum.boxed_clone(), + source1.rest.weekindex.cumulative.boxed_clone(), + source2.rest.weekindex.boxed_clone(), + ), + monthindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.monthindex.sum.boxed_clone(), + source1.rest.monthindex.cumulative.boxed_clone(), + source2.rest.monthindex.boxed_clone(), + ), + quarterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.quarterindex.sum.boxed_clone(), + source1.rest.quarterindex.cumulative.boxed_clone(), + source2.rest.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.semesterindex.sum.boxed_clone(), + source1.rest.semesterindex.cumulative.boxed_clone(), + source2.rest.semesterindex.boxed_clone(), + ), + yearindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.yearindex.sum.boxed_clone(), + source1.rest.yearindex.cumulative.boxed_clone(), + source2.rest.yearindex.boxed_clone(), + ), + decadeindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.decadeindex.sum.boxed_clone(), + source1.rest.decadeindex.cumulative.boxed_clone(), + source2.rest.decadeindex.boxed_clone(), + ), + } + } + + pub fn from_derived_computed_full>( + name: &str, + version: Version, + source1: &DerivedComputedBlockSumCum, + source2: &ComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2SumCumLast::from_sources::( + name, + v, + &source1.dateindex, + &source2.dateindex, + ), + weekindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.weekindex.sum.boxed_clone(), + source1.weekindex.cumulative.boxed_clone(), + source2.rest.weekindex.boxed_clone(), + ), + monthindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.monthindex.sum.boxed_clone(), + source1.monthindex.cumulative.boxed_clone(), + source2.rest.monthindex.boxed_clone(), + ), + quarterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.quarterindex.sum.boxed_clone(), + source1.quarterindex.cumulative.boxed_clone(), + source2.rest.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.semesterindex.sum.boxed_clone(), + source1.semesterindex.cumulative.boxed_clone(), + source2.rest.semesterindex.boxed_clone(), + ), + yearindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.yearindex.sum.boxed_clone(), + source1.yearindex.cumulative.boxed_clone(), + source2.rest.yearindex.boxed_clone(), + ), + decadeindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.decadeindex.sum.boxed_clone(), + source1.decadeindex.cumulative.boxed_clone(), + source2.rest.decadeindex.boxed_clone(), + ), + } + } + + pub fn from_computed_derived_computed>( + name: &str, + version: Version, + source1: &ComputedBlockSumCum, + source2: &DerivedComputedBlockLast, + ) -> Self + where + S1T: PartialOrd, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2SumCumLast::from_sources::( + name, + v, + &source1.dateindex, + &source2.dateindex, + ), + weekindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.weekindex.sum.boxed_clone(), + source1.rest.weekindex.cumulative.boxed_clone(), + source2.weekindex.boxed_clone(), + ), + monthindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.monthindex.sum.boxed_clone(), + source1.rest.monthindex.cumulative.boxed_clone(), + source2.monthindex.boxed_clone(), + ), + quarterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.quarterindex.sum.boxed_clone(), + source1.rest.quarterindex.cumulative.boxed_clone(), + source2.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.semesterindex.sum.boxed_clone(), + source1.rest.semesterindex.cumulative.boxed_clone(), + source2.semesterindex.boxed_clone(), + ), + yearindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.yearindex.sum.boxed_clone(), + source1.rest.yearindex.cumulative.boxed_clone(), + source2.yearindex.boxed_clone(), + ), + decadeindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.rest.decadeindex.sum.boxed_clone(), + source1.rest.decadeindex.cumulative.boxed_clone(), + source2.decadeindex.boxed_clone(), + ), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + source1: &DerivedComputedBlockSumCum, + source2: &DerivedComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dateindex: LazyTransform2SumCumLast::from_sources::( + name, + v, + &source1.dateindex, + &source2.dateindex, + ), + weekindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.weekindex.sum.boxed_clone(), + source1.weekindex.cumulative.boxed_clone(), + source2.weekindex.boxed_clone(), + ), + monthindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.monthindex.sum.boxed_clone(), + source1.monthindex.cumulative.boxed_clone(), + source2.monthindex.boxed_clone(), + ), + quarterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.quarterindex.sum.boxed_clone(), + source1.quarterindex.cumulative.boxed_clone(), + source2.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.semesterindex.sum.boxed_clone(), + source1.semesterindex.cumulative.boxed_clone(), + source2.semesterindex.boxed_clone(), + ), + yearindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.yearindex.sum.boxed_clone(), + source1.yearindex.cumulative.boxed_clone(), + source2.yearindex.boxed_clone(), + ), + decadeindex: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.decadeindex.sum.boxed_clone(), + source1.decadeindex.cumulative.boxed_clone(), + source2.decadeindex.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/date/full.rs b/crates/brk_computer/src/internal/lazy/date/full.rs new file mode 100644 index 000000000..99062ae20 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/full.rs @@ -0,0 +1,101 @@ +//! Lazy transform for Full date sources. + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ComputedVecValue, DerivedDateFull, Full}; + +use super::super::transform::LazyTransformFull; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDateFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub dateindex: LazyTransformFull, + pub weekindex: LazyTransformFull, + pub monthindex: LazyTransformFull, + pub quarterindex: LazyTransformFull, + pub semesterindex: LazyTransformFull, + pub yearindex: LazyTransformFull, + pub decadeindex: LazyTransformFull, +} + +impl LazyDateFull +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_full>( + name: &str, + version: Version, + dateindex: &Full, + source: &DerivedDateFull, + ) -> Self { + let v = version + VERSION; + Self { + dateindex: LazyTransformFull::from_stats_aggregate::(name, v, dateindex), + weekindex: LazyTransformFull::from_boxed::( + name, + v, + source.weekindex.average.boxed_clone(), + source.weekindex.min.boxed_clone(), + source.weekindex.max.boxed_clone(), + source.weekindex.sum.boxed_clone(), + source.weekindex.cumulative.boxed_clone(), + ), + monthindex: LazyTransformFull::from_boxed::( + name, + v, + source.monthindex.average.boxed_clone(), + source.monthindex.min.boxed_clone(), + source.monthindex.max.boxed_clone(), + source.monthindex.sum.boxed_clone(), + source.monthindex.cumulative.boxed_clone(), + ), + quarterindex: LazyTransformFull::from_boxed::( + name, + v, + source.quarterindex.average.boxed_clone(), + source.quarterindex.min.boxed_clone(), + source.quarterindex.max.boxed_clone(), + source.quarterindex.sum.boxed_clone(), + source.quarterindex.cumulative.boxed_clone(), + ), + semesterindex: LazyTransformFull::from_boxed::( + name, + v, + source.semesterindex.average.boxed_clone(), + source.semesterindex.min.boxed_clone(), + source.semesterindex.max.boxed_clone(), + source.semesterindex.sum.boxed_clone(), + source.semesterindex.cumulative.boxed_clone(), + ), + yearindex: LazyTransformFull::from_boxed::( + name, + v, + source.yearindex.average.boxed_clone(), + source.yearindex.min.boxed_clone(), + source.yearindex.max.boxed_clone(), + source.yearindex.sum.boxed_clone(), + source.yearindex.cumulative.boxed_clone(), + ), + decadeindex: LazyTransformFull::from_boxed::( + name, + v, + source.decadeindex.average.boxed_clone(), + source.decadeindex.min.boxed_clone(), + source.decadeindex.max.boxed_clone(), + source.decadeindex.sum.boxed_clone(), + source.decadeindex.cumulative.boxed_clone(), + ), + } + } + +} diff --git a/crates/brk_computer/src/internal/lazy/date/last.rs b/crates/brk_computer/src/internal/lazy/date/last.rs new file mode 100644 index 000000000..89bfab06d --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/last.rs @@ -0,0 +1,79 @@ +//! Lazy transform for Last-only date sources. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ComputedDateLast, ComputedVecValue, DerivedDateLast}; + +use super::super::transform::LazyTransformLast; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDateLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub dateindex: LazyTransformLast, + pub weekindex: LazyTransformLast, + pub monthindex: LazyTransformLast, + pub quarterindex: LazyTransformLast, + pub semesterindex: LazyTransformLast, + pub yearindex: LazyTransformLast, + pub decadeindex: LazyTransformLast, +} + +impl LazyDateLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_source>( + name: &str, + version: Version, + source: &ComputedDateLast, + ) -> Self { + Self::from_computed::(name, version, source.dateindex.boxed_clone(), source) + } + + pub fn from_computed>( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + source: &ComputedDateLast, + ) -> Self { + Self::from_derived::(name, version, dateindex_source, &source.rest) + } + + pub fn from_derived>( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + source: &DerivedDateLast, + ) -> Self { + let v = version + VERSION; + Self { + dateindex: LazyTransformLast::from_boxed::(name, v, dateindex_source), + weekindex: LazyTransformLast::from_lazy_last::(name, v, &source.weekindex), + monthindex: LazyTransformLast::from_lazy_last::(name, v, &source.monthindex), + quarterindex: LazyTransformLast::from_lazy_last::( + name, + v, + &source.quarterindex, + ), + semesterindex: LazyTransformLast::from_lazy_last::( + name, + v, + &source.semesterindex, + ), + yearindex: LazyTransformLast::from_lazy_last::(name, v, &source.yearindex), + decadeindex: LazyTransformLast::from_lazy_last::(name, v, &source.decadeindex), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/date/mod.rs b/crates/brk_computer/src/internal/lazy/date/mod.rs new file mode 100644 index 000000000..2273f7385 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/mod.rs @@ -0,0 +1,17 @@ +mod binary_last; +mod binary_sum; +mod binary_sum_cum; +mod binary_sum_cum_last; +mod full; +mod last; +mod sum; +mod sum_cum; + +pub use binary_last::*; +pub use binary_sum::*; +pub use binary_sum_cum::*; +pub use binary_sum_cum_last::*; +pub use full::*; +pub use last::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/lazy/date/sum.rs b/crates/brk_computer/src/internal/lazy/date/sum.rs new file mode 100644 index 000000000..340a2ccd2 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/sum.rs @@ -0,0 +1,53 @@ +//! Lazy transform for Sum-only date sources. + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ComputedVecValue, DerivedDateSum}; + +use super::super::transform::LazyTransformSum; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDateSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub dateindex: LazyTransformSum, + pub weekindex: LazyTransformSum, + pub monthindex: LazyTransformSum, + pub quarterindex: LazyTransformSum, + pub semesterindex: LazyTransformSum, + pub yearindex: LazyTransformSum, + pub decadeindex: LazyTransformSum, +} + +impl LazyDateSum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_derived>( + name: &str, + version: Version, + dateindex_source: IterableBoxedVec, + source: &DerivedDateSum, + ) -> Self { + let v = version + VERSION; + Self { + dateindex: LazyTransformSum::from_boxed::(name, v, dateindex_source), + weekindex: LazyTransformSum::from_boxed::(name, v, source.weekindex.boxed_clone()), + monthindex: LazyTransformSum::from_boxed::(name, v, source.monthindex.boxed_clone()), + quarterindex: LazyTransformSum::from_boxed::(name, v, source.quarterindex.boxed_clone()), + semesterindex: LazyTransformSum::from_boxed::(name, v, source.semesterindex.boxed_clone()), + yearindex: LazyTransformSum::from_boxed::(name, v, source.yearindex.boxed_clone()), + decadeindex: LazyTransformSum::from_boxed::(name, v, source.decadeindex.boxed_clone()), + } + } + +} diff --git a/crates/brk_computer/src/internal/lazy/date/sum_cum.rs b/crates/brk_computer/src/internal/lazy/date/sum_cum.rs new file mode 100644 index 000000000..b72cb7d9f --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/date/sum_cum.rs @@ -0,0 +1,82 @@ +//! Lazy transform for SumCum date sources. + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ComputedVecValue, DerivedDateSumCum, SumCum}; + +use super::super::transform::LazyTransformSumCum; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDateSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub dateindex: LazyTransformSumCum, + pub weekindex: LazyTransformSumCum, + pub monthindex: LazyTransformSumCum, + pub quarterindex: LazyTransformSumCum, + pub semesterindex: LazyTransformSumCum, + pub yearindex: LazyTransformSumCum, + pub decadeindex: LazyTransformSumCum, +} + +impl LazyDateSumCum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_sum_cum>( + name: &str, + version: Version, + dateindex: &SumCum, + source: &DerivedDateSumCum, + ) -> Self { + let v = version + VERSION; + Self { + dateindex: LazyTransformSumCum::from_sum_cum::(name, v, dateindex), + weekindex: LazyTransformSumCum::from_boxed::( + name, + v, + source.weekindex.sum.boxed_clone(), + source.weekindex.cumulative.boxed_clone(), + ), + monthindex: LazyTransformSumCum::from_boxed::( + name, + v, + source.monthindex.sum.boxed_clone(), + source.monthindex.cumulative.boxed_clone(), + ), + quarterindex: LazyTransformSumCum::from_boxed::( + name, + v, + source.quarterindex.sum.boxed_clone(), + source.quarterindex.cumulative.boxed_clone(), + ), + semesterindex: LazyTransformSumCum::from_boxed::( + name, + v, + source.semesterindex.sum.boxed_clone(), + source.semesterindex.cumulative.boxed_clone(), + ), + yearindex: LazyTransformSumCum::from_boxed::( + name, + v, + source.yearindex.sum.boxed_clone(), + source.yearindex.cumulative.boxed_clone(), + ), + decadeindex: LazyTransformSumCum::from_boxed::( + name, + v, + source.decadeindex.sum.boxed_clone(), + source.decadeindex.cumulative.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/binary_sum.rs b/crates/brk_computer/src/internal/lazy/derived_block/binary_sum.rs new file mode 100644 index 000000000..12aa4446d --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/binary_sum.rs @@ -0,0 +1,52 @@ +//! Lazy aggregated binary transform for Sum-only pattern across all time periods. + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec}; + +use crate::internal::{ComputedVecValue, DerivedComputedBlockSum, LazyDate2Sum, LazyTransform2Sum, NumericValue}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlock2Sum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDate2Sum, + pub difficultyepoch: LazyTransform2Sum, +} + +impl LazyDerivedBlock2Sum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: NumericValue + JsonSchema, + S2T: NumericValue + JsonSchema, +{ + pub fn from_derived>( + name: &str, + version: Version, + source1: &DerivedComputedBlockSum, + source2: &DerivedComputedBlockSum, + ) -> Self { + let v = version + VERSION; + + Self { + dates: LazyDate2Sum::from_derived::(name, v, source1, source2), + difficultyepoch: LazyTransform2Sum::from_boxed::( + name, + v, + source1.difficultyepoch.boxed_clone(), + source2.difficultyepoch.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/binary_sum_cum.rs b/crates/brk_computer/src/internal/lazy/derived_block/binary_sum_cum.rs new file mode 100644 index 000000000..623d3b387 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/binary_sum_cum.rs @@ -0,0 +1,99 @@ +//! Lazy aggregated SumCum - binary transform version. + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec}; + +use crate::internal::{ + ComputedVecValue, DerivedDateFull, DerivedDateSumCum, LazyDate2SumCum, LazyFull, LazySumCum, + SumCum, +}; + +use super::super::transform::LazyTransform2SumCum; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlock2SumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDate2SumCum, + pub difficultyepoch: LazyTransform2SumCum, +} + +impl LazyDerivedBlock2SumCum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + #[allow(clippy::too_many_arguments)] + pub fn from_computed>( + name: &str, + version: Version, + dateindex1: &SumCum, + periods1: &DerivedDateSumCum, + difficultyepoch1: &LazySumCum, + dateindex2: &SumCum, + periods2: &DerivedDateSumCum, + difficultyepoch2: &LazySumCum, + ) -> Self { + let v = version + VERSION; + + Self { + dates: LazyDate2SumCum::from_computed::( + name, v, dateindex1, periods1, dateindex2, periods2, + ), + difficultyepoch: LazyTransform2SumCum::from_sources::( + name, + v, + difficultyepoch1.sum.boxed_clone(), + difficultyepoch2.sum.boxed_clone(), + difficultyepoch1.cumulative.boxed_clone(), + difficultyepoch2.cumulative.boxed_clone(), + ), + } + } + + #[allow(clippy::too_many_arguments)] + pub fn from_derived_full( + name: &str, + version: Version, + dateindex1: &SumCum, + dates1: &DerivedDateFull, + difficultyepoch1: &LazyFull, + dateindex2: &SumCum, + dates2: &DerivedDateFull, + difficultyepoch2: &LazyFull, + ) -> Self + where + F: BinaryTransform, + S1I: vecdb::VecIndex + 'static, + S1L: ComputedVecValue, + S2I: vecdb::VecIndex + 'static, + S2L: ComputedVecValue, + { + let v = version + VERSION; + + Self { + dates: LazyDate2SumCum::from_derived_full::( + name, v, dateindex1, dates1, dateindex2, dates2, + ), + difficultyepoch: LazyTransform2SumCum::from_lazy_stats_aggregate::( + name, + v, + difficultyepoch1, + difficultyepoch2, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/binary_sum_cum_last.rs b/crates/brk_computer/src/internal/lazy/derived_block/binary_sum_cum_last.rs new file mode 100644 index 000000000..d97687ef3 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/binary_sum_cum_last.rs @@ -0,0 +1,136 @@ +//! Lazy aggregated for SumCum + Last binary transform. + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec}; + +use crate::internal::{ + ComputedBlockLast, ComputedBlockSumCum, ComputedVecValue, DerivedComputedBlockLast, + DerivedComputedBlockSumCum, LazyDate2SumCumLast, NumericValue, +}; + +use super::super::transform::LazyTransform2SumCumLast; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlock2SumCumLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDate2SumCumLast, + pub difficultyepoch: LazyTransform2SumCumLast, +} + +impl LazyDerivedBlock2SumCumLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + source1: &ComputedBlockSumCum, + source2: &ComputedBlockLast, + ) -> Self + where + S1T: PartialOrd, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDate2SumCumLast::from_computed::(name, v, source1, source2), + difficultyepoch: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.difficultyepoch.sum.boxed_clone(), + source1.difficultyepoch.cumulative.boxed_clone(), + source2.difficultyepoch.boxed_clone(), + ), + } + } + + pub fn from_derived_computed_full>( + name: &str, + version: Version, + source1: &DerivedComputedBlockSumCum, + source2: &ComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDate2SumCumLast::from_derived_computed_full::(name, v, source1, source2), + difficultyepoch: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.difficultyepoch.sum.boxed_clone(), + source1.difficultyepoch.cumulative.boxed_clone(), + source2.difficultyepoch.boxed_clone(), + ), + } + } + + pub fn from_computed_derived_computed>( + name: &str, + version: Version, + source1: &ComputedBlockSumCum, + source2: &DerivedComputedBlockLast, + ) -> Self + where + S1T: PartialOrd, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDate2SumCumLast::from_computed_derived_computed::( + name, v, source1, source2, + ), + difficultyepoch: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.difficultyepoch.sum.boxed_clone(), + source1.difficultyepoch.cumulative.boxed_clone(), + source2.difficultyepoch.boxed_clone(), + ), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + source1: &DerivedComputedBlockSumCum, + source2: &DerivedComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + S2T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDate2SumCumLast::from_derived_computed::(name, v, source1, source2), + difficultyepoch: LazyTransform2SumCumLast::from_boxed::( + name, + v, + source1.difficultyepoch.sum.boxed_clone(), + source1.difficultyepoch.cumulative.boxed_clone(), + source2.difficultyepoch.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/full.rs b/crates/brk_computer/src/internal/lazy/derived_block/full.rs new file mode 100644 index 000000000..0d0f9ca3f --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/full.rs @@ -0,0 +1,87 @@ +//! Lazy aggregated Full for block-level sources. + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ + ComputedVecValue, DerivedComputedBlockFull, DerivedDateFull, Full, LazyDateFull, NumericValue, +}; + +use super::super::transform::LazyTransformFull; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlockFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDateFull, + pub difficultyepoch: LazyTransformFull, +} + +const VERSION: Version = Version::ZERO; + +impl LazyDerivedBlockFull +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + dateindex: &Full, + periods: &DerivedDateFull, + difficultyepoch: &crate::internal::LazyFull< + DifficultyEpoch, + S1T, + brk_types::Height, + DifficultyEpoch, + >, + ) -> Self { + let v = version + VERSION; + + Self { + dates: LazyDateFull::from_full::(name, v, dateindex, periods), + difficultyepoch: LazyTransformFull::from_boxed::( + name, + v, + difficultyepoch.average.boxed_clone(), + difficultyepoch.min.boxed_clone(), + difficultyepoch.max.boxed_clone(), + difficultyepoch.sum.boxed_clone(), + difficultyepoch.cumulative.boxed_clone(), + ), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + source: &DerivedComputedBlockFull, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDateFull::from_full::(name, v, &source.dateindex, &source.dates), + difficultyepoch: LazyTransformFull::from_boxed::( + name, + v, + source.difficultyepoch.average.boxed_clone(), + source.difficultyepoch.min.boxed_clone(), + source.difficultyepoch.max.boxed_clone(), + source.difficultyepoch.sum.boxed_clone(), + source.difficultyepoch.cumulative.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/last.rs b/crates/brk_computer/src/internal/lazy/derived_block/last.rs new file mode 100644 index 000000000..6433f637d --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/last.rs @@ -0,0 +1,85 @@ +//! Lazy aggregated Last for block-level sources. + +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ + ComputedBlockLast, ComputedVecValue, DerivedComputedBlockLast, LazyDateLast, NumericValue, +}; + +use super::super::transform::LazyTransformLast; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlockLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDateLast, + pub difficultyepoch: LazyTransformLast, +} + +const VERSION: Version = Version::ZERO; + +impl LazyDerivedBlockLast +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + source: &ComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDateLast::from_derived::( + name, + v, + source.dateindex.0.boxed_clone(), + &source.rest, + ), + difficultyepoch: LazyTransformLast::from_boxed::( + name, + v, + source.difficultyepoch.boxed_clone(), + ), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + source: &DerivedComputedBlockLast, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDateLast::from_derived::( + name, + v, + source.dateindex.0.boxed_clone(), + &source.dates, + ), + difficultyepoch: LazyTransformLast::from_boxed::( + name, + v, + source.difficultyepoch.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/mod.rs b/crates/brk_computer/src/internal/lazy/derived_block/mod.rs new file mode 100644 index 000000000..b5bc0d8cc --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/mod.rs @@ -0,0 +1,15 @@ +mod binary_sum; +mod binary_sum_cum; +mod binary_sum_cum_last; +mod full; +mod last; +mod sum; +mod sum_cum; + +pub use binary_sum::*; +pub use binary_sum_cum::*; +pub use binary_sum_cum_last::*; +pub use full::*; +pub use last::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/lazy/derived_block/sum.rs b/crates/brk_computer/src/internal/lazy/derived_block/sum.rs new file mode 100644 index 000000000..8d20fcead --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/sum.rs @@ -0,0 +1,79 @@ +//! Lazy aggregated Sum for block-level sources. + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ + ComputedVecValue, DerivedComputedBlockSum, DerivedDateSum, LazyDateSum, LazySum, NumericValue, SumVec, +}; + +use super::super::transform::LazyTransformSum; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlockSum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDateSum, + pub difficultyepoch: LazyTransformSum, +} + +const VERSION: Version = Version::ZERO; + +impl LazyDerivedBlockSum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + dateindex: &SumVec, + periods: &DerivedDateSum, + difficultyepoch: &LazySum, + ) -> Self { + let v = version + VERSION; + + Self { + dates: LazyDateSum::from_derived::(name, v, dateindex.0.boxed_clone(), periods), + difficultyepoch: LazyTransformSum::from_boxed::( + name, + v, + difficultyepoch.boxed_clone(), + ), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + source: &DerivedComputedBlockSum, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDateSum::from_derived::( + name, + v, + source.dateindex.0.boxed_clone(), + &source.dates, + ), + difficultyepoch: LazyTransformSum::from_boxed::( + name, + v, + source.difficultyepoch.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_block/sum_cum.rs b/crates/brk_computer/src/internal/lazy/derived_block/sum_cum.rs new file mode 100644 index 000000000..15ff9c0d3 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_block/sum_cum.rs @@ -0,0 +1,77 @@ +//! Lazy aggregated SumCum for block-level sources. + +use brk_traversable::Traversable; +use brk_types::{DateIndex, DifficultyEpoch, Height, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ + ComputedVecValue, DerivedComputedBlockSumCum, DerivedDateSumCum, LazyDateSumCum, LazySumCum, + NumericValue, SumCum, +}; + +use super::super::transform::LazyTransformSumCum; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedBlockSumCum +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: LazyDateSumCum, + pub difficultyepoch: LazyTransformSumCum, +} + +const VERSION: Version = Version::ZERO; + +impl LazyDerivedBlockSumCum +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + dateindex: &SumCum, + periods: &DerivedDateSumCum, + difficultyepoch: &LazySumCum, + ) -> Self { + let v = version + VERSION; + + Self { + dates: LazyDateSumCum::from_sum_cum::(name, v, dateindex, periods), + difficultyepoch: LazyTransformSumCum::from_boxed::( + name, + v, + difficultyepoch.sum.boxed_clone(), + difficultyepoch.cumulative.boxed_clone(), + ), + } + } + + pub fn from_derived_computed>( + name: &str, + version: Version, + source: &DerivedComputedBlockSumCum, + ) -> Self + where + S1T: NumericValue, + { + let v = version + VERSION; + + Self { + dates: LazyDateSumCum::from_sum_cum::(name, v, &source.dateindex, &source.dates), + difficultyepoch: LazyTransformSumCum::from_boxed::( + name, + v, + source.difficultyepoch.sum.boxed_clone(), + source.difficultyepoch.cumulative.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_tx/full.rs b/crates/brk_computer/src/internal/lazy/derived_tx/full.rs new file mode 100644 index 000000000..218ae81a5 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_tx/full.rs @@ -0,0 +1,123 @@ +//! Lazy transform of DerivedTxFull. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex, + Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{ComputedVecValue, DerivedTxFull}; + +use super::super::transform::LazyTransformFull; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyDerivedTxFull +where + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub height: LazyTransformFull, + pub difficultyepoch: LazyTransformFull, + pub dateindex: LazyTransformFull, + pub weekindex: LazyTransformFull, + pub monthindex: LazyTransformFull, + pub quarterindex: LazyTransformFull, + pub semesterindex: LazyTransformFull, + pub yearindex: LazyTransformFull, + pub decadeindex: LazyTransformFull, +} + +const VERSION: Version = Version::ZERO; + +impl LazyDerivedTxFull +where + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_computed>( + name: &str, + version: Version, + source: &DerivedTxFull, + ) -> Self { + let v = version + VERSION; + + Self { + height: LazyTransformFull::from_stats_aggregate::(name, v, &source.height), + difficultyepoch: LazyTransformFull::from_boxed::( + name, + v, + source.difficultyepoch.average.boxed_clone(), + source.difficultyepoch.min.boxed_clone(), + source.difficultyepoch.max.boxed_clone(), + source.difficultyepoch.sum.boxed_clone(), + source.difficultyepoch.cumulative.boxed_clone(), + ), + dateindex: LazyTransformFull::from_boxed::( + name, + v, + source.dateindex.average.0.boxed_clone(), + source.dateindex.minmax.min.0.boxed_clone(), + source.dateindex.minmax.max.0.boxed_clone(), + source.dateindex.sum_cum.sum.0.boxed_clone(), + source.dateindex.sum_cum.cumulative.0.boxed_clone(), + ), + weekindex: LazyTransformFull::from_boxed::( + name, + v, + source.weekindex.average.boxed_clone(), + source.weekindex.min.boxed_clone(), + source.weekindex.max.boxed_clone(), + source.weekindex.sum.boxed_clone(), + source.weekindex.cumulative.boxed_clone(), + ), + monthindex: LazyTransformFull::from_boxed::( + name, + v, + source.monthindex.average.boxed_clone(), + source.monthindex.min.boxed_clone(), + source.monthindex.max.boxed_clone(), + source.monthindex.sum.boxed_clone(), + source.monthindex.cumulative.boxed_clone(), + ), + quarterindex: LazyTransformFull::from_boxed::( + name, + v, + source.quarterindex.average.boxed_clone(), + source.quarterindex.min.boxed_clone(), + source.quarterindex.max.boxed_clone(), + source.quarterindex.sum.boxed_clone(), + source.quarterindex.cumulative.boxed_clone(), + ), + semesterindex: LazyTransformFull::from_boxed::( + name, + v, + source.semesterindex.average.boxed_clone(), + source.semesterindex.min.boxed_clone(), + source.semesterindex.max.boxed_clone(), + source.semesterindex.sum.boxed_clone(), + source.semesterindex.cumulative.boxed_clone(), + ), + yearindex: LazyTransformFull::from_boxed::( + name, + v, + source.yearindex.average.boxed_clone(), + source.yearindex.min.boxed_clone(), + source.yearindex.max.boxed_clone(), + source.yearindex.sum.boxed_clone(), + source.yearindex.cumulative.boxed_clone(), + ), + decadeindex: LazyTransformFull::from_boxed::( + name, + v, + source.decadeindex.average.boxed_clone(), + source.decadeindex.min.boxed_clone(), + source.decadeindex.max.boxed_clone(), + source.decadeindex.sum.boxed_clone(), + source.decadeindex.cumulative.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/derived_tx/mod.rs b/crates/brk_computer/src/internal/lazy/derived_tx/mod.rs new file mode 100644 index 000000000..bbd1bdfa9 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/derived_tx/mod.rs @@ -0,0 +1,3 @@ +mod full; + +pub use full::*; diff --git a/crates/brk_computer/src/internal/lazy/from_dateindex.rs b/crates/brk_computer/src/internal/lazy/from_dateindex.rs deleted file mode 100644 index e493095ce..000000000 --- a/crates/brk_computer/src/internal/lazy/from_dateindex.rs +++ /dev/null @@ -1,114 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::{ - DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, TreeNode, Version, WeekIndex, - YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{AnyExportableVec, IterableBoxedVec, LazyVecFrom1, UnaryTransform}; - -use crate::internal::{ComputedVecValue, ComputedVecsFromDateIndex, LazyTransformBuilder}; - -const VERSION: Version = Version::ZERO; - -#[derive(Clone)] -pub struct LazyVecsFromDateIndex -where - T: ComputedVecValue + PartialOrd + JsonSchema, - S1T: ComputedVecValue, -{ - pub dateindex: Option>, - pub dateindex_extra: LazyTransformBuilder, - pub weekindex: LazyTransformBuilder, - pub monthindex: LazyTransformBuilder, - pub quarterindex: LazyTransformBuilder, - pub semesterindex: LazyTransformBuilder, - pub yearindex: LazyTransformBuilder, - pub decadeindex: LazyTransformBuilder, -} - -impl LazyVecsFromDateIndex -where - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, -{ - /// Create a lazy transform from a stored `ComputedVecsFromDateIndex`. - /// F is the transform type (e.g., `Negate`, `Halve`). - pub fn from_computed>( - name: &str, - version: Version, - dateindex_source: Option>, - source: &ComputedVecsFromDateIndex, - ) -> Self { - let v = version + VERSION; - Self { - dateindex: dateindex_source.map(|s| LazyVecFrom1::transformed::(name, v, s)), - dateindex_extra: LazyTransformBuilder::from_eager::( - name, - v, - &source.dateindex_extra, - ), - weekindex: LazyTransformBuilder::from_lazy::(name, v, &source.weekindex), - monthindex: LazyTransformBuilder::from_lazy::(name, v, &source.monthindex), - quarterindex: LazyTransformBuilder::from_lazy::(name, v, &source.quarterindex), - semesterindex: LazyTransformBuilder::from_lazy::( - name, - v, - &source.semesterindex, - ), - yearindex: LazyTransformBuilder::from_lazy::(name, v, &source.yearindex), - decadeindex: LazyTransformBuilder::from_lazy::(name, v, &source.decadeindex), - } - } -} - -impl Traversable for LazyVecsFromDateIndex -where - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, -{ - fn to_tree_node(&self) -> TreeNode { - let dateindex_extra_node = self.dateindex_extra.to_tree_node(); - TreeNode::Branch( - [ - self.dateindex - .as_ref() - .map(|v| ("dateindex".to_string(), v.to_tree_node())), - if dateindex_extra_node.is_empty() { - None - } else { - Some(("dateindex_extra".to_string(), dateindex_extra_node)) - }, - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(std::iter::empty()); - if let Some(ref dateindex) = self.dateindex { - regular_iter = Box::new(regular_iter.chain(dateindex.iter_any_exportable())); - } - regular_iter = Box::new(regular_iter.chain(self.dateindex_extra.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.weekindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.monthindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.quarterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.semesterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.yearindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.decadeindex.iter_any_exportable())); - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/lazy/from_height.rs b/crates/brk_computer/src/internal/lazy/from_height.rs deleted file mode 100644 index 0414784bd..000000000 --- a/crates/brk_computer/src/internal/lazy/from_height.rs +++ /dev/null @@ -1,122 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::{ - DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex, - TreeNode, Version, WeekIndex, YearIndex, -}; -use schemars::JsonSchema; -use vecdb::{AnyExportableVec, IterableBoxedVec, LazyVecFrom1, UnaryTransform}; - -use crate::internal::{ComputedVecValue, ComputedVecsFromHeight, LazyTransformBuilder}; - -const VERSION: Version = Version::ZERO; - -/// Fully lazy version of `ComputedVecsFromHeight` where all vecs are lazy transforms. -/// Each index uses `LazyTransformBuilder` sourced from its corresponding stored groups. -#[derive(Clone)] -pub struct LazyVecsFromHeight -where - T: ComputedVecValue + PartialOrd + JsonSchema, - S1T: ComputedVecValue, -{ - pub height: LazyVecFrom1, - pub height_extra: LazyTransformBuilder, - pub dateindex: LazyTransformBuilder, - pub weekindex: LazyTransformBuilder, - pub difficultyepoch: LazyTransformBuilder, - pub monthindex: LazyTransformBuilder, - pub quarterindex: LazyTransformBuilder, - pub semesterindex: LazyTransformBuilder, - pub yearindex: LazyTransformBuilder, - pub decadeindex: LazyTransformBuilder, -} - -impl LazyVecsFromHeight -where - T: ComputedVecValue + JsonSchema + 'static, - S1T: ComputedVecValue + JsonSchema, -{ - /// Create a lazy transform from a stored `ComputedVecsFromHeight`. - /// F is the transform type (e.g., `Negate`, `Halve`). - pub fn from_computed>( - name: &str, - version: Version, - height_source: IterableBoxedVec, - source: &ComputedVecsFromHeight, - ) -> Self { - let v = version + VERSION; - Self { - height: LazyVecFrom1::transformed::(name, v, height_source), - height_extra: LazyTransformBuilder::from_eager::(name, v, &source.height_extra), - dateindex: LazyTransformBuilder::from_eager::(name, v, &source.dateindex), - weekindex: LazyTransformBuilder::from_lazy::(name, v, &source.weekindex), - difficultyepoch: LazyTransformBuilder::from_lazy::( - name, - v, - &source.difficultyepoch, - ), - monthindex: LazyTransformBuilder::from_lazy::(name, v, &source.monthindex), - quarterindex: LazyTransformBuilder::from_lazy::(name, v, &source.quarterindex), - semesterindex: LazyTransformBuilder::from_lazy::( - name, - v, - &source.semesterindex, - ), - yearindex: LazyTransformBuilder::from_lazy::(name, v, &source.yearindex), - decadeindex: LazyTransformBuilder::from_lazy::(name, v, &source.decadeindex), - } - } -} - -impl Traversable for LazyVecsFromHeight -where - T: ComputedVecValue + JsonSchema, - S1T: ComputedVecValue, -{ - fn to_tree_node(&self) -> TreeNode { - let height_extra_node = self.height_extra.to_tree_node(); - TreeNode::Branch( - [ - Some(("height".to_string(), self.height.to_tree_node())), - if height_extra_node.is_empty() { - None - } else { - Some(("height_extra".to_string(), height_extra_node)) - }, - Some(("dateindex".to_string(), self.dateindex.to_tree_node())), - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(( - "difficultyepoch".to_string(), - self.difficultyepoch.to_tree_node(), - )), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(self.height.iter_any_exportable()); - regular_iter = Box::new(regular_iter.chain(self.height_extra.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.dateindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.weekindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.difficultyepoch.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.monthindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.quarterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.semesterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.yearindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.decadeindex.iter_any_exportable())); - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/lazy/mod.rs b/crates/brk_computer/src/internal/lazy/mod.rs index 9fdf54931..6ec75b4a3 100644 --- a/crates/brk_computer/src/internal/lazy/mod.rs +++ b/crates/brk_computer/src/internal/lazy/mod.rs @@ -1,7 +1,10 @@ -mod binary; -mod from_dateindex; -mod from_height; +mod block; +mod date; +mod derived_block; +mod derived_tx; +mod transform; -pub use binary::*; -pub use from_dateindex::*; -pub use from_height::*; +pub use block::*; +pub use date::*; +pub use derived_tx::*; +pub use transform::*; diff --git a/crates/brk_computer/src/internal/lazy/transform/binary_last.rs b/crates/brk_computer/src/internal/lazy/transform/binary_last.rs new file mode 100644 index 000000000..dbe2592bf --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/binary_last.rs @@ -0,0 +1,61 @@ +//! Lazy binary transform for Last-only. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2, VecIndex}; + +use crate::internal::{ComputedVecValue, LazyLast}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "last")] +pub struct LazyTransform2Last(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue; + +impl LazyTransform2Last +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_lazy_last< + F: BinaryTransform, + S1I: VecIndex + 'static, + S2I: VecIndex + 'static, + S1S2T, + S2S2T, + >( + name: &str, + version: Version, + source1: &LazyLast, + source2: &LazyLast, + ) -> Self + where + S1S2T: vecdb::VecValue, + S2S2T: vecdb::VecValue, + { + Self(LazyVecFrom2::transformed::( + name, + version, + source1.boxed_clone(), + source2.boxed_clone(), + )) + } + + pub fn from_vecs>( + name: &str, + version: Version, + source1: IterableBoxedVec, + source2: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom2::transformed::( + name, version, source1, source2, + )) + } +} diff --git a/crates/brk_computer/src/internal/lazy/transform/binary_sum.rs b/crates/brk_computer/src/internal/lazy/transform/binary_sum.rs new file mode 100644 index 000000000..c32284e31 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/binary_sum.rs @@ -0,0 +1,56 @@ +//! Lazy binary transform for Sum-only aggregation at a single index level. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2, VecIndex}; + +use crate::internal::{ComputedVecValue, SumVec}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "sum")] +pub struct LazyTransform2Sum(pub LazyVecFrom2) +where + I: VecIndex, + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue; + +impl LazyTransform2Sum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_sum>( + name: &str, + version: Version, + source1: &SumVec, + source2: &SumVec, + ) -> Self { + let v = version + VERSION; + + Self(LazyVecFrom2::transformed::( + name, + v, + source1.0.boxed_clone(), + source2.0.boxed_clone(), + )) + } + + pub fn from_boxed>( + name: &str, + version: Version, + source1: IterableBoxedVec, + source2: IterableBoxedVec, + ) -> Self { + let v = version + VERSION; + + Self(LazyVecFrom2::transformed::(name, v, source1, source2)) + } +} + diff --git a/crates/brk_computer/src/internal/lazy/transform/binary_sum_cum.rs b/crates/brk_computer/src/internal/lazy/transform/binary_sum_cum.rs new file mode 100644 index 000000000..23d1e5849 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/binary_sum_cum.rs @@ -0,0 +1,105 @@ +//! Lazy binary transform for SumCum. + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{ + BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2, VecIndex, VecValue, +}; + +use crate::internal::{ComputedVecValue, LazyFull, SumCum}; + +#[derive(Clone, Traversable)] +pub struct LazyTransform2SumCum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub sum: LazyVecFrom2, + pub cumulative: LazyVecFrom2, +} + +impl LazyTransform2SumCum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_sum_cum>( + name: &str, + version: Version, + source1: &SumCum, + source2: &SumCum, + ) -> Self { + Self { + sum: LazyVecFrom2::transformed::( + &format!("{name}_sum"), + version, + source1.sum.0.boxed_clone(), + source2.sum.0.boxed_clone(), + ), + cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + version, + source1.cumulative.0.boxed_clone(), + source2.cumulative.0.boxed_clone(), + ), + } + } + + pub fn from_sources>( + name: &str, + version: Version, + sum_source1: IterableBoxedVec, + sum_source2: IterableBoxedVec, + cum_source1: IterableBoxedVec, + cum_source2: IterableBoxedVec, + ) -> Self { + Self { + sum: LazyVecFrom2::transformed::( + &format!("{name}_sum"), + version, + sum_source1, + sum_source2, + ), + cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + version, + cum_source1, + cum_source2, + ), + } + } + + pub fn from_lazy_stats_aggregate( + name: &str, + version: Version, + source1: &LazyFull, + source2: &LazyFull, + ) -> Self + where + F: BinaryTransform, + S1I: VecIndex + 'static, + S1L: VecValue, + S2I: VecIndex + 'static, + S2L: VecValue, + { + Self { + sum: LazyVecFrom2::transformed::( + &format!("{name}_sum"), + version, + source1.sum.boxed_clone(), + source2.sum.boxed_clone(), + ), + cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + version, + source1.cumulative.boxed_clone(), + source2.cumulative.boxed_clone(), + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/transform/binary_sum_cum_last.rs b/crates/brk_computer/src/internal/lazy/transform/binary_sum_cum_last.rs new file mode 100644 index 000000000..9a2447feb --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/binary_sum_cum_last.rs @@ -0,0 +1,68 @@ +//! Lazy binary transform for SumCum + Last → SumCum result. + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom2, VecIndex}; + +use crate::internal::{ComputedVecValue, LastVec, SumCum}; + +#[derive(Clone, Traversable)] +pub struct LazyTransform2SumCumLast +where + I: VecIndex, + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub sum: LazyVecFrom2, + pub cumulative: LazyVecFrom2, +} + +impl LazyTransform2SumCumLast +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, + S2T: ComputedVecValue + JsonSchema, +{ + pub fn from_sources>( + name: &str, + version: Version, + source1: &SumCum, + source2: &LastVec, + ) -> Self { + Self { + sum: LazyVecFrom2::transformed::( + name, + version, + source1.sum.0.boxed_clone(), + source2.0.boxed_clone(), + ), + cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + version, + source1.cumulative.0.boxed_clone(), + source2.0.boxed_clone(), + ), + } + } + + pub fn from_boxed>( + name: &str, + version: Version, + sum_source: IterableBoxedVec, + cum_source: IterableBoxedVec, + last_source: IterableBoxedVec, + ) -> Self { + Self { + sum: LazyVecFrom2::transformed::(name, version, sum_source, last_source.clone()), + cumulative: LazyVecFrom2::transformed::( + &format!("{name}_cumulative"), + version, + cum_source, + last_source, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/transform/full.rs b/crates/brk_computer/src/internal/lazy/transform/full.rs new file mode 100644 index 000000000..3a246e5cb --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/full.rs @@ -0,0 +1,89 @@ +//! Lazy unary transform for Full. + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex}; + +use crate::internal::{ComputedVecValue, Full}; + +#[derive(Clone, Traversable)] +pub struct LazyTransformFull +where + I: VecIndex, + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub average: LazyVecFrom1, + pub min: LazyVecFrom1, + pub max: LazyVecFrom1, + pub sum: LazyVecFrom1, + pub cumulative: LazyVecFrom1, +} + +impl LazyTransformFull +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_stats_aggregate>( + name: &str, + version: Version, + source: &Full, + ) -> Self { + Self { + average: LazyVecFrom1::transformed::( + &format!("{name}_average"), + version, + source.distribution.average.0.boxed_clone(), + ), + min: LazyVecFrom1::transformed::( + &format!("{name}_min"), + version, + source.distribution.minmax.min.0.boxed_clone(), + ), + max: LazyVecFrom1::transformed::( + &format!("{name}_max"), + version, + source.distribution.minmax.max.0.boxed_clone(), + ), + sum: LazyVecFrom1::transformed::( + &format!("{name}_sum"), + version, + source.sum_cum.sum.0.boxed_clone(), + ), + cumulative: LazyVecFrom1::transformed::( + &format!("{name}_cum"), + version, + source.sum_cum.cumulative.0.boxed_clone(), + ), + } + } + + pub fn from_boxed>( + name: &str, + version: Version, + average_source: IterableBoxedVec, + min_source: IterableBoxedVec, + max_source: IterableBoxedVec, + sum_source: IterableBoxedVec, + cumulative_source: IterableBoxedVec, + ) -> Self { + Self { + average: LazyVecFrom1::transformed::( + &format!("{name}_average"), + version, + average_source, + ), + min: LazyVecFrom1::transformed::(&format!("{name}_min"), version, min_source), + max: LazyVecFrom1::transformed::(&format!("{name}_max"), version, max_source), + sum: LazyVecFrom1::transformed::(&format!("{name}_sum"), version, sum_source), + cumulative: LazyVecFrom1::transformed::( + &format!("{name}_cum"), + version, + cumulative_source, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/lazy/transform/last.rs b/crates/brk_computer/src/internal/lazy/transform/last.rs new file mode 100644 index 000000000..ae408781a --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/last.rs @@ -0,0 +1,58 @@ +//! Lazy unary transform for Last-only - transforms last at one index level. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{ + IterableBoxedVec, IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex, VecValue, +}; + +use crate::internal::{ComputedVecValue, LastVec, LazyLast}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "last")] +pub struct LazyTransformLast(pub LazyVecFrom1) +where + I: VecIndex, + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue; + +impl LazyTransformLast +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_last_vec>( + name: &str, + version: Version, + source: &LastVec, + ) -> Self { + Self(LazyVecFrom1::transformed::( + name, + version, + source.0.boxed_clone(), + )) + } + + pub fn from_lazy_last, S1I: VecIndex + 'static, S1S2T: VecValue>( + name: &str, + version: Version, + source: &LazyLast, + ) -> Self { + Self(LazyVecFrom1::transformed::( + name, + version, + source.boxed_clone(), + )) + } + + pub fn from_boxed>( + name: &str, + version: Version, + last_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom1::transformed::(name, version, last_source)) + } +} diff --git a/crates/brk_computer/src/internal/lazy/transform/mod.rs b/crates/brk_computer/src/internal/lazy/transform/mod.rs new file mode 100644 index 000000000..2273f7385 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/mod.rs @@ -0,0 +1,17 @@ +mod binary_last; +mod binary_sum; +mod binary_sum_cum; +mod binary_sum_cum_last; +mod full; +mod last; +mod sum; +mod sum_cum; + +pub use binary_last::*; +pub use binary_sum::*; +pub use binary_sum_cum::*; +pub use binary_sum_cum_last::*; +pub use full::*; +pub use last::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/lazy/transform/sum.rs b/crates/brk_computer/src/internal/lazy/transform/sum.rs new file mode 100644 index 000000000..e5e961ee3 --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/sum.rs @@ -0,0 +1,44 @@ +//! Lazy unary transform for Sum-only. + +use brk_traversable::Traversable; +use brk_types::Version; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex}; + +use crate::internal::{ComputedVecValue, SumVec}; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "sum")] +pub struct LazyTransformSum(pub LazyVecFrom1) +where + I: VecIndex, + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue; + +impl LazyTransformSum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_sum_vec>( + name: &str, + version: Version, + source: &SumVec, + ) -> Self { + Self(LazyVecFrom1::transformed::( + name, + version, + source.0.boxed_clone(), + )) + } + + pub fn from_boxed>( + name: &str, + version: Version, + sum_source: IterableBoxedVec, + ) -> Self { + Self(LazyVecFrom1::transformed::(name, version, sum_source)) + } +} diff --git a/crates/brk_computer/src/internal/lazy/transform/sum_cum.rs b/crates/brk_computer/src/internal/lazy/transform/sum_cum.rs new file mode 100644 index 000000000..a3af204ee --- /dev/null +++ b/crates/brk_computer/src/internal/lazy/transform/sum_cum.rs @@ -0,0 +1,61 @@ +//! Lazy unary transform for SumCum. + +use brk_traversable::Traversable; +use brk_types::Version; +use schemars::JsonSchema; +use vecdb::{IterableBoxedVec, IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex}; + +use crate::internal::{ComputedVecValue, SumCum}; + +#[derive(Clone, Traversable)] +pub struct LazyTransformSumCum +where + I: VecIndex, + T: ComputedVecValue + PartialOrd + JsonSchema, + S1T: ComputedVecValue, +{ + pub sum: LazyVecFrom1, + pub cumulative: LazyVecFrom1, +} + +impl LazyTransformSumCum +where + I: VecIndex, + T: ComputedVecValue + JsonSchema + 'static, + S1T: ComputedVecValue + JsonSchema, +{ + pub fn from_sum_cum>( + name: &str, + version: Version, + source: &SumCum, + ) -> Self { + Self { + sum: LazyVecFrom1::transformed::( + &format!("{name}_sum"), + version, + source.sum.0.boxed_clone(), + ), + cumulative: LazyVecFrom1::transformed::( + &format!("{name}_cumulative"), + version, + source.cumulative.0.boxed_clone(), + ), + } + } + + pub fn from_boxed>( + name: &str, + version: Version, + sum_source: IterableBoxedVec, + cumulative_source: IterableBoxedVec, + ) -> Self { + Self { + sum: LazyVecFrom1::transformed::(&format!("{name}_sum"), version, sum_source), + cumulative: LazyVecFrom1::transformed::( + &format!("{name}_cumulative"), + version, + cumulative_source, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/mod.rs b/crates/brk_computer/src/internal/mod.rs index cb700e24d..6236074eb 100644 --- a/crates/brk_computer/src/internal/mod.rs +++ b/crates/brk_computer/src/internal/mod.rs @@ -1,15 +1,21 @@ -mod builder; +mod aggregation; +mod compute; mod computed; +mod derived; +mod group; mod lazy; -mod source; mod specialized; -mod transforms; -mod value; +mod traits; +mod transform; +mod vec; -pub use builder::*; -pub use computed::*; -pub use lazy::*; -pub use source::*; -pub use specialized::*; -pub use transforms::*; -pub use value::*; +pub(crate) use aggregation::*; +pub(crate) use compute::*; +pub(crate) use computed::*; +pub(crate) use derived::*; +pub(crate) use group::*; +pub(crate) use lazy::*; +pub(crate) use specialized::*; +pub(crate) use traits::*; +pub(crate) use transform::*; +pub(crate) use vec::*; diff --git a/crates/brk_computer/src/internal/source.rs b/crates/brk_computer/src/internal/source.rs deleted file mode 100644 index 095e5314d..000000000 --- a/crates/brk_computer/src/internal/source.rs +++ /dev/null @@ -1,31 +0,0 @@ -use vecdb::IterableBoxedVec; - -#[derive(Clone)] -pub enum Source { - Compute, - Vec(IterableBoxedVec), -} - -impl Source { - pub fn is_compute(&self) -> bool { - matches!(self, Self::Compute) - } - - pub fn is_vec(&self) -> bool { - matches!(self, Self::Vec(_)) - } - - pub fn vec(self) -> Option> { - match self { - Self::Vec(v) => Some(v), - _ => None, - } - } -} - -impl From> for Source { - #[inline] - fn from(value: IterableBoxedVec) -> Self { - Self::Vec(value) - } -} diff --git a/crates/brk_computer/src/internal/specialized/constant.rs b/crates/brk_computer/src/internal/specialized/constant.rs index 27e45d8ef..240c4faa1 100644 --- a/crates/brk_computer/src/internal/specialized/constant.rs +++ b/crates/brk_computer/src/internal/specialized/constant.rs @@ -1,19 +1,18 @@ use brk_traversable::Traversable; use brk_types::{ - DateIndex, DecadeIndex, Height, MonthIndex, QuarterIndex, SemesterIndex, TreeNode, Version, - WeekIndex, YearIndex, + DateIndex, DecadeIndex, Height, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, + YearIndex, }; use schemars::JsonSchema; use serde::Serialize; -use vecdb::{ - AnyExportableVec, Formattable, IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecValue, -}; +use vecdb::{Formattable, IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecValue}; -use crate::{indexes, internal::ComputedVecValue}; +use crate::indexes; /// Lazy constant vecs for all index levels. /// Uses const generic transforms to return the same value for every index. -#[derive(Clone)] +#[derive(Clone, Traversable)] +#[traversable(merge)] pub struct ConstantVecs where T: VecValue + Formattable + Serialize + JsonSchema, @@ -86,43 +85,3 @@ impl ConstantVecs { } } -impl Traversable for ConstantVecs -where - T: ComputedVecValue + JsonSchema, -{ - fn to_tree_node(&self) -> TreeNode { - TreeNode::Branch( - [ - Some(("height".to_string(), self.height.to_tree_node())), - Some(("dateindex".to_string(), self.dateindex.to_tree_node())), - Some(("weekindex".to_string(), self.weekindex.to_tree_node())), - Some(("monthindex".to_string(), self.monthindex.to_tree_node())), - Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())), - Some(( - "semesterindex".to_string(), - self.semesterindex.to_tree_node(), - )), - Some(("yearindex".to_string(), self.yearindex.to_tree_node())), - Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())), - ] - .into_iter() - .flatten() - .collect(), - ) - .merge_branches() - .unwrap() - } - - fn iter_any_exportable(&self) -> impl Iterator { - let mut regular_iter: Box> = - Box::new(self.height.iter_any_exportable()); - regular_iter = Box::new(regular_iter.chain(self.dateindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.weekindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.monthindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.quarterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.semesterindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.yearindex.iter_any_exportable())); - regular_iter = Box::new(regular_iter.chain(self.decadeindex.iter_any_exportable())); - regular_iter - } -} diff --git a/crates/brk_computer/src/internal/specialized/mod.rs b/crates/brk_computer/src/internal/specialized/mod.rs index 1ac1eaf2a..f544732a5 100644 --- a/crates/brk_computer/src/internal/specialized/mod.rs +++ b/crates/brk_computer/src/internal/specialized/mod.rs @@ -2,8 +2,10 @@ mod constant; mod percentiles; mod ratio; mod stddev; +mod value; pub use constant::*; pub use percentiles::*; pub use ratio::*; pub use stddev::*; +pub use value::*; diff --git a/crates/brk_computer/src/internal/specialized/percentiles.rs b/crates/brk_computer/src/internal/specialized/percentiles.rs index 3df78163e..90a2b15d3 100644 --- a/crates/brk_computer/src/internal/specialized/percentiles.rs +++ b/crates/brk_computer/src/internal/specialized/percentiles.rs @@ -8,7 +8,7 @@ use vecdb::{ use crate::{ComputeIndexes, indexes}; -use super::super::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}; +use super::super::ComputedDateLast; pub const PERCENTILES: [u8; 19] = [ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, @@ -17,7 +17,7 @@ pub const PERCENTILES_LEN: usize = PERCENTILES.len(); #[derive(Clone)] pub struct CostBasisPercentiles { - pub vecs: [Option>; PERCENTILES_LEN], + pub vecs: [Option>; PERCENTILES_LEN], } const VERSION: Version = Version::ZERO; @@ -32,13 +32,11 @@ impl CostBasisPercentiles { ) -> Result { let vecs = PERCENTILES.map(|p| { compute.then(|| { - ComputedVecsFromDateIndex::forced_import( + ComputedDateLast::forced_import( db, &format!("{name}_cost_basis_pct{p:02}"), - Source::Compute, version + VERSION, indexes, - VecBuilderOptions::default().add_last(), ) .unwrap() }) @@ -52,8 +50,7 @@ impl CostBasisPercentiles { self.vecs .iter() .filter_map(|v| v.as_ref()) - .filter_map(|v| v.dateindex.as_ref()) - .map(|v| v.len()) + .map(|v| v.dateindex.len()) .min() .unwrap_or(usize::MAX) } @@ -67,10 +64,7 @@ impl CostBasisPercentiles { ) -> Result<()> { for (i, vec) in self.vecs.iter_mut().enumerate() { if let Some(v) = vec { - v.dateindex - .as_mut() - .unwrap() - .truncate_push(dateindex, percentile_prices[i])?; + v.dateindex.truncate_push(dateindex, percentile_prices[i])?; } } Ok(()) @@ -87,7 +81,7 @@ impl CostBasisPercentiles { Ok(()) } - pub fn get(&self, percentile: u8) -> Option<&ComputedVecsFromDateIndex> { + pub fn get(&self, percentile: u8) -> Option<&ComputedDateLast> { PERCENTILES .iter() .position(|&p| p == percentile) @@ -98,9 +92,7 @@ impl CostBasisPercentiles { impl CostBasisPercentiles { pub fn write(&mut self) -> Result<()> { for vec in self.vecs.iter_mut().flatten() { - if let Some(dateindex_vec) = vec.dateindex.as_mut() { - dateindex_vec.write()?; - } + vec.dateindex.write()?; } Ok(()) } @@ -110,8 +102,7 @@ impl CostBasisPercentiles { self.vecs .iter_mut() .flatten() - .filter_map(|v| v.dateindex.as_mut()) - .map(|v| v as &mut dyn AnyStoredVec) + .map(|v| &mut v.dateindex as &mut dyn AnyStoredVec) .collect::>() .into_par_iter() } @@ -119,9 +110,7 @@ impl CostBasisPercentiles { /// Validate computed versions or reset if mismatched. pub fn validate_computed_version_or_reset(&mut self, version: Version) -> Result<()> { for vec in self.vecs.iter_mut().flatten() { - if let Some(dateindex_vec) = vec.dateindex.as_mut() { - dateindex_vec.validate_computed_version_or_reset(version)?; - } + vec.dateindex.validate_computed_version_or_reset(version)?; } Ok(()) } diff --git a/crates/brk_computer/src/internal/specialized/ratio.rs b/crates/brk_computer/src/internal/specialized/ratio.rs index 479869ea9..1290e58ce 100644 --- a/crates/brk_computer/src/internal/specialized/ratio.rs +++ b/crates/brk_computer/src/internal/specialized/ratio.rs @@ -7,86 +7,76 @@ use vecdb::{ }; use crate::{ - ComputeIndexes, + ComputeIndexes, indexes, internal::{ - ComputedStandardDeviationVecsFromDateIndex, LazyVecsFrom2FromDateIndex, PriceTimesRatio, - StandardDeviationVecsOptions, source::Source, + BinaryDateLast, ComputedStandardDeviationVecsDate, PriceTimesRatio, + StandardDeviationVecsOptions, }, - indexes, price, - utils::{OptionExt, get_percentile}, + price, + utils::get_percentile, }; -use super::super::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions}; +use super::super::{ComputedBlockLast, ComputedDateLast}; #[derive(Clone, Traversable)] -pub struct ComputedRatioVecsFromDateIndex { - pub price: Option>, +pub struct ComputedRatioVecsDate { + pub price: Option>, - pub ratio: ComputedVecsFromDateIndex, - pub ratio_1w_sma: Option>, - pub ratio_1m_sma: Option>, - pub ratio_pct99: Option>, - pub ratio_pct98: Option>, - pub ratio_pct95: Option>, - pub ratio_pct5: Option>, - pub ratio_pct2: Option>, - pub ratio_pct1: Option>, - pub ratio_pct99_usd: Option>, - pub ratio_pct98_usd: Option>, - pub ratio_pct95_usd: Option>, - pub ratio_pct5_usd: Option>, - pub ratio_pct2_usd: Option>, - pub ratio_pct1_usd: Option>, + pub ratio: ComputedDateLast, + pub ratio_1w_sma: Option>, + pub ratio_1m_sma: Option>, + pub ratio_pct99: Option>, + pub ratio_pct98: Option>, + pub ratio_pct95: Option>, + pub ratio_pct5: Option>, + pub ratio_pct2: Option>, + pub ratio_pct1: Option>, + pub ratio_pct99_usd: Option>, + pub ratio_pct98_usd: Option>, + pub ratio_pct95_usd: Option>, + pub ratio_pct5_usd: Option>, + pub ratio_pct2_usd: Option>, + pub ratio_pct1_usd: Option>, - pub ratio_sd: Option, - pub ratio_4y_sd: Option, - pub ratio_2y_sd: Option, - pub ratio_1y_sd: Option, + pub ratio_sd: Option, + pub ratio_4y_sd: Option, + pub ratio_2y_sd: Option, + pub ratio_1y_sd: Option, } const VERSION: Version = Version::TWO; -impl ComputedRatioVecsFromDateIndex { +impl ComputedRatioVecsDate { #[allow(clippy::too_many_arguments)] pub fn forced_import( db: &Database, name: &str, - metric_price: Option<&ComputedVecsFromHeight>, + metric_price: Option<&ComputedBlockLast>, version: Version, indexes: &indexes::Vecs, extended: bool, price_vecs: Option<&price::Vecs>, ) -> Result { - let opts = VecBuilderOptions::default().add_last(); let v = version + VERSION; macro_rules! import { ($suffix:expr) => { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("{name}_{}", $suffix), - Source::Compute, - v, - indexes, - opts, - ) - .unwrap() + ComputedDateLast::forced_import(db, &format!("{name}_{}", $suffix), v, indexes) + .unwrap() }; } // Create price sources first so lazy vecs can reference them // Only compute internally when metric_price is None - let price = metric_price.is_none().then(|| { - ComputedVecsFromDateIndex::forced_import(db, name, Source::Compute, v, indexes, opts) - .unwrap() - }); + let price = metric_price + .is_none() + .then(|| ComputedDateLast::forced_import(db, name, v, indexes).unwrap()); macro_rules! import_sd { ($suffix:expr, $days:expr) => { - ComputedStandardDeviationVecsFromDateIndex::forced_import( + ComputedStandardDeviationVecsDate::forced_import( db, &format!("{name}_{}", $suffix), $days, - Source::Compute, v, indexes, StandardDeviationVecsOptions::default().add_all(), @@ -103,14 +93,11 @@ impl ComputedRatioVecsFromDateIndex { let ratio_pct2 = extended.then(|| import!("ratio_pct2")); let ratio_pct1 = extended.then(|| import!("ratio_pct1")); - // Create lazy usd vecs from price and ratio sources - // Use from_height_and_dateindex when metric_price is provided (external price source) - // Use from_computed when price is computed internally macro_rules! lazy_usd { ($ratio:expr, $suffix:expr) => { if let Some(mp) = metric_price { $ratio.as_ref().map(|r| { - LazyVecsFrom2FromDateIndex::from_height_and_dateindex::( + BinaryDateLast::from_height_and_dateindex_last::( &format!("{name}_{}", $suffix), v, mp, @@ -119,7 +106,7 @@ impl ComputedRatioVecsFromDateIndex { }) } else { price.as_ref().zip($ratio.as_ref()).map(|(p, r)| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &format!("{name}_{}", $suffix), v, p, @@ -180,10 +167,11 @@ impl ComputedRatioVecsFromDateIndex { exit: &Exit, price_opt: Option<&impl IterableVec>, ) -> Result<()> { - let closes = price.usd.timeindexes_to_price_close.dateindex.u(); + let closes = &price.usd.timeindexes_to_price_close.dateindex; - let price = - price_opt.unwrap_or_else(|| unsafe { std::mem::transmute(&self.price.u().dateindex) }); + let price = price_opt.unwrap_or_else(|| unsafe { + std::mem::transmute(&self.price.as_ref().unwrap().dateindex) + }); self.ratio.compute_all(starting_indexes, exit, |v| { v.compute_transform2( @@ -214,7 +202,7 @@ impl ComputedRatioVecsFromDateIndex { .compute_all(starting_indexes, exit, |v| { v.compute_sma_( starting_indexes.dateindex, - self.ratio.dateindex.u(), + &self.ratio.dateindex, 7, exit, Some(min_ratio_date), @@ -228,7 +216,7 @@ impl ComputedRatioVecsFromDateIndex { .compute_all(starting_indexes, exit, |v| { v.compute_sma_( starting_indexes.dateindex, - self.ratio.dateindex.u(), + &self.ratio.dateindex, 30, exit, Some(min_ratio_date), @@ -236,7 +224,7 @@ impl ComputedRatioVecsFromDateIndex { Ok(()) })?; - let ratio_version = self.ratio.dateindex.u().version(); + let ratio_version = self.ratio.dateindex.version(); self.mut_ratio_vecs() .iter_mut() .try_for_each(|v| -> Result<()> { @@ -254,7 +242,7 @@ impl ComputedRatioVecsFromDateIndex { let min_ratio_date_usize = min_ratio_date.to_usize(); - let mut sorted = self.ratio.dateindex.u().collect_range( + let mut sorted = self.ratio.dateindex.collect_range( Some(min_ratio_date_usize), Some(starting_dateindex.to_usize()), ); @@ -262,17 +250,15 @@ impl ComputedRatioVecsFromDateIndex { sorted.sort_unstable(); // Cache mutable refs before the loop to avoid repeated unwrap chains - let pct1_vec = self.ratio_pct1.um().dateindex.um(); - let pct2_vec = self.ratio_pct2.um().dateindex.um(); - let pct5_vec = self.ratio_pct5.um().dateindex.um(); - let pct95_vec = self.ratio_pct95.um().dateindex.um(); - let pct98_vec = self.ratio_pct98.um().dateindex.um(); - let pct99_vec = self.ratio_pct99.um().dateindex.um(); + let pct1_vec = &mut self.ratio_pct1.as_mut().unwrap().dateindex; + let pct2_vec = &mut self.ratio_pct2.as_mut().unwrap().dateindex; + let pct5_vec = &mut self.ratio_pct5.as_mut().unwrap().dateindex; + let pct95_vec = &mut self.ratio_pct95.as_mut().unwrap().dateindex; + let pct98_vec = &mut self.ratio_pct98.as_mut().unwrap().dateindex; + let pct99_vec = &mut self.ratio_pct99.as_mut().unwrap().dateindex; self.ratio .dateindex - .as_ref() - .unwrap() .iter() .enumerate() .skip(starting_dateindex.to_usize()) @@ -301,52 +287,62 @@ impl ComputedRatioVecsFromDateIndex { { let _lock = exit.lock(); - self.mut_ratio_vecs().into_iter().try_for_each(|v| v.flush())?; + self.mut_ratio_vecs() + .into_iter() + .try_for_each(|v| v.flush())?; } - self.ratio_pct1.um().compute_rest( + self.ratio_pct1.as_mut().unwrap().compute_rest( starting_indexes, exit, None as Option<&EagerVec>>, )?; - self.ratio_pct2.um().compute_rest( + self.ratio_pct2.as_mut().unwrap().compute_rest( starting_indexes, exit, None as Option<&EagerVec>>, )?; - self.ratio_pct5.um().compute_rest( + self.ratio_pct5.as_mut().unwrap().compute_rest( starting_indexes, exit, None as Option<&EagerVec>>, )?; - self.ratio_pct95.um().compute_rest( + self.ratio_pct95.as_mut().unwrap().compute_rest( starting_indexes, exit, None as Option<&EagerVec>>, )?; - self.ratio_pct98.um().compute_rest( + self.ratio_pct98.as_mut().unwrap().compute_rest( starting_indexes, exit, None as Option<&EagerVec>>, )?; - self.ratio_pct99.um().compute_rest( + self.ratio_pct99.as_mut().unwrap().compute_rest( starting_indexes, exit, None as Option<&EagerVec>>, )?; - self.ratio_sd - .um() - .compute_all(starting_indexes, exit, self.ratio.dateindex.u())?; - self.ratio_4y_sd - .um() - .compute_all(starting_indexes, exit, self.ratio.dateindex.u())?; - self.ratio_2y_sd - .um() - .compute_all(starting_indexes, exit, self.ratio.dateindex.u())?; - self.ratio_1y_sd - .um() - .compute_all(starting_indexes, exit, self.ratio.dateindex.u())?; + self.ratio_sd.as_mut().unwrap().compute_all( + starting_indexes, + exit, + &self.ratio.dateindex, + )?; + self.ratio_4y_sd.as_mut().unwrap().compute_all( + starting_indexes, + exit, + &self.ratio.dateindex, + )?; + self.ratio_2y_sd.as_mut().unwrap().compute_all( + starting_indexes, + exit, + &self.ratio.dateindex, + )?; + self.ratio_1y_sd.as_mut().unwrap().compute_all( + starting_indexes, + exit, + &self.ratio.dateindex, + )?; Ok(()) } @@ -354,22 +350,22 @@ impl ComputedRatioVecsFromDateIndex { fn mut_ratio_vecs(&mut self) -> Vec<&mut EagerVec>> { let mut vecs = Vec::with_capacity(6); if let Some(v) = self.ratio_pct1.as_mut() { - vecs.push(v.dateindex.um()); + vecs.push(&mut v.dateindex); } if let Some(v) = self.ratio_pct2.as_mut() { - vecs.push(v.dateindex.um()); + vecs.push(&mut v.dateindex); } if let Some(v) = self.ratio_pct5.as_mut() { - vecs.push(v.dateindex.um()); + vecs.push(&mut v.dateindex); } if let Some(v) = self.ratio_pct95.as_mut() { - vecs.push(v.dateindex.um()); + vecs.push(&mut v.dateindex); } if let Some(v) = self.ratio_pct98.as_mut() { - vecs.push(v.dateindex.um()); + vecs.push(&mut v.dateindex); } if let Some(v) = self.ratio_pct99.as_mut() { - vecs.push(v.dateindex.um()); + vecs.push(&mut v.dateindex); } vecs } diff --git a/crates/brk_computer/src/internal/specialized/stddev.rs b/crates/brk_computer/src/internal/specialized/stddev.rs index fe86f8ca3..11c883603 100644 --- a/crates/brk_computer/src/internal/specialized/stddev.rs +++ b/crates/brk_computer/src/internal/specialized/stddev.rs @@ -8,48 +8,46 @@ use vecdb::{ PcoVec, VecIndex, }; -use crate::{ComputeIndexes, internal::source::Source, indexes, price, utils::OptionExt}; +use crate::{ComputeIndexes, indexes, price}; -use super::super::{ - ClosePriceTimesRatio, ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, VecBuilderOptions, -}; +use super::super::{BinaryDateLast, ClosePriceTimesRatio, ComputedDateLast}; #[derive(Clone, Traversable)] -pub struct ComputedStandardDeviationVecsFromDateIndex { +pub struct ComputedStandardDeviationVecsDate { days: usize, - pub sma: Option>, + pub sma: Option>, - pub sd: ComputedVecsFromDateIndex, + pub sd: ComputedDateLast, - pub zscore: Option>, + pub zscore: Option>, - pub p0_5sd: Option>, - pub p1sd: Option>, - pub p1_5sd: Option>, - pub p2sd: Option>, - pub p2_5sd: Option>, - pub p3sd: Option>, - pub m0_5sd: Option>, - pub m1sd: Option>, - pub m1_5sd: Option>, - pub m2sd: Option>, - pub m2_5sd: Option>, - pub m3sd: Option>, + pub p0_5sd: Option>, + pub p1sd: Option>, + pub p1_5sd: Option>, + pub p2sd: Option>, + pub p2_5sd: Option>, + pub p3sd: Option>, + pub m0_5sd: Option>, + pub m1sd: Option>, + pub m1_5sd: Option>, + pub m2sd: Option>, + pub m2_5sd: Option>, + pub m3sd: Option>, - pub _0sd_usd: Option, StoredF32>>, - pub p0_5sd_usd: Option, StoredF32>>, - pub p1sd_usd: Option, StoredF32>>, - pub p1_5sd_usd: Option, StoredF32>>, - pub p2sd_usd: Option, StoredF32>>, - pub p2_5sd_usd: Option, StoredF32>>, - pub p3sd_usd: Option, StoredF32>>, - pub m0_5sd_usd: Option, StoredF32>>, - pub m1sd_usd: Option, StoredF32>>, - pub m1_5sd_usd: Option, StoredF32>>, - pub m2sd_usd: Option, StoredF32>>, - pub m2_5sd_usd: Option, StoredF32>>, - pub m3sd_usd: Option, StoredF32>>, + pub _0sd_usd: Option, StoredF32>>, + pub p0_5sd_usd: Option, StoredF32>>, + pub p1sd_usd: Option, StoredF32>>, + pub p1_5sd_usd: Option, StoredF32>>, + pub p2sd_usd: Option, StoredF32>>, + pub p2_5sd_usd: Option, StoredF32>>, + pub p3sd_usd: Option, StoredF32>>, + pub m0_5sd_usd: Option, StoredF32>>, + pub m1sd_usd: Option, StoredF32>>, + pub m1_5sd_usd: Option, StoredF32>>, + pub m2sd_usd: Option, StoredF32>>, + pub m2_5sd_usd: Option, StoredF32>>, + pub m3sd_usd: Option, StoredF32>>, } #[derive(Debug, Default)] @@ -96,37 +94,32 @@ impl StandardDeviationVecsOptions { } } -impl ComputedStandardDeviationVecsFromDateIndex { +impl ComputedStandardDeviationVecsDate { #[allow(clippy::too_many_arguments)] pub fn forced_import( db: &Database, name: &str, days: usize, - sma: Source, parent_version: Version, indexes: &indexes::Vecs, options: StandardDeviationVecsOptions, price_vecs: Option<&price::Vecs>, ) -> Result { - let opts = VecBuilderOptions::default().add_last(); let version = parent_version + Version::ONE; macro_rules! import { ($suffix:expr) => { - ComputedVecsFromDateIndex::forced_import( + ComputedDateLast::forced_import( db, &format!("{name}_{}", $suffix), - Source::Compute, version, indexes, - opts, ) .unwrap() }; } - // Create sources first so lazy vecs can reference them - let sma_vec = sma.is_compute().then(|| import!("sma")); + let sma_vec = Some(import!("sma")); let p0_5sd = options.bands().then(|| import!("p0_5sd")); let p1sd = options.bands().then(|| import!("p1sd")); let p1_5sd = options.bands().then(|| import!("p1_5sd")); @@ -140,7 +133,6 @@ impl ComputedStandardDeviationVecsFromDateIndex { let m2_5sd = options.bands().then(|| import!("m2_5sd")); let m3sd = options.bands().then(|| import!("m3sd")); - // Create lazy USD vecs from price and band sources macro_rules! lazy_usd { ($band:expr, $suffix:expr) => { price_vecs @@ -148,7 +140,7 @@ impl ComputedStandardDeviationVecsFromDateIndex { .zip($band.as_ref()) .filter(|_| options.price_bands()) .map(|(p, b)| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &format!("{name}_{}", $suffix), version, p, @@ -226,7 +218,8 @@ impl ComputedStandardDeviationVecsFromDateIndex { sma_opt: Option<&impl IterableVec>, source: &impl CollectableVec, ) -> Result<()> { - let sma = sma_opt.unwrap_or_else(|| unsafe { mem::transmute(&self.sma.u().dateindex) }); + let sma = sma_opt + .unwrap_or_else(|| unsafe { mem::transmute(&self.sma.as_ref().unwrap().dateindex) }); let min_date = DateIndex::try_from(Date::MIN_RATIO).unwrap(); @@ -252,18 +245,18 @@ impl ComputedStandardDeviationVecsFromDateIndex { sorted.sort_unstable(); - let mut p0_5sd = self.p0_5sd.as_mut().map(|c| c.dateindex.um()); - let mut p1sd = self.p1sd.as_mut().map(|c| c.dateindex.um()); - let mut p1_5sd = self.p1_5sd.as_mut().map(|c| c.dateindex.um()); - let mut p2sd = self.p2sd.as_mut().map(|c| c.dateindex.um()); - let mut p2_5sd = self.p2_5sd.as_mut().map(|c| c.dateindex.um()); - let mut p3sd = self.p3sd.as_mut().map(|c| c.dateindex.um()); - let mut m0_5sd = self.m0_5sd.as_mut().map(|c| c.dateindex.um()); - let mut m1sd = self.m1sd.as_mut().map(|c| c.dateindex.um()); - let mut m1_5sd = self.m1_5sd.as_mut().map(|c| c.dateindex.um()); - let mut m2sd = self.m2sd.as_mut().map(|c| c.dateindex.um()); - let mut m2_5sd = self.m2_5sd.as_mut().map(|c| c.dateindex.um()); - let mut m3sd = self.m3sd.as_mut().map(|c| c.dateindex.um()); + let mut p0_5sd = self.p0_5sd.as_mut().map(|c| &mut c.dateindex); + let mut p1sd = self.p1sd.as_mut().map(|c| &mut c.dateindex); + let mut p1_5sd = self.p1_5sd.as_mut().map(|c| &mut c.dateindex); + let mut p2sd = self.p2sd.as_mut().map(|c| &mut c.dateindex); + let mut p2_5sd = self.p2_5sd.as_mut().map(|c| &mut c.dateindex); + let mut p3sd = self.p3sd.as_mut().map(|c| &mut c.dateindex); + let mut m0_5sd = self.m0_5sd.as_mut().map(|c| &mut c.dateindex); + let mut m1sd = self.m1sd.as_mut().map(|c| &mut c.dateindex); + let mut m1_5sd = self.m1_5sd.as_mut().map(|c| &mut c.dateindex); + let mut m2sd = self.m2sd.as_mut().map(|c| &mut c.dateindex); + let mut m2_5sd = self.m2_5sd.as_mut().map(|c| &mut c.dateindex); + let mut m3sd = self.m3sd.as_mut().map(|c| &mut c.dateindex); let min_date_usize = min_date.to_usize(); let mut sma_iter = sma.iter().skip(starting_dateindex.to_usize()); @@ -274,11 +267,7 @@ impl ComputedStandardDeviationVecsFromDateIndex { .skip(starting_dateindex.to_usize()) .try_for_each(|(index, ratio)| -> Result<()> { if index < min_date_usize { - self.sd - .dateindex - .as_mut() - .unwrap() - .truncate_push_at(index, StoredF32::NAN)?; + self.sd.dateindex.truncate_push_at(index, StoredF32::NAN)?; if let Some(v) = p0_5sd.as_mut() { v.truncate_push_at(index, StoredF32::NAN)? @@ -322,56 +311,52 @@ impl ComputedStandardDeviationVecsFromDateIndex { let pos = sorted.binary_search(&ratio).unwrap_or_else(|pos| pos); sorted.insert(pos, ratio); - let avg = sma_iter.next().unwrap(); + let average = sma_iter.next().unwrap(); let population = index.checked_sub(min_date_usize).unwrap().to_usize() as f32 + 1.0; let sd = StoredF32::from( - (sorted.iter().map(|v| (**v - *avg).powi(2)).sum::() / population) + (sorted.iter().map(|v| (**v - *average).powi(2)).sum::() / population) .sqrt(), ); - self.sd - .dateindex - .as_mut() - .unwrap() - .truncate_push_at(index, sd)?; + self.sd.dateindex.truncate_push_at(index, sd)?; if let Some(v) = p0_5sd.as_mut() { - v.truncate_push_at(index, avg + StoredF32::from(0.5 * *sd))? + v.truncate_push_at(index, average + StoredF32::from(0.5 * *sd))? } if let Some(v) = p1sd.as_mut() { - v.truncate_push_at(index, avg + sd)? + v.truncate_push_at(index, average + sd)? } if let Some(v) = p1_5sd.as_mut() { - v.truncate_push_at(index, avg + StoredF32::from(1.5 * *sd))? + v.truncate_push_at(index, average + StoredF32::from(1.5 * *sd))? } if let Some(v) = p2sd.as_mut() { - v.truncate_push_at(index, avg + 2 * sd)? + v.truncate_push_at(index, average + 2 * sd)? } if let Some(v) = p2_5sd.as_mut() { - v.truncate_push_at(index, avg + StoredF32::from(2.5 * *sd))? + v.truncate_push_at(index, average + StoredF32::from(2.5 * *sd))? } if let Some(v) = p3sd.as_mut() { - v.truncate_push_at(index, avg + 3 * sd)? + v.truncate_push_at(index, average + 3 * sd)? } if let Some(v) = m0_5sd.as_mut() { - v.truncate_push_at(index, avg - StoredF32::from(0.5 * *sd))? + v.truncate_push_at(index, average - StoredF32::from(0.5 * *sd))? } if let Some(v) = m1sd.as_mut() { - v.truncate_push_at(index, avg - sd)? + v.truncate_push_at(index, average - sd)? } if let Some(v) = m1_5sd.as_mut() { - v.truncate_push_at(index, avg - StoredF32::from(1.5 * *sd))? + v.truncate_push_at(index, average - StoredF32::from(1.5 * *sd))? } if let Some(v) = m2sd.as_mut() { - v.truncate_push_at(index, avg - 2 * sd)? + v.truncate_push_at(index, average - 2 * sd)? } if let Some(v) = m2_5sd.as_mut() { - v.truncate_push_at(index, avg - StoredF32::from(2.5 * *sd))? + v.truncate_push_at(index, average - StoredF32::from(2.5 * *sd))? } if let Some(v) = m3sd.as_mut() { - v.truncate_push_at(index, avg - 3 * sd)? + v.truncate_push_at(index, average - 3 * sd)? } } @@ -399,7 +384,7 @@ impl ComputedStandardDeviationVecsFromDateIndex { starting_indexes.dateindex, source, sma, - self.sd.dateindex.u(), + &self.sd.dateindex, exit, )?; Ok(()) @@ -409,9 +394,7 @@ impl ComputedStandardDeviationVecsFromDateIndex { Ok(()) } - fn mut_stateful_computed( - &mut self, - ) -> impl Iterator> { + fn mut_stateful_computed(&mut self) -> impl Iterator> { [ Some(&mut self.sd), self.p0_5sd.as_mut(), @@ -434,6 +417,6 @@ impl ComputedStandardDeviationVecsFromDateIndex { fn mut_stateful_date_vecs( &mut self, ) -> impl Iterator>> { - self.mut_stateful_computed().map(|c| c.dateindex.um()) + self.mut_stateful_computed().map(|c| &mut c.dateindex) } } diff --git a/crates/brk_computer/src/internal/specialized/value/block/binary.rs b/crates/brk_computer/src/internal/specialized/value/block/binary.rs new file mode 100644 index 000000000..f8715473c --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/binary.rs @@ -0,0 +1,122 @@ +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; +use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec}; + +use crate::internal::{BinaryBlockSumCum, DerivedValueBlockSumCum, ValueBlockSumCum}; + +/// Lazy value vecs computed from two ValueBlockSumCum sources via binary transforms. +/// Used for computing coinbase = subsidy + fee. +#[derive(Clone, Traversable)] +pub struct ValueBinaryBlock { + pub sats: BinaryBlockSumCum, + pub bitcoin: BinaryBlockSumCum, + pub dollars: Option>, +} + +impl ValueBinaryBlock { + pub fn from_computed( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &ValueBlockSumCum, + source2: &ValueBlockSumCum, + ) -> Self + where + SatsF: BinaryTransform, + BitcoinF: BinaryTransform, + DollarsF: BinaryTransform, + { + let sats = BinaryBlockSumCum::from_computed::( + name, + version, + height_source1.boxed_clone(), + height_source2.boxed_clone(), + &source1.sats, + &source2.sats, + ); + + let bitcoin = BinaryBlockSumCum::from_computed::( + &format!("{name}_btc"), + version, + height_source1, + height_source2, + &source1.sats, + &source2.sats, + ); + + let dollars = source1 + .dollars + .as_ref() + .zip(source2.dollars.as_ref()) + .map(|(d1, d2)| { + BinaryBlockSumCum::from_computed::( + &format!("{name}_usd"), + version, + d1.height.boxed_clone(), + d2.height.boxed_clone(), + d1, + d2, + ) + }); + + Self { + sats, + bitcoin, + dollars, + } + } + + pub fn from_derived( + name: &str, + version: Version, + height_source1: IterableBoxedVec, + height_source2: IterableBoxedVec, + source1: &DerivedValueBlockSumCum, + source2: &DerivedValueBlockSumCum, + ) -> Self + where + SatsF: BinaryTransform, + BitcoinF: BinaryTransform, + DollarsF: BinaryTransform, + { + let sats = BinaryBlockSumCum::from_derived::( + name, + version, + height_source1.boxed_clone(), + height_source2.boxed_clone(), + &source1.sats, + &source2.sats, + ); + + let bitcoin = BinaryBlockSumCum::from_derived::( + &format!("{name}_btc"), + version, + height_source1, + height_source2, + &source1.sats, + &source2.sats, + ); + + let dollars = source1 + .dollars + .as_ref() + .zip(source2.dollars.as_ref()) + .map(|(d1, d2)| { + BinaryBlockSumCum::from_derived::( + &format!("{name}_usd"), + version, + d1.height_cumulative.0.boxed_clone(), + d2.height_cumulative.0.boxed_clone(), + d1, + d2, + ) + }); + + Self { + sats, + bitcoin, + dollars, + } + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/block/full.rs b/crates/brk_computer/src/internal/specialized/value/block/full.rs new file mode 100644 index 000000000..a862b7e4d --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/full.rs @@ -0,0 +1,86 @@ +//! Value type for Full pattern from Height. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; +use vecdb::{Database, EagerVec, Exit, IterableCloneableVec, PcoVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedBlockFull, LazyBlockFull, SatsToBitcoin}, + price, + traits::ComputeFromBitcoin, +}; + +#[derive(Clone, Traversable)] +pub struct ValueBlockFull { + pub sats: ComputedBlockFull, + pub bitcoin: LazyBlockFull, + pub dollars: Option>, +} + +const VERSION: Version = Version::ZERO; + +impl ValueBlockFull { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + compute_dollars: bool, + ) -> Result { + let v = version + VERSION; + + let sats = ComputedBlockFull::forced_import(db, name, v, indexes)?; + + let bitcoin = LazyBlockFull::from_computed::( + &format!("{name}_btc"), + v, + sats.height.boxed_clone(), + &sats, + ); + + let dollars = compute_dollars + .then(|| ComputedBlockFull::forced_import(db, &format!("{name}_usd"), v, indexes)) + .transpose()?; + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + // Compute sats + self.sats + .compute_all(indexes, starting_indexes, exit, |v| compute(v))?; + + // Compute dollars from bitcoin and price (if enabled) + if let (Some(dollars), Some(price)) = (self.dollars.as_mut(), price) { + let height_to_bitcoin = &self.bitcoin.height; + let height_to_price_close = &price.usd.chainindexes_to_price_close.height; + + dollars.compute_all(indexes, starting_indexes, exit, |v| { + v.compute_from_bitcoin( + starting_indexes.height, + height_to_bitcoin, + height_to_price_close, + exit, + ) + })?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/block/last.rs b/crates/brk_computer/src/internal/specialized/value/block/last.rs new file mode 100644 index 000000000..65c48708d --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/last.rs @@ -0,0 +1,86 @@ +//! Value type for Last pattern from Height. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; +use vecdb::{Database, EagerVec, Exit, IterableCloneableVec, PcoVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedBlockLast, LazyBlockLast, SatsToBitcoin}, + price, + traits::ComputeFromBitcoin, +}; + +#[derive(Clone, Traversable)] +pub struct ValueBlockLast { + pub sats: ComputedBlockLast, + pub bitcoin: LazyBlockLast, + pub dollars: Option>, +} + +const VERSION: Version = Version::ZERO; + +impl ValueBlockLast { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + compute_dollars: bool, + ) -> Result { + let v = version + VERSION; + + let sats = ComputedBlockLast::forced_import(db, name, v, indexes)?; + + let bitcoin = LazyBlockLast::from_computed::( + &format!("{name}_btc"), + v, + sats.height.boxed_clone(), + &sats, + ); + + let dollars = compute_dollars + .then(|| ComputedBlockLast::forced_import(db, &format!("{name}_usd"), v, indexes)) + .transpose()?; + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + // Compute sats (closure receives &mut height vec) + self.sats + .compute_all(indexes, starting_indexes, exit, |v| compute(v))?; + + // Compute dollars from bitcoin and price (if enabled) + if let (Some(dollars), Some(price)) = (self.dollars.as_mut(), price) { + let height_to_bitcoin = &self.bitcoin.height; + let height_to_price_close = &price.usd.chainindexes_to_price_close.height; + + dollars.compute_all(indexes, starting_indexes, exit, |v| { + v.compute_from_bitcoin( + starting_indexes.height, + height_to_bitcoin, + height_to_price_close, + exit, + ) + })?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/value/lazy/height.rs b/crates/brk_computer/src/internal/specialized/value/block/lazy.rs similarity index 59% rename from crates/brk_computer/src/internal/value/lazy/height.rs rename to crates/brk_computer/src/internal/specialized/value/block/lazy.rs index 7663dc58a..87937fb57 100644 --- a/crates/brk_computer/src/internal/value/lazy/height.rs +++ b/crates/brk_computer/src/internal/specialized/value/block/lazy.rs @@ -1,24 +1,23 @@ use brk_traversable::Traversable; use brk_types::{Bitcoin, Close, Dollars, Height, Sats, Version}; +use derive_more::{Deref, DerefMut}; use vecdb::{BinaryTransform, IterableBoxedVec, LazyVecFrom1, LazyVecFrom2, UnaryTransform}; +use super::LazyDerivedBlockValue; + const VERSION: Version = Version::ZERO; -/// Fully lazy version of `ComputedHeightValueVecs` where all fields are lazy transforms. -/// Used for computed values like supply_half where sources are stored sats and dollars vecs. -#[derive(Clone, Traversable)] -pub struct LazyHeightValueVecs { +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct LazyBlockValue { + #[traversable(rename = "sats")] pub sats: LazyVecFrom1, - pub bitcoin: LazyVecFrom1, - pub dollars: Option, Height, Sats>>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: LazyDerivedBlockValue, } -impl LazyHeightValueVecs { - /// Create lazy height value vecs from sats and price sources via transforms. - /// - /// - `SatsTransform`: Transform from Sats -> Sats (e.g., HalveSats) - /// - `BitcoinTransform`: Transform from Sats -> Bitcoin (e.g., HalveSatsToBitcoin) - /// - `DollarsTransform`: Binary transform from (Close, Sats) -> Dollars (e.g., HalfClosePriceTimesSats) +impl LazyBlockValue { pub fn from_sources( name: &str, sats_source: IterableBoxedVec, @@ -40,7 +39,6 @@ impl LazyHeightValueVecs { sats_source.clone(), ); - // dollars is binary transform: price × sats (with optional halving etc) let dollars = price_source.map(|price| { LazyVecFrom2::transformed::( &format!("{name}_usd"), @@ -52,8 +50,7 @@ impl LazyHeightValueVecs { Self { sats, - bitcoin, - dollars, + rest: LazyDerivedBlockValue { bitcoin, dollars }, } } } diff --git a/crates/brk_computer/src/internal/specialized/value/block/lazy_derived.rs b/crates/brk_computer/src/internal/specialized/value/block/lazy_derived.rs new file mode 100644 index 000000000..dc99bba59 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/lazy_derived.rs @@ -0,0 +1,39 @@ +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Close, Dollars, Height, Sats, Version}; +use vecdb::{IterableBoxedVec, LazyVecFrom1, LazyVecFrom2}; + +use crate::internal::{ClosePriceTimesSats, SatsToBitcoin}; + +#[derive(Clone, Traversable)] +pub struct LazyDerivedBlockValue { + pub bitcoin: LazyVecFrom1, + pub dollars: Option, Height, Sats>>, +} + +const VERSION: Version = Version::ZERO; + +impl LazyDerivedBlockValue { + pub fn from_source( + name: &str, + sats_source: IterableBoxedVec, + version: Version, + price_source: Option>>, + ) -> Self { + let bitcoin = LazyVecFrom1::transformed::( + &format!("{name}_btc"), + version + VERSION, + sats_source.clone(), + ); + + let dollars = price_source.map(|price| { + LazyVecFrom2::transformed::( + &format!("{name}_usd"), + version + VERSION, + price, + sats_source, + ) + }); + + Self { bitcoin, dollars } + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/block/mod.rs b/crates/brk_computer/src/internal/specialized/value/block/mod.rs new file mode 100644 index 000000000..e44c232df --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/mod.rs @@ -0,0 +1,15 @@ +mod binary; +mod full; +mod last; +mod lazy_derived; +mod lazy; +mod sum; +mod sum_cum; + +pub use binary::*; +pub use full::*; +pub use last::*; +pub use lazy::*; +pub use lazy_derived::*; +pub use sum::*; +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/specialized/value/block/sum.rs b/crates/brk_computer/src/internal/specialized/value/block/sum.rs new file mode 100644 index 000000000..979431ede --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/sum.rs @@ -0,0 +1,86 @@ +//! Value type for Sum pattern from Height. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; +use vecdb::{Database, EagerVec, Exit, IterableCloneableVec, PcoVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedBlockSum, LazyBlockSum, SatsToBitcoin}, + price, + traits::ComputeFromBitcoin, +}; + +#[derive(Clone, Traversable)] +pub struct ValueBlockSum { + pub sats: ComputedBlockSum, + pub bitcoin: LazyBlockSum, + pub dollars: Option>, +} + +const VERSION: Version = Version::ZERO; + +impl ValueBlockSum { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + compute_dollars: bool, + ) -> Result { + let v = version + VERSION; + + let sats = ComputedBlockSum::forced_import(db, name, v, indexes)?; + + let bitcoin = LazyBlockSum::from_computed::( + &format!("{name}_btc"), + v, + sats.height.boxed_clone(), + &sats, + ); + + let dollars = compute_dollars + .then(|| ComputedBlockSum::forced_import(db, &format!("{name}_usd"), v, indexes)) + .transpose()?; + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + // Compute sats (closure receives &mut height vec) + self.sats + .compute_all(indexes, starting_indexes, exit, |v| compute(v))?; + + // Compute dollars from bitcoin and price (if enabled) + if let (Some(dollars), Some(price)) = (self.dollars.as_mut(), price) { + let height_to_bitcoin = &self.bitcoin.height; + let height_to_price_close = &price.usd.chainindexes_to_price_close.height; + + dollars.compute_all(indexes, starting_indexes, exit, |v| { + v.compute_from_bitcoin( + starting_indexes.height, + height_to_bitcoin, + height_to_price_close, + exit, + ) + })?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/block/sum_cum.rs b/crates/brk_computer/src/internal/specialized/value/block/sum_cum.rs new file mode 100644 index 000000000..6e68861f8 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/block/sum_cum.rs @@ -0,0 +1,118 @@ +//! Value type for SumCum pattern from Height. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; +use vecdb::{Database, EagerVec, Exit, IterableCloneableVec, PcoVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedBlockSumCum, LazyBlockSumCum, SatsToBitcoin}, + price, + traits::ComputeFromBitcoin, +}; +use vecdb::IterableVec; + +#[derive(Clone, Traversable)] +pub struct ValueBlockSumCum { + pub sats: ComputedBlockSumCum, + pub bitcoin: LazyBlockSumCum, + pub dollars: Option>, +} + +const VERSION: Version = Version::ZERO; + +impl ValueBlockSumCum { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + compute_dollars: bool, + ) -> Result { + let v = version + VERSION; + + let sats = ComputedBlockSumCum::forced_import(db, name, v, indexes)?; + + let bitcoin = LazyBlockSumCum::from_computed::( + &format!("{name}_btc"), + v, + sats.height.boxed_clone(), + &sats, + ); + + let dollars = compute_dollars + .then(|| ComputedBlockSumCum::forced_import(db, &format!("{name}_usd"), v, indexes)) + .transpose()?; + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn compute_all( + &mut self, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + // Compute sats (closure receives &mut height vec) + self.sats + .compute_all(indexes, starting_indexes, exit, |v| compute(v))?; + + // Compute dollars from bitcoin and price (if enabled) + if let (Some(dollars), Some(price)) = (self.dollars.as_mut(), price) { + let height_to_bitcoin = &self.bitcoin.height; + let height_to_price_close = &price.usd.chainindexes_to_price_close.height; + + dollars.compute_all(indexes, starting_indexes, exit, |v| { + v.compute_from_bitcoin( + starting_indexes.height, + height_to_bitcoin, + height_to_price_close, + exit, + ) + })?; + } + + Ok(()) + } + + /// Derive from an external height source (e.g., a LazyVec). + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + // Derive sats from source + self.sats + .derive_from(indexes, starting_indexes, source, exit)?; + + // Compute dollars from bitcoin and price (if enabled) + if let (Some(dollars), Some(price)) = (self.dollars.as_mut(), price) { + let height_to_bitcoin = &self.bitcoin.height; + let height_to_price_close = &price.usd.chainindexes_to_price_close.height; + + dollars.compute_all(indexes, starting_indexes, exit, |v| { + v.compute_from_bitcoin( + starting_indexes.height, + height_to_bitcoin, + height_to_price_close, + exit, + ) + })?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/date/derived_last.rs b/crates/brk_computer/src/internal/specialized/value/date/derived_last.rs new file mode 100644 index 000000000..4d230875d --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/date/derived_last.rs @@ -0,0 +1,77 @@ +//! Value type for Derived Last pattern from DateIndex (when source is external). + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, DateIndex, Dollars, Sats, Version}; +use vecdb::{Database, Exit, IterableBoxedVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ComputedDateLast, DerivedDateLast, LazyDateLast, SatsToBitcoin}, + price, + traits::ComputeFromBitcoin, + utils::OptionExt, +}; + +#[derive(Clone, Traversable)] +pub struct ValueDerivedDateLast { + pub sats: DerivedDateLast, + pub bitcoin: LazyDateLast, + pub dollars: Option>, +} + +const VERSION: Version = Version::ZERO; + +impl ValueDerivedDateLast { + pub fn from_source( + db: &Database, + name: &str, + source: IterableBoxedVec, + version: Version, + compute_dollars: bool, + indexes: &indexes::Vecs, + ) -> Result { + let sats = DerivedDateLast::from_source(name, version + VERSION, source.clone(), indexes); + + let bitcoin = LazyDateLast::from_derived::( + &format!("{name}_btc"), + version + VERSION, + source, + &sats, + ); + + let dollars = compute_dollars.then(|| { + ComputedDateLast::forced_import(db, &format!("{name}_usd"), version + VERSION, indexes) + .unwrap() + }); + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn compute_rest( + &mut self, + price: Option<&price::Vecs>, + _starting_indexes: &ComputeIndexes, + exit: &Exit, + ) -> Result<()> { + let dateindex_to_bitcoin = &*self.bitcoin.dateindex; + let dateindex_to_price_close = &price.u().usd.timeindexes_to_price_close.dateindex; + + if let Some(dollars) = self.dollars.as_mut() { + dollars.compute_all(_starting_indexes, exit, |v| { + v.compute_from_bitcoin( + _starting_indexes.dateindex, + dateindex_to_bitcoin, + dateindex_to_price_close, + exit, + ) + })?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/date/last.rs b/crates/brk_computer/src/internal/specialized/value/date/last.rs new file mode 100644 index 000000000..b91815f79 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/date/last.rs @@ -0,0 +1,73 @@ +//! Value type for Last pattern from DateIndex. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{DateIndex, Sats, Version}; +use derive_more::{Deref, DerefMut}; +use vecdb::{Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, PcoVec}; + +use crate::{ComputeIndexes, indexes, price}; + +use super::ValueDerivedDateLast; + +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct ValueDateLast { + #[traversable(rename = "sats")] + pub sats_dateindex: EagerVec>, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub rest: ValueDerivedDateLast, +} + +const VERSION: Version = Version::ZERO; + +impl ValueDateLast { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + compute_dollars: bool, + indexes: &indexes::Vecs, + ) -> Result { + let sats_dateindex = EagerVec::forced_import(db, name, version + VERSION)?; + + let rest = ValueDerivedDateLast::from_source( + db, + name, + sats_dateindex.boxed_clone(), + version + VERSION, + compute_dollars, + indexes, + )?; + + Ok(Self { + sats_dateindex, + rest, + }) + } + + pub fn compute_all( + &mut self, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + mut compute: F, + ) -> Result<()> + where + F: FnMut(&mut EagerVec>) -> Result<()>, + { + compute(&mut self.sats_dateindex)?; + self.rest.compute_rest(price, starting_indexes, exit)?; + Ok(()) + } + + pub fn compute_rest( + &mut self, + price: Option<&price::Vecs>, + starting_indexes: &ComputeIndexes, + exit: &Exit, + ) -> Result<()> { + self.rest.compute_rest(price, starting_indexes, exit) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/date/lazy_last.rs b/crates/brk_computer/src/internal/specialized/value/date/lazy_last.rs new file mode 100644 index 000000000..7e5b95864 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/date/lazy_last.rs @@ -0,0 +1,56 @@ +//! Lazy value type for Last pattern from DateIndex. + +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Sats, Version}; +use vecdb::{IterableCloneableVec, UnaryTransform}; + +use crate::internal::{LazyDateLast, ValueDateLast}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +pub struct LazyValueDateLast { + pub sats: LazyDateLast, + pub bitcoin: LazyDateLast, + pub dollars: Option>, +} + +impl LazyValueDateLast { + pub fn from_source( + name: &str, + source: &ValueDateLast, + version: Version, + ) -> Self + where + SatsTransform: UnaryTransform, + BitcoinTransform: UnaryTransform, + DollarsTransform: UnaryTransform, + { + let v = version + VERSION; + + let sats = LazyDateLast::from_derived::( + name, + v, + source.sats_dateindex.boxed_clone(), + &source.sats, + ); + + let bitcoin = LazyDateLast::from_derived::( + &format!("{name}_btc"), + v, + source.sats_dateindex.boxed_clone(), + &source.sats, + ); + + let dollars = source.dollars.as_ref().map(|dollars_source| { + LazyDateLast::from_computed::( + &format!("{name}_usd"), + v, + dollars_source.dateindex.boxed_clone(), + dollars_source, + ) + }); + + Self { sats, bitcoin, dollars } + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/date/mod.rs b/crates/brk_computer/src/internal/specialized/value/date/mod.rs new file mode 100644 index 000000000..b98939532 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/date/mod.rs @@ -0,0 +1,7 @@ +mod derived_last; +mod last; +mod lazy_last; + +pub use derived_last::*; +pub use last::*; +pub use lazy_last::*; diff --git a/crates/brk_computer/src/internal/specialized/value/derived_block/mod.rs b/crates/brk_computer/src/internal/specialized/value/derived_block/mod.rs new file mode 100644 index 000000000..9d6b32026 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/derived_block/mod.rs @@ -0,0 +1,3 @@ +mod sum_cum; + +pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/specialized/value/derived_block/sum_cum.rs b/crates/brk_computer/src/internal/specialized/value/derived_block/sum_cum.rs new file mode 100644 index 000000000..7bf228d79 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/derived_block/sum_cum.rs @@ -0,0 +1,101 @@ +//! Value type for derived SumCum pattern (derives from external height source). + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Close, Dollars, Height, Sats, Version}; +use vecdb::{Database, Exit, IterableBoxedVec, IterableCloneableVec, IterableVec, LazyVecFrom2}; + +use crate::{ + ComputeIndexes, indexes, + internal::{ClosePriceTimesSats, DerivedComputedBlockSumCum, LazyBlockSumCum, SatsToBitcoin}, + price, +}; + +pub type LazyDollarsHeight = LazyVecFrom2, Height, Sats>; + +/// Value wrapper for derived SumCum (derives from external height source). +#[derive(Clone, Traversable)] +pub struct DerivedValueBlockSumCum { + pub sats: DerivedComputedBlockSumCum, + pub bitcoin: LazyBlockSumCum, + pub dollars_source: Option, + pub dollars: Option>, +} + +const VERSION: Version = Version::ZERO; + +impl DerivedValueBlockSumCum { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + sats_source: IterableBoxedVec, + price: Option<&price::Vecs>, + ) -> Result { + let v = version + VERSION; + + let sats = DerivedComputedBlockSumCum::forced_import( + db, + name, + sats_source.boxed_clone(), + v, + indexes, + )?; + + let bitcoin = LazyBlockSumCum::from_derived::( + &format!("{name}_btc"), + v, + sats_source.boxed_clone(), + &sats, + ); + + let (dollars_source, dollars) = if let Some(price) = price { + let dollars_source = LazyVecFrom2::transformed::( + &format!("{name}_usd"), + v, + price.usd.chainindexes_to_price_close.height.boxed_clone(), + sats_source.boxed_clone(), + ); + + let dollars = DerivedComputedBlockSumCum::forced_import( + db, + &format!("{name}_usd"), + dollars_source.boxed_clone(), + v, + indexes, + )?; + + (Some(dollars_source), Some(dollars)) + } else { + (None, None) + }; + + Ok(Self { + sats, + bitcoin, + dollars_source, + dollars, + }) + } + + /// Derive aggregates from caller-provided sats height source. + pub fn derive_from( + &mut self, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + sats_source: &impl IterableVec, + exit: &Exit, + ) -> Result<()> { + self.sats + .derive_from(indexes, starting_indexes, sats_source, exit)?; + + if let (Some(dollars), Some(dollars_source)) = + (self.dollars.as_mut(), self.dollars_source.as_ref()) + { + dollars.derive_from(indexes, starting_indexes, dollars_source, exit)?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/mod.rs b/crates/brk_computer/src/internal/specialized/value/mod.rs new file mode 100644 index 000000000..e67ad59bb --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/mod.rs @@ -0,0 +1,9 @@ +mod block; +mod date; +mod derived_block; +mod tx; + +pub use block::*; +pub use date::*; +pub use derived_block::*; +pub use tx::*; diff --git a/crates/brk_computer/src/internal/specialized/value/tx/dollars.rs b/crates/brk_computer/src/internal/specialized/value/tx/dollars.rs new file mode 100644 index 000000000..7146b9501 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/tx/dollars.rs @@ -0,0 +1,140 @@ +//! Dollars from TxIndex with lazy txindex and eager aggregates. + +use brk_error::Result; +use brk_indexer::Indexer; +use brk_traversable::Traversable; +use brk_types::{ + Bitcoin, Close, DateIndex, DifficultyEpoch, Dollars, Height, Sats, TxIndex, Version, +}; +use derive_more::{Deref, DerefMut}; +use vecdb::{Database, Exit, IterableBoxedVec, IterableCloneableVec, LazyVecFrom3}; + +use crate::{ + ComputeIndexes, indexes, + internal::{DerivedDateFull, Full, LazyFull, Stats}, +}; + +/// Lazy dollars at TxIndex: `sats * price[height]` +pub type LazyDollarsTxIndex = + LazyVecFrom3>; + +/// Dollars with lazy txindex field and eager height/dateindex aggregates. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct DollarsTxFull { + #[traversable(skip)] + pub txindex: LazyDollarsTxIndex, + pub height: Full, + pub difficultyepoch: LazyFull, + pub dateindex: Stats, + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dates: DerivedDateFull, +} + +const VERSION: Version = Version::ZERO; + +impl DollarsTxFull { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + sats_txindex: IterableBoxedVec, + txindex_to_height: IterableBoxedVec, + height_to_price: IterableBoxedVec>, + ) -> Result { + let v = version + VERSION; + + let txindex = + create_lazy_txindex(name, v, sats_txindex, txindex_to_height, height_to_price); + let height = Full::forced_import(db, name, v)?; + let dateindex = Stats::forced_import(db, name, v)?; + + let difficultyepoch = + LazyFull::::from_stats_aggregate( + name, + v, + height.distribution.average.0.boxed_clone(), + height.distribution.minmax.min.0.boxed_clone(), + height.distribution.minmax.max.0.boxed_clone(), + height.sum_cum.sum.0.boxed_clone(), + height.sum_cum.cumulative.0.boxed_clone(), + indexes + .block + .difficultyepoch_to_difficultyepoch + .boxed_clone(), + ); + + let dates = DerivedDateFull::from_sources( + name, + v, + dateindex.average.0.boxed_clone(), + dateindex.minmax.min.0.boxed_clone(), + dateindex.minmax.max.0.boxed_clone(), + dateindex.sum_cum.sum.0.boxed_clone(), + dateindex.sum_cum.cumulative.0.boxed_clone(), + indexes, + ); + + Ok(Self { + txindex, + height, + difficultyepoch, + dateindex, + dates, + }) + } + + pub fn derive_from( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + exit: &Exit, + ) -> Result<()> { + self.height.compute( + starting_indexes.height, + &self.txindex, + &indexer.vecs.tx.height_to_first_txindex, + &indexes.block.height_to_txindex_count, + exit, + )?; + + self.dateindex.compute( + starting_indexes.dateindex, + &self.height.distribution.average.0, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, + exit, + )?; + + Ok(()) + } +} + +fn create_lazy_txindex( + name: &str, + version: Version, + sats_txindex: IterableBoxedVec, + txindex_to_height: IterableBoxedVec, + height_to_price: IterableBoxedVec>, +) -> LazyDollarsTxIndex { + LazyVecFrom3::init( + &format!("{name}_txindex"), + version, + sats_txindex, + txindex_to_height, + height_to_price, + |txindex, sats_iter, height_iter, price_iter| { + sats_iter.get(txindex).and_then(|sats| { + height_iter.get(txindex).and_then(|height| { + price_iter + .get(height) + .map(|close| *close * Bitcoin::from(sats)) + }) + }) + }, + ) +} diff --git a/crates/brk_computer/src/internal/specialized/value/tx/full.rs b/crates/brk_computer/src/internal/specialized/value/tx/full.rs new file mode 100644 index 000000000..6204763f6 --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/tx/full.rs @@ -0,0 +1,79 @@ +//! Value type for Full pattern from TxIndex. + +use brk_error::Result; +use brk_indexer::Indexer; +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Sats, TxIndex, Version}; +use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec}; + +use crate::{ + ComputeIndexes, indexes, + internal::{DerivedTxFull, DollarsTxFull, LazyDerivedTxFull, SatsToBitcoin}, + price, +}; + +#[derive(Clone, Traversable)] +pub struct ValueDerivedTxFull { + pub sats: DerivedTxFull, + pub bitcoin: LazyDerivedTxFull, + pub dollars: Option, +} + +const VERSION: Version = Version::ZERO; + +impl ValueDerivedTxFull { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + indexer: &Indexer, + price: Option<&price::Vecs>, + sats_txindex: &impl IterableCloneableVec, + ) -> Result { + let v = version + VERSION; + + let sats = DerivedTxFull::forced_import(db, name, v, indexes)?; + + let bitcoin = + LazyDerivedTxFull::from_computed::(&format!("{name}_btc"), v, &sats); + + let dollars = price + .map(|price| { + DollarsTxFull::forced_import( + db, + &format!("{name}_usd"), + v, + indexes, + sats_txindex.boxed_clone(), + indexer.vecs.tx.txindex_to_height.boxed_clone(), + price.usd.chainindexes_to_price_close.height.boxed_clone(), + ) + }) + .transpose()?; + + Ok(Self { + sats, + bitcoin, + dollars, + }) + } + + pub fn derive_from( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + starting_indexes: &ComputeIndexes, + txindex_source: &impl CollectableVec, + exit: &Exit, + ) -> Result<()> { + self.sats + .derive_from(indexer, indexes, starting_indexes, txindex_source, exit)?; + + if let Some(dollars) = self.dollars.as_mut() { + dollars.derive_from(indexer, indexes, starting_indexes, exit)?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/specialized/value/tx/mod.rs b/crates/brk_computer/src/internal/specialized/value/tx/mod.rs new file mode 100644 index 000000000..b3e24d62b --- /dev/null +++ b/crates/brk_computer/src/internal/specialized/value/tx/mod.rs @@ -0,0 +1,5 @@ +mod dollars; +mod full; + +pub use dollars::*; +pub use full::*; diff --git a/crates/brk_computer/src/internal/computed/traits.rs b/crates/brk_computer/src/internal/traits/computed.rs similarity index 100% rename from crates/brk_computer/src/internal/computed/traits.rs rename to crates/brk_computer/src/internal/traits/computed.rs diff --git a/crates/brk_computer/src/internal/value/mod.rs b/crates/brk_computer/src/internal/traits/mod.rs similarity index 52% rename from crates/brk_computer/src/internal/value/mod.rs rename to crates/brk_computer/src/internal/traits/mod.rs index 4e1cf831d..31174c352 100644 --- a/crates/brk_computer/src/internal/value/mod.rs +++ b/crates/brk_computer/src/internal/traits/mod.rs @@ -1,5 +1,5 @@ mod computed; -mod lazy; +mod numeric; pub use computed::*; -pub use lazy::*; +pub use numeric::*; diff --git a/crates/brk_computer/src/internal/traits/numeric.rs b/crates/brk_computer/src/internal/traits/numeric.rs new file mode 100644 index 000000000..d65a7c920 --- /dev/null +++ b/crates/brk_computer/src/internal/traits/numeric.rs @@ -0,0 +1,5 @@ +use super::ComputedVecValue; + +pub trait NumericValue: ComputedVecValue + From + Into {} + +impl NumericValue for T where T: ComputedVecValue + From + Into {} diff --git a/crates/brk_computer/src/internal/transform/close_price_times_ratio.rs b/crates/brk_computer/src/internal/transform/close_price_times_ratio.rs new file mode 100644 index 000000000..320d8bfd4 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/close_price_times_ratio.rs @@ -0,0 +1,13 @@ +use brk_types::{Close, Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// Close * StoredF32 -> Dollars (price × ratio) +/// Same as PriceTimesRatio but accepts Close price source. +pub struct ClosePriceTimesRatio; + +impl BinaryTransform, StoredF32, Dollars> for ClosePriceTimesRatio { + #[inline(always)] + fn apply(price: Close, ratio: StoredF32) -> Dollars { + *price * ratio + } +} diff --git a/crates/brk_computer/src/internal/transform/close_price_times_sats.rs b/crates/brk_computer/src/internal/transform/close_price_times_sats.rs new file mode 100644 index 000000000..bf38c0f4a --- /dev/null +++ b/crates/brk_computer/src/internal/transform/close_price_times_sats.rs @@ -0,0 +1,13 @@ +use brk_types::{Bitcoin, Close, Dollars, Sats}; +use vecdb::BinaryTransform; + +/// Close * Sats -> Dollars (price × sats / 1e8) +/// Same as PriceTimesSats but accepts Close price source. +pub struct ClosePriceTimesSats; + +impl BinaryTransform, Sats, Dollars> for ClosePriceTimesSats { + #[inline(always)] + fn apply(price: Close, sats: Sats) -> Dollars { + *price * Bitcoin::from(sats) + } +} diff --git a/crates/brk_computer/src/internal/transform/difference_f32.rs b/crates/brk_computer/src/internal/transform/difference_f32.rs new file mode 100644 index 000000000..fe273eaa6 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/difference_f32.rs @@ -0,0 +1,12 @@ +use brk_types::StoredF32; +use vecdb::BinaryTransform; + +/// (StoredF32, StoredF32) -> StoredF32 difference (a - b) +pub struct DifferenceF32; + +impl BinaryTransform for DifferenceF32 { + #[inline(always)] + fn apply(a: StoredF32, b: StoredF32) -> StoredF32 { + StoredF32::from(*a - *b) + } +} diff --git a/crates/brk_computer/src/internal/transform/dollar_halve.rs b/crates/brk_computer/src/internal/transform/dollar_halve.rs new file mode 100644 index 000000000..0cbc28f0b --- /dev/null +++ b/crates/brk_computer/src/internal/transform/dollar_halve.rs @@ -0,0 +1,12 @@ +use brk_types::Dollars; +use vecdb::UnaryTransform; + +/// Dollars -> Dollars/2 (for supply_half_usd) +pub struct HalveDollars; + +impl UnaryTransform for HalveDollars { + #[inline(always)] + fn apply(dollars: Dollars) -> Dollars { + dollars.halved() + } +} diff --git a/crates/brk_computer/src/internal/transform/dollar_identity.rs b/crates/brk_computer/src/internal/transform/dollar_identity.rs new file mode 100644 index 000000000..12754ac68 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/dollar_identity.rs @@ -0,0 +1,12 @@ +use brk_types::Dollars; +use vecdb::UnaryTransform; + +/// Dollars -> Dollars (identity transform for lazy references) +pub struct DollarsIdentity; + +impl UnaryTransform for DollarsIdentity { + #[inline(always)] + fn apply(dollars: Dollars) -> Dollars { + dollars + } +} diff --git a/crates/brk_computer/src/internal/transform/dollar_minus.rs b/crates/brk_computer/src/internal/transform/dollar_minus.rs new file mode 100644 index 000000000..1294c391c --- /dev/null +++ b/crates/brk_computer/src/internal/transform/dollar_minus.rs @@ -0,0 +1,11 @@ +use brk_types::Dollars; +use vecdb::BinaryTransform; + +pub struct DollarsMinus; + +impl BinaryTransform for DollarsMinus { + #[inline(always)] + fn apply(lhs: Dollars, rhs: Dollars) -> Dollars { + lhs - rhs + } +} diff --git a/crates/brk_computer/src/internal/transform/dollar_plus.rs b/crates/brk_computer/src/internal/transform/dollar_plus.rs new file mode 100644 index 000000000..d2b2743b3 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/dollar_plus.rs @@ -0,0 +1,13 @@ +use brk_types::Dollars; +use vecdb::BinaryTransform; + +/// (Dollars, Dollars) -> Dollars addition +/// Used for computing total = profit + loss +pub struct DollarsPlus; + +impl BinaryTransform for DollarsPlus { + #[inline(always)] + fn apply(lhs: Dollars, rhs: Dollars) -> Dollars { + lhs + rhs + } +} diff --git a/crates/brk_computer/src/internal/transform/dollar_times_tenths.rs b/crates/brk_computer/src/internal/transform/dollar_times_tenths.rs new file mode 100644 index 000000000..c557c7947 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/dollar_times_tenths.rs @@ -0,0 +1,12 @@ +use brk_types::Dollars; +use vecdb::UnaryTransform; + +/// Dollars * (V/10) -> Dollars (e.g., V=8 -> * 0.8, V=24 -> * 2.4) +pub struct DollarsTimesTenths; + +impl UnaryTransform for DollarsTimesTenths { + #[inline(always)] + fn apply(d: Dollars) -> Dollars { + d * (V as f64 / 10.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/f32_identity.rs b/crates/brk_computer/src/internal/transform/f32_identity.rs new file mode 100644 index 000000000..345f69c7b --- /dev/null +++ b/crates/brk_computer/src/internal/transform/f32_identity.rs @@ -0,0 +1,12 @@ +use brk_types::StoredF32; +use vecdb::UnaryTransform; + +/// StoredF32 -> StoredF32 (identity transform for lazy references/proxies) +pub struct StoredF32Identity; + +impl UnaryTransform for StoredF32Identity { + #[inline(always)] + fn apply(v: StoredF32) -> StoredF32 { + v + } +} diff --git a/crates/brk_computer/src/internal/transform/half_close_price_times_sats.rs b/crates/brk_computer/src/internal/transform/half_close_price_times_sats.rs new file mode 100644 index 000000000..069d76720 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/half_close_price_times_sats.rs @@ -0,0 +1,13 @@ +use brk_types::{Bitcoin, Close, Dollars, Sats}; +use vecdb::BinaryTransform; + +/// Close * Sats -> Dollars/2 (price × sats / 1e8 / 2) +/// Computes halved dollars directly from sats, avoiding lazy-from-lazy chains. +pub struct HalfClosePriceTimesSats; + +impl BinaryTransform, Sats, Dollars> for HalfClosePriceTimesSats { + #[inline(always)] + fn apply(price: Close, sats: Sats) -> Dollars { + (*price * Bitcoin::from(sats)).halved() + } +} diff --git a/crates/brk_computer/src/internal/transform/mod.rs b/crates/brk_computer/src/internal/transform/mod.rs new file mode 100644 index 000000000..8c7b8c18c --- /dev/null +++ b/crates/brk_computer/src/internal/transform/mod.rs @@ -0,0 +1,75 @@ +mod close_price_times_ratio; +mod close_price_times_sats; +mod difference_f32; +mod dollar_halve; +mod dollar_identity; +mod dollar_minus; +mod dollar_plus; +mod dollar_times_tenths; +mod f32_identity; +mod half_close_price_times_sats; +mod percentage_btc_f64; +mod percentage_diff_close_dollars; +mod percentage_dollars_f32; +mod percentage_dollars_f32_neg; +mod percentage_sats_f64; +mod percentage_u32_f32; +mod percentage_u64_f32; +mod price_times_ratio; +mod ratio32; +mod ratio32_neg; +mod ratio_f32; +mod return_f32_tenths; +mod return_i16; +mod return_u16; +mod rsi_formula; +mod sat_halve; +mod sat_halve_to_bitcoin; +mod sat_identity; +mod sat_mask; +mod sat_plus; +mod sat_plus_to_bitcoin; +mod sat_to_bitcoin; +mod u16_to_years; +mod volatility_sqrt30; +mod volatility_sqrt365; +mod volatility_sqrt7; +mod weight_to_fullness; + +pub use close_price_times_ratio::*; +pub use close_price_times_sats::*; +pub use difference_f32::*; +pub use dollar_halve::*; +pub use dollar_identity::*; +pub use dollar_minus::*; +pub use dollar_plus::*; +pub use dollar_times_tenths::*; +pub use f32_identity::*; +pub use half_close_price_times_sats::*; +pub use percentage_btc_f64::*; +pub use percentage_diff_close_dollars::*; +pub use percentage_dollars_f32::*; +pub use percentage_dollars_f32_neg::*; +pub use percentage_sats_f64::*; +pub use percentage_u32_f32::*; +pub use percentage_u64_f32::*; +pub use price_times_ratio::*; +pub use ratio32::*; +pub use ratio32_neg::*; +pub use ratio_f32::*; +pub use return_f32_tenths::*; +pub use return_i16::*; +pub use return_u16::*; +pub use rsi_formula::*; +pub use sat_halve::*; +pub use sat_halve_to_bitcoin::*; +pub use sat_identity::*; +pub use sat_mask::*; +pub use sat_plus::*; +pub use sat_plus_to_bitcoin::*; +pub use sat_to_bitcoin::*; +pub use u16_to_years::*; +pub use volatility_sqrt30::*; +pub use volatility_sqrt365::*; +pub use volatility_sqrt7::*; +pub use weight_to_fullness::*; diff --git a/crates/brk_computer/src/internal/transform/percentage_btc_f64.rs b/crates/brk_computer/src/internal/transform/percentage_btc_f64.rs new file mode 100644 index 000000000..5393ab891 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_btc_f64.rs @@ -0,0 +1,14 @@ +use brk_types::{Bitcoin, StoredF64}; +use vecdb::BinaryTransform; + +/// (Bitcoin, Bitcoin) -> StoredF64 percentage (a/b × 100) +/// Used for supply ratio calculations like supply_in_profit / total_supply × 100 +pub struct PercentageBtcF64; + +impl BinaryTransform for PercentageBtcF64 { + #[inline(always)] + fn apply(numerator: Bitcoin, denominator: Bitcoin) -> StoredF64 { + // Bitcoin / Bitcoin returns StoredF64, so dereference and multiply + StoredF64::from(*(numerator / denominator) * 100.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/percentage_diff_close_dollars.rs b/crates/brk_computer/src/internal/transform/percentage_diff_close_dollars.rs new file mode 100644 index 000000000..64446c8e9 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_diff_close_dollars.rs @@ -0,0 +1,18 @@ +use brk_types::{Close, Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// (Close, Dollars) -> StoredF32 percentage difference ((a/b - 1) × 100) +/// Used for DCA returns: (price / dca_average_price - 1) × 100 +/// Also used for drawdown: (close / ath - 1) × 100 (note: drawdown is typically negative) +pub struct PercentageDiffCloseDollars; + +impl BinaryTransform, Dollars, StoredF32> for PercentageDiffCloseDollars { + #[inline(always)] + fn apply(close: Close, base: Dollars) -> StoredF32 { + if base == Dollars::ZERO { + StoredF32::default() + } else { + StoredF32::from((**close / *base - 1.0) * 100.0) + } + } +} diff --git a/crates/brk_computer/src/internal/transform/percentage_dollars_f32.rs b/crates/brk_computer/src/internal/transform/percentage_dollars_f32.rs new file mode 100644 index 000000000..9f61b7175 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_dollars_f32.rs @@ -0,0 +1,14 @@ +use brk_types::{Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// (Dollars, Dollars) -> StoredF32 percentage (a/b × 100) +/// Used for unrealized/realized ratio calculations +pub struct PercentageDollarsF32; + +impl BinaryTransform for PercentageDollarsF32 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { + // Dollars / Dollars returns StoredF64, so dereference and multiply + StoredF32::from(*(numerator / denominator) * 100.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/percentage_dollars_f32_neg.rs b/crates/brk_computer/src/internal/transform/percentage_dollars_f32_neg.rs new file mode 100644 index 000000000..26e8654cf --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_dollars_f32_neg.rs @@ -0,0 +1,14 @@ +use brk_types::{Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// (Dollars, Dollars) -> StoredF32 negated percentage (-(a/b × 100)) +/// Used for negated loss ratio calculations, avoiding lazy-from-lazy chains. +pub struct NegPercentageDollarsF32; + +impl BinaryTransform for NegPercentageDollarsF32 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { + // Dollars / Dollars returns StoredF64, so dereference and multiply + StoredF32::from(-(*(numerator / denominator) * 100.0)) + } +} diff --git a/crates/brk_computer/src/internal/transform/percentage_sats_f64.rs b/crates/brk_computer/src/internal/transform/percentage_sats_f64.rs new file mode 100644 index 000000000..f02b7ceb0 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_sats_f64.rs @@ -0,0 +1,13 @@ +use brk_types::{Sats, StoredF64}; +use vecdb::BinaryTransform; + +/// (Sats, Sats) -> StoredF64 percentage (a/b × 100) +/// Used for supply ratio calculations (equivalent to Bitcoin/Bitcoin since 1e8 cancels) +pub struct PercentageSatsF64; + +impl BinaryTransform for PercentageSatsF64 { + #[inline(always)] + fn apply(numerator: Sats, denominator: Sats) -> StoredF64 { + StoredF64::from((*numerator as f64 / *denominator as f64) * 100.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/percentage_u32_f32.rs b/crates/brk_computer/src/internal/transform/percentage_u32_f32.rs new file mode 100644 index 000000000..eb26fbd8c --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_u32_f32.rs @@ -0,0 +1,13 @@ +use brk_types::{StoredF32, StoredU32}; +use vecdb::BinaryTransform; + +/// (StoredU32, StoredU32) -> StoredF32 percentage (a/b × 100) +/// Used for pool dominance calculations (pool_blocks / total_blocks × 100) +pub struct PercentageU32F32; + +impl BinaryTransform for PercentageU32F32 { + #[inline(always)] + fn apply(numerator: StoredU32, denominator: StoredU32) -> StoredF32 { + StoredF32::from((*numerator as f64 / *denominator as f64) * 100.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/percentage_u64_f32.rs b/crates/brk_computer/src/internal/transform/percentage_u64_f32.rs new file mode 100644 index 000000000..cb72df424 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/percentage_u64_f32.rs @@ -0,0 +1,17 @@ +use brk_types::{StoredF32, StoredU64}; +use vecdb::BinaryTransform; + +/// (StoredU64, StoredU64) -> StoredF32 percentage (a/b × 100) +/// Used for adoption ratio calculations (type_count / total_count × 100) +pub struct PercentageU64F32; + +impl BinaryTransform for PercentageU64F32 { + #[inline(always)] + fn apply(numerator: StoredU64, denominator: StoredU64) -> StoredF32 { + if *denominator == 0 { + StoredF32::default() + } else { + StoredF32::from((*numerator as f64 / *denominator as f64) * 100.0) + } + } +} diff --git a/crates/brk_computer/src/internal/transform/price_times_ratio.rs b/crates/brk_computer/src/internal/transform/price_times_ratio.rs new file mode 100644 index 000000000..768254ba6 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/price_times_ratio.rs @@ -0,0 +1,12 @@ +use brk_types::{Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// Dollars * StoredF32 -> Dollars (price × ratio) +pub struct PriceTimesRatio; + +impl BinaryTransform for PriceTimesRatio { + #[inline(always)] + fn apply(price: Dollars, ratio: StoredF32) -> Dollars { + price * ratio + } +} diff --git a/crates/brk_computer/src/internal/transform/ratio32.rs b/crates/brk_computer/src/internal/transform/ratio32.rs new file mode 100644 index 000000000..dfb44dd7f --- /dev/null +++ b/crates/brk_computer/src/internal/transform/ratio32.rs @@ -0,0 +1,13 @@ +use brk_types::{Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// (Dollars, Dollars) -> StoredF32 ratio +/// Used for computing percentage ratios like profit/total, loss/total, etc. +pub struct Ratio32; + +impl BinaryTransform for Ratio32 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { + StoredF32::from(numerator / denominator) + } +} diff --git a/crates/brk_computer/src/internal/transform/ratio32_neg.rs b/crates/brk_computer/src/internal/transform/ratio32_neg.rs new file mode 100644 index 000000000..5b294f749 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/ratio32_neg.rs @@ -0,0 +1,13 @@ +use brk_types::{Dollars, StoredF32}; +use vecdb::BinaryTransform; + +/// (Dollars, Dollars) -> -StoredF32 (negated ratio) +/// Computes -(a/b) directly to avoid lazy-from-lazy chains. +pub struct NegRatio32; + +impl BinaryTransform for NegRatio32 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { + -StoredF32::from(numerator / denominator) + } +} diff --git a/crates/brk_computer/src/internal/transform/ratio_f32.rs b/crates/brk_computer/src/internal/transform/ratio_f32.rs new file mode 100644 index 000000000..20610df51 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/ratio_f32.rs @@ -0,0 +1,16 @@ +use brk_types::StoredF32; +use vecdb::BinaryTransform; + +/// (StoredF32, StoredF32) -> StoredF32 ratio (a / b) +pub struct RatioF32; + +impl BinaryTransform for RatioF32 { + #[inline(always)] + fn apply(a: StoredF32, b: StoredF32) -> StoredF32 { + if *b == 0.0 { + StoredF32::from(0.0) + } else { + StoredF32::from(*a / *b) + } + } +} diff --git a/crates/brk_computer/src/internal/transform/return_f32_tenths.rs b/crates/brk_computer/src/internal/transform/return_f32_tenths.rs new file mode 100644 index 000000000..521b2c432 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/return_f32_tenths.rs @@ -0,0 +1,12 @@ +use brk_types::StoredF32; +use vecdb::UnaryTransform; + +/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input. +pub struct ReturnF32Tenths; + +impl UnaryTransform for ReturnF32Tenths { + #[inline(always)] + fn apply(_: S) -> StoredF32 { + StoredF32::from(V as f32 / 10.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/return_i16.rs b/crates/brk_computer/src/internal/transform/return_i16.rs new file mode 100644 index 000000000..8122dfa7d --- /dev/null +++ b/crates/brk_computer/src/internal/transform/return_i16.rs @@ -0,0 +1,12 @@ +use brk_types::StoredI16; +use vecdb::UnaryTransform; + +/// Returns a constant i16 value, ignoring the input. +pub struct ReturnI16; + +impl UnaryTransform for ReturnI16 { + #[inline(always)] + fn apply(_: S) -> StoredI16 { + StoredI16::new(V) + } +} diff --git a/crates/brk_computer/src/internal/transform/return_u16.rs b/crates/brk_computer/src/internal/transform/return_u16.rs new file mode 100644 index 000000000..d9fa8d642 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/return_u16.rs @@ -0,0 +1,12 @@ +use brk_types::StoredU16; +use vecdb::UnaryTransform; + +/// Returns a constant u16 value, ignoring the input. +pub struct ReturnU16; + +impl UnaryTransform for ReturnU16 { + #[inline(always)] + fn apply(_: S) -> StoredU16 { + StoredU16::new(V) + } +} diff --git a/crates/brk_computer/src/internal/transform/rsi_formula.rs b/crates/brk_computer/src/internal/transform/rsi_formula.rs new file mode 100644 index 000000000..53f551350 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/rsi_formula.rs @@ -0,0 +1,17 @@ +use brk_types::StoredF32; +use vecdb::BinaryTransform; + +/// (StoredF32, StoredF32) -> StoredF32 RSI formula: 100 * a / (a + b) +pub struct RsiFormula; + +impl BinaryTransform for RsiFormula { + #[inline(always)] + fn apply(average_gain: StoredF32, average_loss: StoredF32) -> StoredF32 { + let sum = *average_gain + *average_loss; + if sum == 0.0 { + StoredF32::from(50.0) + } else { + StoredF32::from(100.0 * *average_gain / sum) + } + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_halve.rs b/crates/brk_computer/src/internal/transform/sat_halve.rs new file mode 100644 index 000000000..2c4bb889c --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_halve.rs @@ -0,0 +1,12 @@ +use brk_types::Sats; +use vecdb::UnaryTransform; + +/// Sats -> Sats/2 (for supply_half) +pub struct HalveSats; + +impl UnaryTransform for HalveSats { + #[inline(always)] + fn apply(sats: Sats) -> Sats { + sats / 2 + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_halve_to_bitcoin.rs b/crates/brk_computer/src/internal/transform/sat_halve_to_bitcoin.rs new file mode 100644 index 000000000..0438a6741 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_halve_to_bitcoin.rs @@ -0,0 +1,13 @@ +use brk_types::{Bitcoin, Sats}; +use vecdb::UnaryTransform; + +/// Sats -> Bitcoin/2 (halve then convert to bitcoin) +/// Avoids lazy-from-lazy by combining both transforms +pub struct HalveSatsToBitcoin; + +impl UnaryTransform for HalveSatsToBitcoin { + #[inline(always)] + fn apply(sats: Sats) -> Bitcoin { + Bitcoin::from(sats / 2) + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_identity.rs b/crates/brk_computer/src/internal/transform/sat_identity.rs new file mode 100644 index 000000000..92e642337 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_identity.rs @@ -0,0 +1,12 @@ +use brk_types::Sats; +use vecdb::UnaryTransform; + +/// Sats -> Sats (identity transform for lazy references) +pub struct SatsIdentity; + +impl UnaryTransform for SatsIdentity { + #[inline(always)] + fn apply(sats: Sats) -> Sats { + sats + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_mask.rs b/crates/brk_computer/src/internal/transform/sat_mask.rs new file mode 100644 index 000000000..7c27155ae --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_mask.rs @@ -0,0 +1,17 @@ +use brk_types::{Sats, StoredU32}; +use vecdb::BinaryTransform; + +/// (StoredU32, Sats) -> Sats mask +/// Returns value if mask == 1, else 0. Used for pool fee/subsidy from chain data. +pub struct MaskSats; + +impl BinaryTransform for MaskSats { + #[inline(always)] + fn apply(mask: StoredU32, value: Sats) -> Sats { + if mask == StoredU32::ONE { + value + } else { + Sats::ZERO + } + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_plus.rs b/crates/brk_computer/src/internal/transform/sat_plus.rs new file mode 100644 index 000000000..11d41a5af --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_plus.rs @@ -0,0 +1,13 @@ +use brk_types::Sats; +use vecdb::BinaryTransform; + +/// (Sats, Sats) -> Sats addition +/// Used for computing coinbase = subsidy + fee +pub struct SatsPlus; + +impl BinaryTransform for SatsPlus { + #[inline(always)] + fn apply(lhs: Sats, rhs: Sats) -> Sats { + lhs + rhs + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_plus_to_bitcoin.rs b/crates/brk_computer/src/internal/transform/sat_plus_to_bitcoin.rs new file mode 100644 index 000000000..7ea0f43ed --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_plus_to_bitcoin.rs @@ -0,0 +1,13 @@ +use brk_types::{Bitcoin, Sats}; +use vecdb::BinaryTransform; + +/// (Sats, Sats) -> Bitcoin addition with conversion +/// Used for computing coinbase_btc = (subsidy + fee) / 1e8 +pub struct SatsPlusToBitcoin; + +impl BinaryTransform for SatsPlusToBitcoin { + #[inline(always)] + fn apply(lhs: Sats, rhs: Sats) -> Bitcoin { + Bitcoin::from(lhs + rhs) + } +} diff --git a/crates/brk_computer/src/internal/transform/sat_to_bitcoin.rs b/crates/brk_computer/src/internal/transform/sat_to_bitcoin.rs new file mode 100644 index 000000000..f3cfe4bb7 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/sat_to_bitcoin.rs @@ -0,0 +1,12 @@ +use brk_types::{Bitcoin, Sats}; +use vecdb::UnaryTransform; + +/// Sats -> Bitcoin (divide by 1e8) +pub struct SatsToBitcoin; + +impl UnaryTransform for SatsToBitcoin { + #[inline(always)] + fn apply(sats: Sats) -> Bitcoin { + Bitcoin::from(sats) + } +} diff --git a/crates/brk_computer/src/internal/transform/u16_to_years.rs b/crates/brk_computer/src/internal/transform/u16_to_years.rs new file mode 100644 index 000000000..22f878882 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/u16_to_years.rs @@ -0,0 +1,12 @@ +use brk_types::{StoredF32, StoredU16}; +use vecdb::UnaryTransform; + +/// StoredU16 / 365.0 -> StoredF32 (days to years conversion) +pub struct StoredU16ToYears; + +impl UnaryTransform for StoredU16ToYears { + #[inline(always)] + fn apply(v: StoredU16) -> StoredF32 { + StoredF32::from(*v as f64 / 365.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/volatility_sqrt30.rs b/crates/brk_computer/src/internal/transform/volatility_sqrt30.rs new file mode 100644 index 000000000..fd43dfda6 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/volatility_sqrt30.rs @@ -0,0 +1,12 @@ +use brk_types::StoredF32; +use vecdb::UnaryTransform; + +/// StoredF32 × sqrt(30) -> StoredF32 (1-month volatility from daily SD) +pub struct StoredF32TimesSqrt30; + +impl UnaryTransform for StoredF32TimesSqrt30 { + #[inline(always)] + fn apply(v: StoredF32) -> StoredF32 { + (*v * 30.0_f32.sqrt()).into() + } +} diff --git a/crates/brk_computer/src/internal/transform/volatility_sqrt365.rs b/crates/brk_computer/src/internal/transform/volatility_sqrt365.rs new file mode 100644 index 000000000..97dd940f3 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/volatility_sqrt365.rs @@ -0,0 +1,12 @@ +use brk_types::StoredF32; +use vecdb::UnaryTransform; + +/// StoredF32 × sqrt(365) -> StoredF32 (1-year volatility from daily SD) +pub struct StoredF32TimesSqrt365; + +impl UnaryTransform for StoredF32TimesSqrt365 { + #[inline(always)] + fn apply(v: StoredF32) -> StoredF32 { + (*v * 365.0_f32.sqrt()).into() + } +} diff --git a/crates/brk_computer/src/internal/transform/volatility_sqrt7.rs b/crates/brk_computer/src/internal/transform/volatility_sqrt7.rs new file mode 100644 index 000000000..83af6f972 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/volatility_sqrt7.rs @@ -0,0 +1,12 @@ +use brk_types::StoredF32; +use vecdb::UnaryTransform; + +/// StoredF32 × sqrt(7) -> StoredF32 (1-week volatility from daily SD) +pub struct StoredF32TimesSqrt7; + +impl UnaryTransform for StoredF32TimesSqrt7 { + #[inline(always)] + fn apply(v: StoredF32) -> StoredF32 { + (*v * 7.0_f32.sqrt()).into() + } +} diff --git a/crates/brk_computer/src/internal/transform/weight_to_fullness.rs b/crates/brk_computer/src/internal/transform/weight_to_fullness.rs new file mode 100644 index 000000000..6812bc253 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/weight_to_fullness.rs @@ -0,0 +1,13 @@ +use brk_types::{StoredF32, Weight}; +use vecdb::UnaryTransform; + +/// Weight -> StoredF32 percentage (weight / MAX_BLOCK × 100) +/// Used for computing block fullness as a percentage of max capacity +pub struct WeightToFullness; + +impl UnaryTransform for WeightToFullness { + #[inline(always)] + fn apply(weight: Weight) -> StoredF32 { + StoredF32::from(weight.fullness()) + } +} diff --git a/crates/brk_computer/src/internal/transforms.rs b/crates/brk_computer/src/internal/transforms.rs deleted file mode 100644 index e4fea9135..000000000 --- a/crates/brk_computer/src/internal/transforms.rs +++ /dev/null @@ -1,432 +0,0 @@ -use brk_types::{Bitcoin, Close, Dollars, Sats, StoredF32, StoredF64, StoredU32, StoredU64, Weight}; -use vecdb::{BinaryTransform, UnaryTransform}; - -/// (Dollars, Dollars) -> Dollars addition -/// Used for computing total = profit + loss -pub struct DollarsPlus; - -impl BinaryTransform for DollarsPlus { - #[inline(always)] - fn apply(lhs: Dollars, rhs: Dollars) -> Dollars { - lhs + rhs - } -} - -pub struct DollarsMinus; - -impl BinaryTransform for DollarsMinus { - #[inline(always)] - fn apply(lhs: Dollars, rhs: Dollars) -> Dollars { - lhs - rhs - } -} - -/// (Sats, Sats) -> Sats addition -/// Used for computing coinbase = subsidy + fee -pub struct SatsPlus; - -impl BinaryTransform for SatsPlus { - #[inline(always)] - fn apply(lhs: Sats, rhs: Sats) -> Sats { - lhs + rhs - } -} - -/// (Sats, Sats) -> Bitcoin addition with conversion -/// Used for computing coinbase_btc = (subsidy + fee) / 1e8 -pub struct SatsPlusToBitcoin; - -impl BinaryTransform for SatsPlusToBitcoin { - #[inline(always)] - fn apply(lhs: Sats, rhs: Sats) -> Bitcoin { - Bitcoin::from(lhs + rhs) - } -} - -/// (StoredU32, Sats) -> Sats mask -/// Returns value if mask == 1, else 0. Used for pool fee/subsidy from chain data. -pub struct MaskSats; - -impl BinaryTransform for MaskSats { - #[inline(always)] - fn apply(mask: StoredU32, value: Sats) -> Sats { - if mask == StoredU32::ONE { - value - } else { - Sats::ZERO - } - } -} - -/// (Dollars, Dollars) -> StoredF32 ratio -/// Used for computing percentage ratios like profit/total, loss/total, etc. -pub struct Ratio32; - -impl BinaryTransform for Ratio32 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { - StoredF32::from(numerator / denominator) - } -} - -/// (Dollars, Dollars) -> -StoredF32 (negated ratio) -/// Computes -(a/b) directly to avoid lazy-from-lazy chains. -pub struct NegRatio32; - -impl BinaryTransform for NegRatio32 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { - -StoredF32::from(numerator / denominator) - } -} - -// === Unary Transforms === - -/// Sats -> Bitcoin (divide by 1e8) -pub struct SatsToBitcoin; - -impl UnaryTransform for SatsToBitcoin { - #[inline(always)] - fn apply(sats: Sats) -> Bitcoin { - Bitcoin::from(sats) - } -} - -/// Sats -> Sats/2 (for supply_half) -pub struct HalveSats; - -impl UnaryTransform for HalveSats { - #[inline(always)] - fn apply(sats: Sats) -> Sats { - sats / 2 - } -} - -/// Sats -> Bitcoin/2 (halve then convert to bitcoin) -/// Avoids lazy-from-lazy by combining both transforms -pub struct HalveSatsToBitcoin; - -impl UnaryTransform for HalveSatsToBitcoin { - #[inline(always)] - fn apply(sats: Sats) -> Bitcoin { - Bitcoin::from(sats / 2) - } -} - -/// Dollars -> Dollars/2 (for supply_half_usd) -pub struct HalveDollars; - -impl UnaryTransform for HalveDollars { - #[inline(always)] - fn apply(dollars: Dollars) -> Dollars { - dollars.halved() - } -} - -/// Sats -> Sats (identity transform for lazy references) -pub struct SatsIdentity; - -impl UnaryTransform for SatsIdentity { - #[inline(always)] - fn apply(sats: Sats) -> Sats { - sats - } -} - -/// Dollars -> Dollars (identity transform for lazy references) -pub struct DollarsIdentity; - -impl UnaryTransform for DollarsIdentity { - #[inline(always)] - fn apply(dollars: Dollars) -> Dollars { - dollars - } -} - -/// StoredF32 -> StoredF32 (identity transform for lazy references/proxies) -pub struct StoredF32Identity; - -impl UnaryTransform for StoredF32Identity { - #[inline(always)] - fn apply(v: StoredF32) -> StoredF32 { - v - } -} - -/// Dollars * StoredF32 -> Dollars (price × ratio) -pub struct PriceTimesRatio; - -impl BinaryTransform for PriceTimesRatio { - #[inline(always)] - fn apply(price: Dollars, ratio: StoredF32) -> Dollars { - price * ratio - } -} - -/// Close * StoredF32 -> Dollars (price × ratio) -/// Same as PriceTimesRatio but accepts Close price source. -pub struct ClosePriceTimesRatio; - -impl BinaryTransform, StoredF32, Dollars> for ClosePriceTimesRatio { - #[inline(always)] - fn apply(price: Close, ratio: StoredF32) -> Dollars { - *price * ratio - } -} - -/// Close * Sats -> Dollars (price × sats / 1e8) -/// Same as PriceTimesSats but accepts Close price source. -pub struct ClosePriceTimesSats; - -impl BinaryTransform, Sats, Dollars> for ClosePriceTimesSats { - #[inline(always)] - fn apply(price: Close, sats: Sats) -> Dollars { - *price * Bitcoin::from(sats) - } -} - -/// Close * Sats -> Dollars/2 (price × sats / 1e8 / 2) -/// Computes halved dollars directly from sats, avoiding lazy-from-lazy chains. -pub struct HalfClosePriceTimesSats; - -impl BinaryTransform, Sats, Dollars> for HalfClosePriceTimesSats { - #[inline(always)] - fn apply(price: Close, sats: Sats) -> Dollars { - (*price * Bitcoin::from(sats)).halved() - } -} - -// === Constant Transforms (using const generics) === - -use brk_types::{StoredI16, StoredU16}; - -/// Returns a constant u16 value, ignoring the input. -pub struct ReturnU16; - -impl UnaryTransform for ReturnU16 { - #[inline(always)] - fn apply(_: S) -> StoredU16 { - StoredU16::new(V) - } -} - -/// Returns a constant i16 value, ignoring the input. -pub struct ReturnI16; - -impl UnaryTransform for ReturnI16 { - #[inline(always)] - fn apply(_: S) -> StoredI16 { - StoredI16::new(V) - } -} - -/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input. -pub struct ReturnF32Tenths; - -impl UnaryTransform for ReturnF32Tenths { - #[inline(always)] - fn apply(_: S) -> StoredF32 { - StoredF32::from(V as f32 / 10.0) - } -} - -/// Dollars * (V/10) -> Dollars (e.g., V=8 -> * 0.8, V=24 -> * 2.4) -pub struct DollarsTimesTenths; - -impl UnaryTransform for DollarsTimesTenths { - #[inline(always)] - fn apply(d: Dollars) -> Dollars { - d * (V as f64 / 10.0) - } -} - -// === Percentage Transforms (a/b × 100) === - -/// (Bitcoin, Bitcoin) -> StoredF64 percentage (a/b × 100) -/// Used for supply ratio calculations like supply_in_profit / total_supply × 100 -pub struct PercentageBtcF64; - -impl BinaryTransform for PercentageBtcF64 { - #[inline(always)] - fn apply(numerator: Bitcoin, denominator: Bitcoin) -> StoredF64 { - // Bitcoin / Bitcoin returns StoredF64, so dereference and multiply - StoredF64::from(*(numerator / denominator) * 100.0) - } -} - -/// (Dollars, Dollars) -> StoredF32 percentage (a/b × 100) -/// Used for unrealized/realized ratio calculations -pub struct PercentageDollarsF32; - -impl BinaryTransform for PercentageDollarsF32 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { - // Dollars / Dollars returns StoredF64, so dereference and multiply - StoredF32::from(*(numerator / denominator) * 100.0) - } -} - -/// (Dollars, Dollars) -> StoredF32 negated percentage (-(a/b × 100)) -/// Used for negated loss ratio calculations, avoiding lazy-from-lazy chains. -pub struct NegPercentageDollarsF32; - -impl BinaryTransform for NegPercentageDollarsF32 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { - // Dollars / Dollars returns StoredF64, so dereference and multiply - StoredF32::from(-(*(numerator / denominator) * 100.0)) - } -} - -/// (Sats, Sats) -> StoredF64 percentage (a/b × 100) -/// Used for supply ratio calculations (equivalent to Bitcoin/Bitcoin since 1e8 cancels) -pub struct PercentageSatsF64; - -impl BinaryTransform for PercentageSatsF64 { - #[inline(always)] - fn apply(numerator: Sats, denominator: Sats) -> StoredF64 { - StoredF64::from((*numerator as f64 / *denominator as f64) * 100.0) - } -} - -/// (StoredU32, StoredU32) -> StoredF32 percentage (a/b × 100) -/// Used for pool dominance calculations (pool_blocks / total_blocks × 100) -pub struct PercentageU32F32; - -impl BinaryTransform for PercentageU32F32 { - #[inline(always)] - fn apply(numerator: StoredU32, denominator: StoredU32) -> StoredF32 { - StoredF32::from((*numerator as f64 / *denominator as f64) * 100.0) - } -} - -/// (StoredU64, StoredU64) -> StoredF32 percentage (a/b × 100) -/// Used for adoption ratio calculations (type_count / total_count × 100) -pub struct PercentageU64F32; - -impl BinaryTransform for PercentageU64F32 { - #[inline(always)] - fn apply(numerator: StoredU64, denominator: StoredU64) -> StoredF32 { - if *denominator == 0 { - StoredF32::default() - } else { - StoredF32::from((*numerator as f64 / *denominator as f64) * 100.0) - } - } -} - -// === Volatility Transforms (SD × sqrt(N)) === - -/// StoredF32 × sqrt(7) -> StoredF32 (1-week volatility from daily SD) -pub struct StoredF32TimesSqrt7; - -impl UnaryTransform for StoredF32TimesSqrt7 { - #[inline(always)] - fn apply(v: StoredF32) -> StoredF32 { - (*v * 7.0_f32.sqrt()).into() - } -} - -/// StoredF32 × sqrt(30) -> StoredF32 (1-month volatility from daily SD) -pub struct StoredF32TimesSqrt30; - -impl UnaryTransform for StoredF32TimesSqrt30 { - #[inline(always)] - fn apply(v: StoredF32) -> StoredF32 { - (*v * 30.0_f32.sqrt()).into() - } -} - -/// StoredF32 × sqrt(365) -> StoredF32 (1-year volatility from daily SD) -pub struct StoredF32TimesSqrt365; - -impl UnaryTransform for StoredF32TimesSqrt365 { - #[inline(always)] - fn apply(v: StoredF32) -> StoredF32 { - (*v * 365.0_f32.sqrt()).into() - } -} - -/// StoredU16 / 365.0 -> StoredF32 (days to years conversion) -pub struct StoredU16ToYears; - -impl UnaryTransform for StoredU16ToYears { - #[inline(always)] - fn apply(v: StoredU16) -> StoredF32 { - StoredF32::from(*v as f64 / 365.0) - } -} - -// === Percentage Difference Transforms === - -/// (Close, Dollars) -> StoredF32 percentage difference ((a/b - 1) × 100) -/// Used for DCA returns: (price / dca_avg_price - 1) × 100 -/// Also used for drawdown: (close / ath - 1) × 100 (note: drawdown is typically negative) -pub struct PercentageDiffCloseDollars; - -impl BinaryTransform, Dollars, StoredF32> for PercentageDiffCloseDollars { - #[inline(always)] - fn apply(close: Close, base: Dollars) -> StoredF32 { - if base == Dollars::ZERO { - StoredF32::default() - } else { - StoredF32::from((**close / *base - 1.0) * 100.0) - } - } -} - -// === Block Fullness Transform === - -/// Weight -> StoredF32 percentage (weight / MAX_BLOCK × 100) -/// Used for computing block fullness as a percentage of max capacity -pub struct WeightToFullness; - -impl UnaryTransform for WeightToFullness { - #[inline(always)] - fn apply(weight: Weight) -> StoredF32 { - StoredF32::from(weight.fullness()) - } -} - -// === RSI Transform === - -/// (StoredF32, StoredF32) -> StoredF32 RSI formula: 100 * a / (a + b) -pub struct RsiFormula; - -impl BinaryTransform for RsiFormula { - #[inline(always)] - fn apply(avg_gain: StoredF32, avg_loss: StoredF32) -> StoredF32 { - let sum = *avg_gain + *avg_loss; - if sum == 0.0 { - StoredF32::from(50.0) - } else { - StoredF32::from(100.0 * *avg_gain / sum) - } - } -} - -// === MACD Transform === - -/// (StoredF32, StoredF32) -> StoredF32 difference (a - b) -pub struct DifferenceF32; - -impl BinaryTransform for DifferenceF32 { - #[inline(always)] - fn apply(a: StoredF32, b: StoredF32) -> StoredF32 { - StoredF32::from(*a - *b) - } -} - -/// (StoredF32, StoredF32) -> StoredF32 ratio (a / b) -pub struct RatioF32; - -impl BinaryTransform for RatioF32 { - #[inline(always)] - fn apply(a: StoredF32, b: StoredF32) -> StoredF32 { - if *b == 0.0 { - StoredF32::from(0.0) - } else { - StoredF32::from(*a / *b) - } - } -} diff --git a/crates/brk_computer/src/internal/value/computed/from_dateindex.rs b/crates/brk_computer/src/internal/value/computed/from_dateindex.rs deleted file mode 100644 index 0cac537ef..000000000 --- a/crates/brk_computer/src/internal/value/computed/from_dateindex.rs +++ /dev/null @@ -1,126 +0,0 @@ -use brk_error::Result; -use brk_traversable::Traversable; -use brk_types::{Bitcoin, DateIndex, Dollars, Sats, Version}; -use vecdb::{CollectableVec, Database, EagerVec, Exit, IterableCloneableVec, PcoVec}; - -use crate::{ - ComputeIndexes, - internal::{ComputedVecsFromDateIndex, LazyVecsFromDateIndex, SatsToBitcoin}, - indexes, price, - traits::ComputeFromBitcoin, - utils::OptionExt, -}; - -use crate::internal::{Source, VecBuilderOptions}; - -#[derive(Clone, Traversable)] -pub struct ComputedValueVecsFromDateIndex { - pub sats: ComputedVecsFromDateIndex, - pub bitcoin: LazyVecsFromDateIndex, - pub dollars: Option>, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedValueVecsFromDateIndex { - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - db: &Database, - name: &str, - source: Source, - version: Version, - options: VecBuilderOptions, - compute_dollars: bool, - indexes: &indexes::Vecs, - ) -> Result { - let sats = ComputedVecsFromDateIndex::forced_import( - db, - name, - source.clone(), - version + VERSION, - indexes, - options, - )?; - - let sats_source = source.vec().or(sats.dateindex.as_ref().map(|v| v.boxed_clone())); - - let bitcoin = LazyVecsFromDateIndex::from_computed::( - &format!("{name}_btc"), - version + VERSION, - sats_source, - &sats, - ); - - Ok(Self { - sats, - bitcoin, - dollars: compute_dollars.then(|| { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("{name}_usd"), - Source::Compute, - version + VERSION, - indexes, - options, - ) - .unwrap() - }), - }) - } - - pub fn compute_all( - &mut self, - price: Option<&price::Vecs>, - starting_indexes: &ComputeIndexes, - exit: &Exit, - mut compute: F, - ) -> Result<()> - where - F: FnMut(&mut EagerVec>) -> Result<()>, - { - compute(self.sats.dateindex.um())?; - - let dateindex: Option<&PcoVec> = None; - self.compute_rest(price, starting_indexes, exit, dateindex)?; - - Ok(()) - } - - pub fn compute_rest( - &mut self, - price: Option<&price::Vecs>, - starting_indexes: &ComputeIndexes, - exit: &Exit, - dateindex: Option<&impl CollectableVec>, - ) -> Result<()> { - if let Some(dateindex) = dateindex { - self.sats - .compute_rest(starting_indexes, exit, Some(dateindex))?; - } else { - let dateindex: Option<&PcoVec> = None; - self.sats.compute_rest(starting_indexes, exit, dateindex)?; - } - - let dateindex_to_bitcoin = self.bitcoin.dateindex.u(); - let dateindex_to_price_close = price - .u() - .usd - .timeindexes_to_price_close - .dateindex - .as_ref() - .unwrap(); - - if let Some(dollars) = self.dollars.as_mut() { - dollars.compute_all(starting_indexes, exit, |v| { - v.compute_from_bitcoin( - starting_indexes.dateindex, - dateindex_to_bitcoin, - dateindex_to_price_close, - exit, - ) - })?; - } - - Ok(()) - } -} diff --git a/crates/brk_computer/src/internal/value/computed/from_height.rs b/crates/brk_computer/src/internal/value/computed/from_height.rs deleted file mode 100644 index 0dd5aac49..000000000 --- a/crates/brk_computer/src/internal/value/computed/from_height.rs +++ /dev/null @@ -1,125 +0,0 @@ -use brk_error::Result; -use brk_traversable::Traversable; -use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; -use vecdb::{CollectableVec, Database, EagerVec, Exit, IterableCloneableVec, PcoVec}; - -use crate::{ - ComputeIndexes, - internal::{LazyVecsFromHeight, SatsToBitcoin, Source}, - indexes, price, - traits::ComputeFromBitcoin, - utils::OptionExt, -}; - -use crate::internal::{ComputedVecsFromHeight, VecBuilderOptions}; - -#[derive(Clone, Traversable)] -pub struct ComputedValueVecsFromHeight { - pub sats: ComputedVecsFromHeight, - pub bitcoin: LazyVecsFromHeight, - pub dollars: Option>, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedValueVecsFromHeight { - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - db: &Database, - name: &str, - source: Source, - version: Version, - options: VecBuilderOptions, - compute_dollars: bool, - indexes: &indexes::Vecs, - ) -> Result { - let sats = ComputedVecsFromHeight::forced_import( - db, - name, - source.clone(), - version + VERSION, - indexes, - options, - )?; - - let sats_source = source - .vec() - .unwrap_or_else(|| sats.height.as_ref().unwrap().boxed_clone()); - - let bitcoin = LazyVecsFromHeight::from_computed::( - &format!("{name}_btc"), - version + VERSION, - sats_source, - &sats, - ); - - Ok(Self { - sats, - bitcoin, - dollars: compute_dollars.then(|| { - ComputedVecsFromHeight::forced_import( - db, - &format!("{name}_usd"), - Source::Compute, - version + VERSION, - indexes, - options, - ) - .unwrap() - }), - }) - } - - pub fn compute_all( - &mut self, - indexes: &indexes::Vecs, - price: Option<&price::Vecs>, - starting_indexes: &ComputeIndexes, - exit: &Exit, - mut compute: F, - ) -> Result<()> - where - F: FnMut(&mut EagerVec>) -> Result<()>, - { - compute(self.sats.height.um())?; - - let height: Option<&PcoVec> = None; - self.compute_rest(indexes, price, starting_indexes, exit, height)?; - - Ok(()) - } - - pub fn compute_rest( - &mut self, - indexes: &indexes::Vecs, - price: Option<&price::Vecs>, - starting_indexes: &ComputeIndexes, - exit: &Exit, - height: Option<&impl CollectableVec>, - ) -> Result<()> { - if let Some(height) = height { - self.sats - .compute_rest(indexes, starting_indexes, exit, Some(height))?; - } else { - let height: Option<&PcoVec> = None; - self.sats - .compute_rest(indexes, starting_indexes, exit, height)?; - } - - let height_to_bitcoin = &self.bitcoin.height; - let height_to_price_close = &price.u().usd.chainindexes_to_price_close.height; - - if let Some(dollars) = self.dollars.as_mut() { - dollars.compute_all(indexes, starting_indexes, exit, |v| { - v.compute_from_bitcoin( - starting_indexes.height, - height_to_bitcoin, - height_to_price_close, - exit, - ) - })?; - } - - Ok(()) - } -} diff --git a/crates/brk_computer/src/internal/value/computed/from_txindex.rs b/crates/brk_computer/src/internal/value/computed/from_txindex.rs deleted file mode 100644 index 47abfa32a..000000000 --- a/crates/brk_computer/src/internal/value/computed/from_txindex.rs +++ /dev/null @@ -1,160 +0,0 @@ -use brk_error::Result; -use brk_indexer::Indexer; -use brk_traversable::Traversable; -use brk_types::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version}; -use vecdb::{ - CollectableVec, Database, Exit, IterableCloneableVec, LazyVecFrom1, LazyVecFrom3, PcoVec, - VecIndex, -}; - -use crate::{ComputeIndexes, internal::Source, indexes, price, utils::OptionExt}; - -use crate::internal::{ComputedVecsFromTxindex, VecBuilderOptions}; - -#[derive(Clone, Traversable)] -pub struct ComputedValueVecsFromTxindex { - pub sats: ComputedVecsFromTxindex, - pub bitcoin_txindex: LazyVecFrom1, - pub bitcoin: ComputedVecsFromTxindex, - // Derives directly from sats source (Eager) to avoid Lazy <- Lazy - #[allow(clippy::type_complexity)] - pub dollars_txindex: Option< - LazyVecFrom3>, - >, - pub dollars: Option>, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedValueVecsFromTxindex { - #[allow(clippy::too_many_arguments)] - pub fn forced_import( - db: &Database, - name: &str, - indexer: &Indexer, - indexes: &indexes::Vecs, - source: Source, - version: Version, - price: Option<&price::Vecs>, - options: VecBuilderOptions, - ) -> Result { - let name_btc = format!("{name}_btc"); - let name_usd = format!("{name}_usd"); - - let sats = ComputedVecsFromTxindex::forced_import( - db, - name, - source.clone(), - version + VERSION, - indexes, - options, - )?; - - // Compute sats source once - used by both bitcoin_txindex and dollars_txindex - let sats_source = source - .vec() - .unwrap_or_else(|| sats.txindex.u().boxed_clone()); - - let bitcoin_txindex = LazyVecFrom1::init( - &name_btc, - version + VERSION, - sats_source.clone(), - |txindex: TxIndex, iter| iter.get_at(txindex.to_usize()).map(Bitcoin::from), - ); - - let bitcoin = ComputedVecsFromTxindex::forced_import( - db, - &name_btc, - Source::Vec(bitcoin_txindex.boxed_clone()), - version + VERSION, - indexes, - options, - )?; - - // Derive directly from sats source (Eager) to avoid Lazy <- Lazy - let dollars_txindex = price.map(|price| { - LazyVecFrom3::init( - &name_usd, - version + VERSION, - sats_source.clone(), - indexer.vecs.tx.txindex_to_height.boxed_clone(), - price.usd.chainindexes_to_price_close.height.boxed_clone(), - |txindex: TxIndex, - txindex_to_sats_iter, - txindex_to_height_iter, - height_to_price_close_iter| { - let txindex = txindex.to_usize(); - txindex_to_sats_iter.get_at(txindex).and_then(|sats| { - txindex_to_height_iter.get_at(txindex).and_then(|height| { - height_to_price_close_iter - .get_at(height.to_usize()) - .map(|close| *close * Bitcoin::from(sats)) - }) - }) - }, - ) - }); - - Ok(Self { - sats, - bitcoin_txindex, - bitcoin, - dollars: dollars_txindex.as_ref().map(|dtx| { - ComputedVecsFromTxindex::forced_import( - db, - &name_usd, - Source::Vec(dtx.boxed_clone()), - version + VERSION, - indexes, - options, - ) - .unwrap() - }), - dollars_txindex, - }) - } - - pub fn compute_rest( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &ComputeIndexes, - exit: &Exit, - txindex: Option<&impl CollectableVec>, - price: Option<&price::Vecs>, - ) -> Result<()> { - if let Some(txindex) = txindex { - self.sats - .compute_rest(indexer, indexes, starting_indexes, exit, Some(txindex))?; - } else { - let txindex: Option<&PcoVec> = None; - self.sats - .compute_rest(indexer, indexes, starting_indexes, exit, txindex)?; - } - - self.bitcoin.compute_rest_from_sats( - indexer, - indexes, - starting_indexes, - exit, - &self.sats, - Some(&self.bitcoin_txindex), - )?; - - if let Some(dollars) = self.dollars.as_mut() { - let dollars_txindex = self.dollars_txindex.um(); - - dollars.compute_rest_from_bitcoin( - indexer, - indexes, - starting_indexes, - exit, - &self.bitcoin, - Some(dollars_txindex), - price.u(), - )?; - } - - Ok(()) - } -} diff --git a/crates/brk_computer/src/internal/value/computed/mod.rs b/crates/brk_computer/src/internal/value/computed/mod.rs deleted file mode 100644 index 79c974b7f..000000000 --- a/crates/brk_computer/src/internal/value/computed/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod from_dateindex; -mod from_height; -mod from_txindex; - -pub use from_dateindex::*; -pub use from_height::*; -pub use from_txindex::*; diff --git a/crates/brk_computer/src/internal/value/lazy/binary_from_height.rs b/crates/brk_computer/src/internal/value/lazy/binary_from_height.rs deleted file mode 100644 index fe2bc9115..000000000 --- a/crates/brk_computer/src/internal/value/lazy/binary_from_height.rs +++ /dev/null @@ -1,69 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; -use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec}; - -use crate::internal::{ComputedValueVecsFromHeight, LazyVecsFrom2FromHeight}; - -/// Lazy value vecs computed from two `ComputedValueVecsFromHeight` sources via binary transforms. -/// Used for computing coinbase = subsidy + fee. -#[derive(Clone, Traversable)] -pub struct LazyValueVecsFrom2FromHeight { - pub sats: LazyVecsFrom2FromHeight, - pub bitcoin: LazyVecsFrom2FromHeight, - pub dollars: Option>, -} - -impl LazyValueVecsFrom2FromHeight { - pub fn from_computed( - name: &str, - version: Version, - height_source1: IterableBoxedVec, - height_source2: IterableBoxedVec, - source1: &ComputedValueVecsFromHeight, - source2: &ComputedValueVecsFromHeight, - ) -> Self - where - SatsF: BinaryTransform, - BitcoinF: BinaryTransform, - DollarsF: BinaryTransform, - { - let sats = LazyVecsFrom2FromHeight::from_computed::( - name, - version, - height_source1.boxed_clone(), - height_source2.boxed_clone(), - &source1.sats, - &source2.sats, - ); - - let bitcoin = LazyVecsFrom2FromHeight::from_computed::( - &format!("{name}_btc"), - version, - height_source1, - height_source2, - &source1.sats, - &source2.sats, - ); - - let dollars = source1 - .dollars - .as_ref() - .zip(source2.dollars.as_ref()) - .map(|(d1, d2)| { - LazyVecsFrom2FromHeight::from_computed::( - &format!("{name}_usd"), - version, - d1.height.as_ref().unwrap().boxed_clone(), - d2.height.as_ref().unwrap().boxed_clone(), - d1, - d2, - ) - }); - - Self { - sats, - bitcoin, - dollars, - } - } -} diff --git a/crates/brk_computer/src/internal/value/lazy/from_dateindex.rs b/crates/brk_computer/src/internal/value/lazy/from_dateindex.rs deleted file mode 100644 index 3bc2d5dd1..000000000 --- a/crates/brk_computer/src/internal/value/lazy/from_dateindex.rs +++ /dev/null @@ -1,65 +0,0 @@ -use brk_traversable::Traversable; -use brk_types::{Bitcoin, Dollars, Sats, Version}; -use vecdb::{IterableCloneableVec, UnaryTransform}; - -use crate::internal::{ComputedValueVecsFromDateIndex, LazyVecsFromDateIndex}; - -const VERSION: Version = Version::ZERO; - -/// Fully lazy version of `ComputedValueVecsFromDateIndex` where all fields are lazy transforms. -/// Used for computed values like supply_half where sources are stored sats and dollars vecs. -#[derive(Clone, Traversable)] -pub struct LazyValueVecsFromDateIndex { - pub sats: LazyVecsFromDateIndex, - pub bitcoin: LazyVecsFromDateIndex, - pub dollars: Option>, -} - -impl LazyValueVecsFromDateIndex { - /// Create lazy dateindex value vecs from source vecs via transforms. - /// - /// - `SatsTransform`: Transform from Sats -> Sats (e.g., HalveSats) - /// - `BitcoinTransform`: Transform from Sats -> Bitcoin (e.g., HalveSatsToBitcoin) - /// - `DollarsTransform`: Transform from Dollars -> Dollars (e.g., HalveDollars) - pub fn from_source( - name: &str, - source: &ComputedValueVecsFromDateIndex, - version: Version, - ) -> Self - where - SatsTransform: UnaryTransform, - BitcoinTransform: UnaryTransform, - DollarsTransform: UnaryTransform, - { - let v = version + VERSION; - - let sats = LazyVecsFromDateIndex::from_computed::( - name, - v, - source.sats.dateindex.as_ref().map(|v| v.boxed_clone()), - &source.sats, - ); - - let bitcoin = LazyVecsFromDateIndex::from_computed::( - &format!("{name}_btc"), - v, - source.sats.dateindex.as_ref().map(|v| v.boxed_clone()), - &source.sats, - ); - - let dollars = source.dollars.as_ref().map(|dollars_source| { - LazyVecsFromDateIndex::from_computed::( - &format!("{name}_usd"), - v, - dollars_source.dateindex.as_ref().map(|v| v.boxed_clone()), - dollars_source, - ) - }); - - Self { - sats, - bitcoin, - dollars, - } - } -} diff --git a/crates/brk_computer/src/internal/value/lazy/mod.rs b/crates/brk_computer/src/internal/value/lazy/mod.rs deleted file mode 100644 index c0f27556a..000000000 --- a/crates/brk_computer/src/internal/value/lazy/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod binary_from_height; -mod from_dateindex; -mod height; -mod value_height; - -pub use binary_from_height::*; -pub use from_dateindex::*; -pub use height::*; -pub use value_height::*; diff --git a/crates/brk_computer/src/internal/value/lazy/value_height.rs b/crates/brk_computer/src/internal/value/lazy/value_height.rs deleted file mode 100644 index 0f452a971..000000000 --- a/crates/brk_computer/src/internal/value/lazy/value_height.rs +++ /dev/null @@ -1,57 +0,0 @@ -use brk_error::Result; -use brk_traversable::Traversable; -use brk_types::{Bitcoin, Close, Dollars, Height, Sats, Version}; -use vecdb::{ - Database, EagerVec, ImportableVec, IterableBoxedVec, IterableCloneableVec, LazyVecFrom1, - LazyVecFrom2, PcoVec, -}; - -use crate::internal::{ClosePriceTimesSats, SatsToBitcoin, Source}; - -#[derive(Clone, Traversable)] -pub struct ComputedHeightValueVecs { - pub sats: Option>>, - pub bitcoin: LazyVecFrom1, - pub dollars: Option, Height, Sats>>, -} - -const VERSION: Version = Version::ZERO; - -impl ComputedHeightValueVecs { - pub fn forced_import( - db: &Database, - name: &str, - source: Source, - version: Version, - price_source: Option>>, - ) -> Result { - let sats = source - .is_compute() - .then(|| EagerVec::forced_import(db, name, version + VERSION).unwrap()); - - let sats_source: IterableBoxedVec = source - .vec() - .unwrap_or_else(|| sats.as_ref().unwrap().boxed_clone()); - - let bitcoin = LazyVecFrom1::transformed::( - &format!("{name}_btc"), - version + VERSION, - sats_source.clone(), - ); - - let dollars = price_source.map(|price| { - LazyVecFrom2::transformed::( - &format!("{name}_usd"), - version + VERSION, - price, - sats_source.clone(), - ) - }); - - Ok(Self { - sats, - bitcoin, - dollars, - }) - } -} diff --git a/crates/brk_computer/src/internal/vec/average.rs b/crates/brk_computer/src/internal/vec/average.rs new file mode 100644 index 000000000..5ea94aad3 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/average.rs @@ -0,0 +1,26 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// Average value in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct AverageVec(pub EagerVec>); + +impl AverageVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import( + db, + &format!("{name}_average"), + version, + )?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/cumulative.rs b/crates/brk_computer/src/internal/vec/cumulative.rs new file mode 100644 index 000000000..f7ef16b43 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/cumulative.rs @@ -0,0 +1,25 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// Cumulative sum across aggregation periods +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "cumulative")] +pub struct CumulativeVec( + pub EagerVec>, +); + +impl CumulativeVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_cumulative"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/last.rs b/crates/brk_computer/src/internal/vec/last.rs new file mode 100644 index 000000000..aabf4a20d --- /dev/null +++ b/crates/brk_computer/src/internal/vec/last.rs @@ -0,0 +1,74 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{CheckedSub, StoredU64}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, GenericStoredVec, ImportableVec, IterableVec, PcoVec, VecIndex, VecValue, Version}; + +use crate::internal::ComputedVecValue; + +/// Last value in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct LastVec( + pub EagerVec>, +); + +impl LastVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, name, version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } + + /// Compute last values from a source vec. + /// + /// For each output index I, takes the last value from the corresponding + /// range in the source vec (indexed by A). + pub fn compute_last( + &mut self, + max_from: I, + source: &impl IterableVec, + first_indexes: &impl IterableVec, + count_indexes: &impl IterableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecIndex + VecValue + CheckedSub, + { + self.0.validate_computed_version_or_reset( + source.version() + first_indexes.version() + count_indexes.version(), + )?; + + let index = max_from.min(I::from(self.0.len())); + + let mut source_iter = source.iter(); + let mut count_indexes_iter = count_indexes.iter().skip(index.to_usize()); + + first_indexes + .iter() + .enumerate() + .skip(index.to_usize()) + .try_for_each(|(i, first_index)| -> Result<()> { + let count_index = count_indexes_iter.next().unwrap(); + let count = *count_index as usize; + + if count == 0 { + panic!("should not compute last if count can be 0"); + } + + let last_index = first_index + (count - 1); + let v = source_iter.get_unwrap(last_index); + self.0.truncate_push_at(i, v)?; + + Ok(()) + })?; + + let _lock = exit.lock(); + self.0.write()?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/vec/max.rs b/crates/brk_computer/src/internal/vec/max.rs new file mode 100644 index 000000000..7505e690c --- /dev/null +++ b/crates/brk_computer/src/internal/vec/max.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// Maximum value in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct MaxVec( + pub EagerVec>, +); + +impl MaxVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_max"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/median.rs b/crates/brk_computer/src/internal/vec/median.rs new file mode 100644 index 000000000..51ab50881 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/median.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// Median (50th percentile) in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct MedianVec( + pub EagerVec>, +); + +impl MedianVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_median"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/min.rs b/crates/brk_computer/src/internal/vec/min.rs new file mode 100644 index 000000000..8499455f3 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/min.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// Minimum value in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct MinVec( + pub EagerVec>, +); + +impl MinVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_min"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/mod.rs b/crates/brk_computer/src/internal/vec/mod.rs new file mode 100644 index 000000000..f1fbfcf97 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/mod.rs @@ -0,0 +1,23 @@ +mod average; +mod cumulative; +mod last; +mod max; +mod median; +mod min; +mod pct10; +mod pct25; +mod pct75; +mod pct90; +mod sum; + +pub use average::*; +pub use cumulative::*; +pub use last::*; +pub use max::*; +pub use median::*; +pub use min::*; +pub use pct10::*; +pub use pct25::*; +pub use pct75::*; +pub use pct90::*; +pub use sum::*; diff --git a/crates/brk_computer/src/internal/vec/pct10.rs b/crates/brk_computer/src/internal/vec/pct10.rs new file mode 100644 index 000000000..65d099ead --- /dev/null +++ b/crates/brk_computer/src/internal/vec/pct10.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// 10th percentile in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct Pct10Vec( + pub EagerVec>, +); + +impl Pct10Vec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_pct10"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/pct25.rs b/crates/brk_computer/src/internal/vec/pct25.rs new file mode 100644 index 000000000..0ca26d48b --- /dev/null +++ b/crates/brk_computer/src/internal/vec/pct25.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// 25th percentile in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct Pct25Vec( + pub EagerVec>, +); + +impl Pct25Vec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_pct25"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/pct75.rs b/crates/brk_computer/src/internal/vec/pct75.rs new file mode 100644 index 000000000..26e957b54 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/pct75.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// 75th percentile in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct Pct75Vec( + pub EagerVec>, +); + +impl Pct75Vec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_pct75"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/pct90.rs b/crates/brk_computer/src/internal/vec/pct90.rs new file mode 100644 index 000000000..25e15ef11 --- /dev/null +++ b/crates/brk_computer/src/internal/vec/pct90.rs @@ -0,0 +1,24 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// 90th percentile in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +pub struct Pct90Vec( + pub EagerVec>, +); + +impl Pct90Vec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_pct90"), version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/internal/vec/sum.rs b/crates/brk_computer/src/internal/vec/sum.rs new file mode 100644 index 000000000..32c8bcf6a --- /dev/null +++ b/crates/brk_computer/src/internal/vec/sum.rs @@ -0,0 +1,30 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, ImportableVec, PcoVec, VecIndex, Version}; + +use crate::internal::ComputedVecValue; + +/// Sum of values in an aggregation period +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(wrap = "sum")] +pub struct SumVec( + pub EagerVec>, +); + +impl SumVec { + pub fn forced_import(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, &format!("{name}_sum"), version)?)) + } + + /// Import with raw name (no suffix) for backwards compat + pub fn forced_import_raw(db: &Database, name: &str, version: Version) -> Result { + Ok(Self(EagerVec::forced_import(db, name, version)?)) + } + + #[inline] + pub fn inner(&self) -> &EagerVec> { + &self.0 + } +} diff --git a/crates/brk_computer/src/lib.rs b/crates/brk_computer/src/lib.rs index 39e66afdf..2fefce45d 100644 --- a/crates/brk_computer/src/lib.rs +++ b/crates/brk_computer/src/lib.rs @@ -12,21 +12,21 @@ use log::info; use vecdb::Exit; mod blocks; -mod transactions; -mod scripts; -mod positions; mod cointime; mod constants; -mod internal; -mod indexes; -mod market; -mod pools; -mod price; mod distribution; +mod indexes; +mod inputs; +mod internal; +mod market; +mod outputs; +mod pools; +mod positions; +mod price; +mod scripts; mod supply; mod traits; -mod inputs; -mod outputs; +mod transactions; mod utils; use indexes::ComputeIndexes; @@ -68,8 +68,9 @@ impl Computer { let i = Instant::now(); let (indexes, positions) = thread::scope(|s| -> Result<_> { - let positions_handle = big_thread() - .spawn_scoped(s, || positions::Vecs::forced_import(&computed_path, VERSION))?; + let positions_handle = big_thread().spawn_scoped(s, || { + positions::Vecs::forced_import(&computed_path, VERSION) + })?; let indexes = indexes::Vecs::forced_import(&computed_path, VERSION, indexer)?; let positions = positions_handle.join().unwrap()?; @@ -129,7 +130,13 @@ impl Computer { // Import scripts module (depends on outputs for adoption ratio denominators) let scripts_handle = big_thread().spawn_scoped(s, || { - scripts::Vecs::forced_import(&computed_path, VERSION, &indexes, price.as_ref(), &outputs) + scripts::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + price.as_ref(), + &outputs, + ) })?; let cointime = @@ -151,7 +158,10 @@ impl Computer { Ok((blocks, transactions, scripts, pools, cointime)) })?; - info!("Imported blocks/transactions/scripts/pools/cointime in {:?}", i.elapsed()); + info!( + "Imported blocks/transactions/scripts/pools/cointime in {:?}", + i.elapsed() + ); // Threads inside let i = Instant::now(); @@ -267,7 +277,9 @@ impl Computer { info!("Computing indexes..."); let i = Instant::now(); - let mut starting_indexes = self.indexes.compute(indexer, &self.blocks.time, starting_indexes, exit)?; + let mut starting_indexes = + self.indexes + .compute(indexer, &self.blocks.time, starting_indexes, exit)?; info!("Computed indexes in {:?}", i.elapsed()); if let Some(price) = self.price.as_mut() { @@ -302,8 +314,13 @@ impl Computer { // Scripts (needed for outputs.count.utxo_count) info!("Computing scripts..."); let i = Instant::now(); - self.scripts - .compute(indexer, &self.indexes, self.price.as_ref(), &starting_indexes, exit)?; + self.scripts.compute( + indexer, + &self.indexes, + self.price.as_ref(), + &starting_indexes, + exit, + )?; info!("Computed scripts in {:?}", i.elapsed()); // Outputs depends on inputs and scripts (for utxo_count) @@ -346,13 +363,6 @@ impl Computer { )?; info!("Computed blocks in {:?}", i.elapsed()); - if let Some(price) = self.price.as_ref() { - info!("Computing market..."); - let i = Instant::now(); - self.market.compute(price, &self.blocks, &self.distribution, &starting_indexes, exit)?; - info!("Computed market in {:?}", i.elapsed()); - } - positions.join().unwrap()?; Ok(()) })?; @@ -366,7 +376,6 @@ impl Computer { indexer, &self.indexes, &starting_indexes_clone, - self.price.as_ref(), exit, )?; info!("Computed pools in {:?}", i.elapsed()); @@ -392,6 +401,20 @@ impl Computer { Ok(()) })?; + // Market must be computed after distribution (uses distribution data for gini) + if let Some(price) = self.price.as_ref() { + info!("Computing market..."); + let i = Instant::now(); + self.market.compute( + price, + &self.blocks, + &self.distribution, + &starting_indexes, + exit, + )?; + info!("Computed market in {:?}", i.elapsed()); + } + // Supply must be computed after distribution (uses actual circulating supply) info!("Computing supply..."); let i = Instant::now(); @@ -431,7 +454,11 @@ impl Computer { use brk_traversable::Traversable; std::iter::empty() - .chain(self.blocks.iter_any_exportable().map(|v| (blocks::DB_NAME, v))) + .chain( + self.blocks + .iter_any_exportable() + .map(|v| (blocks::DB_NAME, v)), + ) .chain( self.transactions .iter_any_exportable() @@ -442,7 +469,11 @@ impl Computer { .iter_any_exportable() .map(|v| (scripts::DB_NAME, v)), ) - .chain(self.positions.iter_any_exportable().map(|v| (positions::DB_NAME, v))) + .chain( + self.positions + .iter_any_exportable() + .map(|v| (positions::DB_NAME, v)), + ) .chain( self.cointime .iter_any_exportable() @@ -495,36 +526,3 @@ impl Computer { ) } } - -// pub fn generate_allocation_files(monitored: &pools::Vecs) -> Result<()> { -// info!("Generating allocative files..."); - -// let mut flamegraph = allocative::FlameGraphBuilder::default(); -// flamegraph.visit_root(monitored); -// let output = flamegraph.finish(); - -// let folder = format!( -// "at-{}", -// jiff::Timestamp::now().strftime("%Y-%m-%d_%Hh%Mm%Ss"), -// ); - -// let path = std::path::PathBuf::from(&format!("./target/flamegraph/{folder}")); -// std::fs::create_dir_all(&path)?; - -// // fs::write(path.join("flamegraph.src"), &output.flamegraph())?; - -// let mut fg_svg = Vec::new(); -// inferno::flamegraph::from_reader( -// &mut inferno::flamegraph::Options::default(), -// output.flamegraph().write().as_bytes(), -// &mut fg_svg, -// )?; - -// std::fs::write(path.join("flamegraph.svg"), &fg_svg)?; - -// std::fs::write(path.join("warnings.txt"), output.warnings())?; - -// info!("Successfully generate allocative files"); - -// Ok(()) -// } diff --git a/crates/brk_computer/src/market/ath/compute.rs b/crates/brk_computer/src/market/ath/compute.rs index 0013cb6e9..eb04d2b66 100644 --- a/crates/brk_computer/src/market/ath/compute.rs +++ b/crates/brk_computer/src/market/ath/compute.rs @@ -3,7 +3,7 @@ use brk_types::StoredU16; use vecdb::{Exit, GenericStoredVec, TypedVecIterator, VecIndex}; use super::Vecs; -use crate::{ComputeIndexes, price, traits::ComputeDrawdown, utils::OptionExt}; +use crate::{ComputeIndexes, price, traits::ComputeDrawdown}; impl Vecs { pub fn compute( @@ -25,23 +25,21 @@ impl Vecs { exit, )?; - self.indexes_to_price_ath - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_price_ath.compute_all(starting_indexes, exit, |v| { v.compute_all_time_high( starting_indexes.dateindex, - price.usd.timeindexes_to_price_high.dateindex.u(), + &price.usd.timeindexes_to_price_high.dateindex, exit, )?; Ok(()) })?; - self.indexes_to_days_since_price_ath - .compute_all(starting_indexes, exit, |v| { - let mut high_iter = price.usd.timeindexes_to_price_high.dateindex.u().into_iter(); + self.indexes_to_days_since_price_ath.compute_all(starting_indexes, exit, |v| { + let mut high_iter = price.usd.timeindexes_to_price_high.dateindex.into_iter(); let mut prev = None; v.compute_transform( starting_indexes.dateindex, - self.indexes_to_price_ath.dateindex.u(), + &self.indexes_to_price_ath.dateindex, |(i, ath, slf)| { if prev.is_none() { let i = i.to_usize(); @@ -64,12 +62,11 @@ impl Vecs { Ok(()) })?; - self.indexes_to_max_days_between_price_aths - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_max_days_between_price_aths.compute_all(starting_indexes, exit, |v| { let mut prev = None; v.compute_transform( starting_indexes.dateindex, - self.indexes_to_days_since_price_ath.dateindex.u(), + &self.indexes_to_days_since_price_ath.dateindex, |(i, days, slf)| { if prev.is_none() { let i = i.to_usize(); diff --git a/crates/brk_computer/src/market/ath/import.rs b/crates/brk_computer/src/market/ath/import.rs index 8d31ef23c..1bef9478d 100644 --- a/crates/brk_computer/src/market/ath/import.rs +++ b/crates/brk_computer/src/market/ath/import.rs @@ -6,8 +6,8 @@ use super::Vecs; use crate::{ indexes, internal::{ - ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, LazyVecsFromDateIndex, - PercentageDiffCloseDollars, Source, StoredU16ToYears, VecBuilderOptions, + BinaryDateLast, ComputedDateLast, LazyDateLast, PercentageDiffCloseDollars, + StoredU16ToYears, }, price, }; @@ -19,59 +19,33 @@ impl Vecs { indexes: &indexes::Vecs, price: &price::Vecs, ) -> Result { - let last = VecBuilderOptions::default().add_last(); + let indexes_to_price_ath = + ComputedDateLast::forced_import(db, "price_ath", version, indexes)?; - let indexes_to_price_ath = ComputedVecsFromDateIndex::forced_import( - db, - "price_ath", - Source::Compute, + let indexes_to_max_days_between_price_aths = + ComputedDateLast::forced_import(db, "max_days_between_price_aths", version, indexes)?; + + let indexes_to_max_years_between_price_aths = LazyDateLast::from_computed::( + "max_years_between_price_aths", version, - indexes, - last, - )?; + indexes_to_max_days_between_price_aths + .dateindex + .boxed_clone(), + &indexes_to_max_days_between_price_aths, + ); - let indexes_to_max_days_between_price_aths = ComputedVecsFromDateIndex::forced_import( - db, - "max_days_between_price_aths", - Source::Compute, + let indexes_to_days_since_price_ath = + ComputedDateLast::forced_import(db, "days_since_price_ath", version, indexes)?; + + let indexes_to_years_since_price_ath = LazyDateLast::from_computed::( + "years_since_price_ath", version, - indexes, - last, - )?; - - let indexes_to_max_years_between_price_aths = - LazyVecsFromDateIndex::from_computed::( - "max_years_between_price_aths", - version, - indexes_to_max_days_between_price_aths - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), - &indexes_to_max_days_between_price_aths, - ); - - let indexes_to_days_since_price_ath = ComputedVecsFromDateIndex::forced_import( - db, - "days_since_price_ath", - Source::Compute, - version, - indexes, - last, - )?; - - let indexes_to_years_since_price_ath = - LazyVecsFromDateIndex::from_computed::( - "years_since_price_ath", - version, - indexes_to_days_since_price_ath - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), - &indexes_to_days_since_price_ath, - ); + indexes_to_days_since_price_ath.dateindex.boxed_clone(), + &indexes_to_days_since_price_ath, + ); let indexes_to_price_drawdown = - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( "price_drawdown", version, &price.usd.timeindexes_to_price_close, diff --git a/crates/brk_computer/src/market/ath/vecs.rs b/crates/brk_computer/src/market/ath/vecs.rs index 47d3a7351..e6dc3a056 100644 --- a/crates/brk_computer/src/market/ath/vecs.rs +++ b/crates/brk_computer/src/market/ath/vecs.rs @@ -2,19 +2,18 @@ use brk_traversable::Traversable; use brk_types::{Close, Dollars, Height, StoredF32, StoredU16}; use vecdb::{EagerVec, PcoVec}; -use crate::internal::{ - ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, LazyVecsFromDateIndex, -}; +use crate::internal::{BinaryDateLast, ComputedDateLast, LazyDateLast}; /// All-time high related metrics #[derive(Clone, Traversable)] pub struct Vecs { pub height_to_price_ath: EagerVec>, pub height_to_price_drawdown: EagerVec>, - pub indexes_to_price_ath: ComputedVecsFromDateIndex, - pub indexes_to_price_drawdown: LazyVecsFrom2FromDateIndex, Dollars>, - pub indexes_to_days_since_price_ath: ComputedVecsFromDateIndex, - pub indexes_to_years_since_price_ath: LazyVecsFromDateIndex, - pub indexes_to_max_days_between_price_aths: ComputedVecsFromDateIndex, - pub indexes_to_max_years_between_price_aths: LazyVecsFromDateIndex, + pub indexes_to_price_ath: ComputedDateLast, + // KISS: both sources are ComputedVecsDateLast + pub indexes_to_price_drawdown: BinaryDateLast, Dollars>, + pub indexes_to_days_since_price_ath: ComputedDateLast, + pub indexes_to_years_since_price_ath: LazyDateLast, + pub indexes_to_max_days_between_price_aths: ComputedDateLast, + pub indexes_to_max_years_between_price_aths: LazyDateLast, } diff --git a/crates/brk_computer/src/market/dca/compute.rs b/crates/brk_computer/src/market/dca/compute.rs index fde31bb01..daaecaae9 100644 --- a/crates/brk_computer/src/market/dca/compute.rs +++ b/crates/brk_computer/src/market/dca/compute.rs @@ -3,11 +3,10 @@ use vecdb::Exit; use super::Vecs; use crate::{ + ComputeIndexes, market::lookback, price, traits::{ComputeDCAAveragePriceViaLen, ComputeDCAStackViaLen, ComputeLumpSumStackViaLen}, - utils::OptionExt, - ComputeIndexes, }; impl Vecs { @@ -18,25 +17,30 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - let close = price.usd.timeindexes_to_price_close.dateindex.u(); + let close = &price.usd.timeindexes_to_price_close.dateindex; // DCA by period - stack for (stack, days) in self.period_stack.iter_mut_with_days() { stack.compute_all(Some(price), starting_indexes, exit, |v| { - v.compute_dca_stack_via_len(starting_indexes.dateindex, close, days as usize, exit)?; + v.compute_dca_stack_via_len( + starting_indexes.dateindex, + close, + days as usize, + exit, + )?; Ok(()) })?; } - // DCA by period - avg_price (needs stack's dateindex) - for (avg_price, stack, days) in self - .period_avg_price + // DCA by period - average_price (needs stack's dateindex) + for (average_price, stack, days) in self + .period_average_price .zip_mut_with_days(&self.period_stack) { - avg_price.compute_all(starting_indexes, exit, |v| { - v.compute_dca_avg_price_via_len( + average_price.compute_all(starting_indexes, exit, |v| { + v.compute_dca_average_price_via_len( starting_indexes.dateindex, - stack.sats.dateindex.u(), + &stack.sats_dateindex, days as usize, exit, )?; @@ -45,14 +49,12 @@ impl Vecs { } // DCA by period - CAGR (computed from returns) - for (cagr, returns, days) in self - .period_cagr - .zip_mut_with_period(&self.period_returns) - { + for (cagr, returns, days) in self.period_cagr.zip_mut_with_period(&self.period_returns) { cagr.compute_all(starting_indexes, exit, |v| { + // KISS: dateindex is no longer Option v.compute_cagr( starting_indexes.dateindex, - returns.dateindex.u(), + &returns.dateindex, days as usize, exit, )?; @@ -62,15 +64,14 @@ impl Vecs { // Lump sum by period - stack (for comparison with DCA) let lookback_dca = lookback.price_ago.as_dca_period(); - for (stack, lookback_price, days) in self - .period_lump_sum_stack - .zip_mut_with_days(&lookback_dca) + for (stack, lookback_price, days) in + self.period_lump_sum_stack.zip_mut_with_days(&lookback_dca) { stack.compute_all(Some(price), starting_indexes, exit, |v| { v.compute_lump_sum_stack_via_len( starting_indexes.dateindex, close, - lookback_price.dateindex.u(), + &lookback_price.dateindex, days as usize, exit, )?; @@ -78,12 +79,12 @@ impl Vecs { })?; } - // DCA by year class - stack and avg_price + // DCA by year class - stack and average_price let dateindexes = super::ByDcaClass::<()>::dateindexes(); - for ((stack, avg_price), dateindex) in self + for ((stack, average_price), dateindex) in self .class_stack .iter_mut() - .zip(self.class_avg_price.iter_mut()) + .zip(self.class_average_price.iter_mut()) .zip(dateindexes) { stack.compute_all(Some(price), starting_indexes, exit, |v| { @@ -91,10 +92,10 @@ impl Vecs { Ok(()) })?; - avg_price.compute_all(starting_indexes, exit, |v| { - v.compute_dca_avg_price_via_from( + average_price.compute_all(starting_indexes, exit, |v| { + v.compute_dca_average_price_via_from( starting_indexes.dateindex, - stack.sats.dateindex.u(), + &stack.sats_dateindex, dateindex, exit, )?; diff --git a/crates/brk_computer/src/market/dca/import.rs b/crates/brk_computer/src/market/dca/import.rs index 26c4335ee..3a7bb6bd6 100644 --- a/crates/brk_computer/src/market/dca/import.rs +++ b/crates/brk_computer/src/market/dca/import.rs @@ -5,10 +5,7 @@ use vecdb::Database; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, DCA_CLASS_NAMES, DCA_PERIOD_NAMES, Vecs}; use crate::{ indexes, - internal::{ - ComputedValueVecsFromDateIndex, ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, - PercentageDiffCloseDollars, Source, VecBuilderOptions, - }, + internal::{BinaryDateLast, ComputedDateLast, PercentageDiffCloseDollars, ValueDateLast}, price, }; @@ -19,116 +16,81 @@ impl Vecs { indexes: &indexes::Vecs, price: &price::Vecs, ) -> Result { - let last = VecBuilderOptions::default().add_last(); - - // DCA by period - stack + // DCA by period - stack (KISS) let period_stack = ByDcaPeriod::try_new(|name, _days| { - ComputedValueVecsFromDateIndex::forced_import( + ValueDateLast::forced_import(db, &format!("{name}_dca_stack"), version, true, indexes) + })?; + + // DCA by period - average price + let period_average_price = ByDcaPeriod::try_new(|name, _days| { + ComputedDateLast::forced_import( db, - &format!("{name}_dca_stack"), - Source::Compute, + &format!("{name}_dca_average_price"), version, - last, - true, indexes, ) })?; - // DCA by period - avg price - let period_avg_price = ByDcaPeriod::try_new(|name, _days| { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("{name}_dca_avg_price"), - Source::Compute, - version, - indexes, - last, - ) - })?; - - // DCA by period - returns (lazy, derived from price and avg_price) + // KISS: DCA by period - returns (lazy, derived from price and average_price) let period_returns = DCA_PERIOD_NAMES - .zip_ref(&period_avg_price) - .map(|(name, avg_price)| { - LazyVecsFrom2FromDateIndex::from_computed::( + .zip_ref(&period_average_price) + .map(|(name, average_price)| { + BinaryDateLast::from_computed_both_last::( &format!("{name}_dca_returns"), version, &price.usd.timeindexes_to_price_close, - avg_price, + average_price, ) }); // DCA by period - CAGR let period_cagr = ByDcaCagr::try_new(|name, _days| { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("{name}_dca_cagr"), - Source::Compute, - version, - indexes, - last, - ) + ComputedDateLast::forced_import(db, &format!("{name}_dca_cagr"), version, indexes) })?; - // Lump sum by period - stack + // Lump sum by period - stack (KISS) let period_lump_sum_stack = ByDcaPeriod::try_new(|name, _days| { - ComputedValueVecsFromDateIndex::forced_import( + ValueDateLast::forced_import( db, &format!("{name}_lump_sum_stack"), - Source::Compute, version, - last, true, indexes, ) })?; - // DCA by year class - stack + // DCA by year class - stack (KISS) let class_stack = ByDcaClass::try_new(|name, _year, _dateindex| { - ComputedValueVecsFromDateIndex::forced_import( - db, - &format!("{name}_stack"), - Source::Compute, - version, - last, - true, - indexes, - ) + ValueDateLast::forced_import(db, &format!("{name}_stack"), version, true, indexes) })?; - // DCA by year class - avg price - let class_avg_price = ByDcaClass::try_new(|name, _year, _dateindex| { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("{name}_avg_price"), - Source::Compute, - version, - indexes, - last, - ) + // DCA by year class - average price + let class_average_price = ByDcaClass::try_new(|name, _year, _dateindex| { + ComputedDateLast::forced_import(db, &format!("{name}_average_price"), version, indexes) })?; - // DCA by year class - returns (lazy) - let class_returns = DCA_CLASS_NAMES - .zip_ref(&class_avg_price) - .map(|(name, avg_price)| { - LazyVecsFrom2FromDateIndex::from_computed::( - &format!("{name}_returns"), - version, - &price.usd.timeindexes_to_price_close, - avg_price, - ) - }); + // KISS: DCA by year class - returns (lazy) + let class_returns = + DCA_CLASS_NAMES + .zip_ref(&class_average_price) + .map(|(name, average_price)| { + BinaryDateLast::from_computed_both_last::( + &format!("{name}_returns"), + version, + &price.usd.timeindexes_to_price_close, + average_price, + ) + }); Ok(Self { period_stack, - period_avg_price, + period_average_price, period_returns, period_cagr, period_lump_sum_stack, class_stack, - class_avg_price, + class_average_price, class_returns, }) } diff --git a/crates/brk_computer/src/market/dca/vecs.rs b/crates/brk_computer/src/market/dca/vecs.rs index 1d5bda444..2c76a9bb8 100644 --- a/crates/brk_computer/src/market/dca/vecs.rs +++ b/crates/brk_computer/src/market/dca/vecs.rs @@ -2,24 +2,22 @@ use brk_traversable::Traversable; use brk_types::{Close, Dollars, StoredF32}; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod}; -use crate::internal::{ - ComputedValueVecsFromDateIndex, ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, -}; +use crate::internal::{BinaryDateLast, ComputedDateLast, ValueDateLast}; /// Dollar-cost averaging metrics by time period and year class #[derive(Clone, Traversable)] pub struct Vecs { - // DCA by period - pub period_stack: ByDcaPeriod, - pub period_avg_price: ByDcaPeriod>, - pub period_returns: ByDcaPeriod, Dollars>>, - pub period_cagr: ByDcaCagr>, + // DCA by period - KISS types + pub period_stack: ByDcaPeriod, + pub period_average_price: ByDcaPeriod>, + pub period_returns: ByDcaPeriod, Dollars>>, + pub period_cagr: ByDcaCagr>, - // Lump sum by period (for comparison with DCA) - pub period_lump_sum_stack: ByDcaPeriod, + // Lump sum by period (for comparison with DCA) - KISS types + pub period_lump_sum_stack: ByDcaPeriod, - // DCA by year class - pub class_stack: ByDcaClass, - pub class_avg_price: ByDcaClass>, - pub class_returns: ByDcaClass, Dollars>>, + // DCA by year class - KISS types + pub class_stack: ByDcaClass, + pub class_average_price: ByDcaClass>, + pub class_returns: ByDcaClass, Dollars>>, } diff --git a/crates/brk_computer/src/market/indicators/compute.rs b/crates/brk_computer/src/market/indicators/compute.rs index 94df09dda..a30e131cb 100644 --- a/crates/brk_computer/src/market/indicators/compute.rs +++ b/crates/brk_computer/src/market/indicators/compute.rs @@ -6,7 +6,7 @@ use super::{ super::{moving_average, range, returns::Vecs as ReturnsVecs}, Vecs, }; -use crate::{ComputeIndexes, blocks, distribution, price, utils::OptionExt}; +use crate::{ComputeIndexes, blocks, distribution, price}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -26,20 +26,22 @@ impl Vecs { rewards.indexes_to_subsidy_usd_1y_sma.as_ref(), rewards.indexes_to_coinbase.dollars.as_ref(), ) { - let date_to_coinbase_usd_sum = coinbase_dollars.dateindex.unwrap_sum(); + // KISS: dateindex.sum is now a concrete field + let date_to_coinbase_usd_sum = &coinbase_dollars.dateindex.sum_cum.sum.0; puell.compute_all(starting_indexes, exit, |v| { v.compute_divide( starting_indexes.dateindex, date_to_coinbase_usd_sum, - sma.dateindex.as_ref().unwrap(), + &sma.dateindex, exit, )?; Ok(()) })?; } - let returns_dateindex = returns.price_returns._1d.dateindex.u(); + // KISS: dateindex is no longer Option + let returns_dateindex = &returns.price_returns._1d.dateindex; self.dateindex_to_rsi_gains.compute_transform( starting_indexes.dateindex, @@ -55,32 +57,32 @@ impl Vecs { exit, )?; - self.dateindex_to_rsi_avg_gain_14d.compute_rma( + self.dateindex_to_rsi_average_gain_14d.compute_rma( starting_indexes.dateindex, &self.dateindex_to_rsi_gains, 14, exit, )?; - self.dateindex_to_rsi_avg_loss_14d.compute_rma( + self.dateindex_to_rsi_average_loss_14d.compute_rma( starting_indexes.dateindex, &self.dateindex_to_rsi_losses, 14, exit, )?; - let ema12 = moving_average + let ema12 = &moving_average .indexes_to_price_12d_ema .price - .u() - .dateindex - .u(); - let ema26 = moving_average + .as_ref() + .unwrap() + .dateindex; + let ema26 = &moving_average .indexes_to_price_26d_ema .price - .u() - .dateindex - .u(); + .as_ref() + .unwrap() + .dateindex; self.dateindex_to_macd_line.compute_transform2( starting_indexes.dateindex, @@ -144,11 +146,10 @@ impl Vecs { )?; // Stochastic Oscillator: K = (close - low_14) / (high_14 - low_14) * 100 - if let (Some(close), Some(low_2w), Some(high_2w)) = ( - price.usd.timeindexes_to_price_close.dateindex.as_ref(), - range.indexes_to_price_2w_min.dateindex.as_ref(), - range.indexes_to_price_2w_max.dateindex.as_ref(), - ) { + { + let close = &price.usd.timeindexes_to_price_close.dateindex; + let low_2w = &range.indexes_to_price_2w_min.dateindex; + let high_2w = &range.indexes_to_price_2w_max.dateindex; self.dateindex_to_stoch_k.compute_transform3( starting_indexes.dateindex, close, @@ -175,20 +176,14 @@ impl Vecs { } let amount_range = &distribution.utxo_cohorts.amount_range; + // KISS: dateindex is now always present (not Option) let supply_vecs: Vec<_> = amount_range .iter() - .filter_map(|c| c.metrics.supply.indexes_to_supply.sats.dateindex.as_ref()) + .map(|c| &c.metrics.supply.indexes_to_supply.sats_dateindex) .collect(); let count_vecs: Vec<_> = amount_range .iter() - .filter_map(|c| { - c.metrics - .supply - .indexes_to_utxo_count - .dateindex - .last - .as_ref() - }) + .map(|c| &c.metrics.supply.indexes_to_utxo_count.dateindex) .collect(); if let Some(first_supply) = supply_vecs.first() diff --git a/crates/brk_computer/src/market/indicators/import.rs b/crates/brk_computer/src/market/indicators/import.rs index 15c989747..212f3faf3 100644 --- a/crates/brk_computer/src/market/indicators/import.rs +++ b/crates/brk_computer/src/market/indicators/import.rs @@ -5,10 +5,7 @@ use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom use super::{super::moving_average, Vecs}; use crate::{ distribution, indexes, - internal::{ - ComputedVecsFromDateIndex, DifferenceF32, LazyVecsFrom2FromDateIndex, Ratio32, RsiFormula, - Source, VecBuilderOptions, - }, + internal::{BinaryDateLast, ComputedDateLast, DifferenceF32, Ratio32, RsiFormula}, transactions, }; @@ -25,8 +22,8 @@ impl Vecs { moving_average: &moving_average::Vecs, ) -> Result { let v = version + VERSION; - let last = || VecBuilderOptions::default().add_last(); + // NVT = Market Cap (KISS DateIndex) / Volume (Height) let indexes_to_nvt = distribution .utxo_cohorts .all @@ -37,26 +34,24 @@ impl Vecs { .as_ref() .zip(transactions.volume.indexes_to_sent_sum.dollars.as_ref()) .map(|(market_cap, volume)| { - LazyVecsFrom2FromDateIndex::from_dateindex_and_height::( - "nvt", - v, - market_cap, - volume, + // KISS: market_cap is ComputedVecsDateLast, volume is ComputedBlockSum + BinaryDateLast::from_dateindex_last_and_height_sum::( + "nvt", v, market_cap, volume, ) }); let dateindex_to_rsi_gains = EagerVec::forced_import(db, "rsi_gains", v)?; let dateindex_to_rsi_losses = EagerVec::forced_import(db, "rsi_losses", v)?; // v1: Changed from SMA to RMA (Wilder's smoothing) - let dateindex_to_rsi_avg_gain_14d = - EagerVec::forced_import(db, "rsi_avg_gain_14d", v + Version::ONE)?; - let dateindex_to_rsi_avg_loss_14d = - EagerVec::forced_import(db, "rsi_avg_loss_14d", v + Version::ONE)?; + let dateindex_to_rsi_average_gain_14d = + EagerVec::forced_import(db, "rsi_average_gain_14d", v + Version::ONE)?; + let dateindex_to_rsi_average_loss_14d = + EagerVec::forced_import(db, "rsi_average_loss_14d", v + Version::ONE)?; let dateindex_to_rsi_14d = LazyVecFrom2::transformed::( "rsi_14d", v, - dateindex_to_rsi_avg_gain_14d.boxed_clone(), - dateindex_to_rsi_avg_loss_14d.boxed_clone(), + dateindex_to_rsi_average_gain_14d.boxed_clone(), + dateindex_to_rsi_average_loss_14d.boxed_clone(), ); let dateindex_to_macd_line = EagerVec::forced_import(db, "macd_line", v)?; @@ -80,39 +75,32 @@ impl Vecs { let dateindex_to_gini = EagerVec::forced_import(db, "gini", v)?; // Pi Cycle Top: 111d SMA / (2 * 350d SMA) - signals top when > 1 - let dateindex_to_pi_cycle = moving_average - .indexes_to_price_111d_sma - .price - .as_ref() - .and_then(|sma_111| sma_111.dateindex.as_ref()) - .zip(moving_average.indexes_to_price_350d_sma_x2.dateindex.as_ref()) - .map(|(sma_111, sma_350_x2)| { - LazyVecFrom2::transformed::( - "pi_cycle", - v, - sma_111.boxed_clone(), - sma_350_x2.boxed_clone(), - ) - }); + let dateindex_to_pi_cycle = + moving_average + .indexes_to_price_111d_sma + .price + .as_ref() + .map(|sma_111| { + LazyVecFrom2::transformed::( + "pi_cycle", + v, + sma_111.dateindex.boxed_clone(), + moving_average + .indexes_to_price_350d_sma_x2 + .dateindex + .boxed_clone(), + ) + }); Ok(Self { indexes_to_puell_multiple: compute_dollars - .then(|| { - ComputedVecsFromDateIndex::forced_import( - db, - "puell_multiple", - Source::Compute, - v, - indexes, - last(), - ) - }) + .then(|| ComputedDateLast::forced_import(db, "puell_multiple", v, indexes)) .transpose()?, indexes_to_nvt, dateindex_to_rsi_gains, dateindex_to_rsi_losses, - dateindex_to_rsi_avg_gain_14d, - dateindex_to_rsi_avg_loss_14d, + dateindex_to_rsi_average_gain_14d, + dateindex_to_rsi_average_loss_14d, dateindex_to_rsi_14d, dateindex_to_rsi_14d_min, dateindex_to_rsi_14d_max, diff --git a/crates/brk_computer/src/market/indicators/vecs.rs b/crates/brk_computer/src/market/indicators/vecs.rs index 9dbb4c819..0f87aa2d4 100644 --- a/crates/brk_computer/src/market/indicators/vecs.rs +++ b/crates/brk_computer/src/market/indicators/vecs.rs @@ -2,18 +2,19 @@ use brk_traversable::Traversable; use brk_types::{DateIndex, Dollars, StoredF32}; use vecdb::{EagerVec, LazyVecFrom2, PcoVec}; -use crate::internal::{ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex}; +use crate::internal::{BinaryDateLast, ComputedDateLast}; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_puell_multiple: Option>, - pub indexes_to_nvt: Option>, + pub indexes_to_puell_multiple: Option>, + pub indexes_to_nvt: Option>, pub dateindex_to_rsi_gains: EagerVec>, pub dateindex_to_rsi_losses: EagerVec>, - pub dateindex_to_rsi_avg_gain_14d: EagerVec>, - pub dateindex_to_rsi_avg_loss_14d: EagerVec>, - pub dateindex_to_rsi_14d: LazyVecFrom2, + pub dateindex_to_rsi_average_gain_14d: EagerVec>, + pub dateindex_to_rsi_average_loss_14d: EagerVec>, + pub dateindex_to_rsi_14d: + LazyVecFrom2, pub dateindex_to_rsi_14d_min: EagerVec>, pub dateindex_to_rsi_14d_max: EagerVec>, @@ -24,11 +25,13 @@ pub struct Vecs { pub dateindex_to_stoch_k: EagerVec>, pub dateindex_to_stoch_d: EagerVec>, - pub dateindex_to_pi_cycle: Option>, + pub dateindex_to_pi_cycle: + Option>, pub dateindex_to_macd_line: EagerVec>, pub dateindex_to_macd_signal: EagerVec>, - pub dateindex_to_macd_histogram: LazyVecFrom2, + pub dateindex_to_macd_histogram: + LazyVecFrom2, pub dateindex_to_gini: EagerVec>, } diff --git a/crates/brk_computer/src/market/lookback/compute.rs b/crates/brk_computer/src/market/lookback/compute.rs index 21f9935f1..fec98bf1a 100644 --- a/crates/brk_computer/src/market/lookback/compute.rs +++ b/crates/brk_computer/src/market/lookback/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use vecdb::Exit; use super::Vecs; -use crate::{price, utils::OptionExt, ComputeIndexes}; +use crate::{price, ComputeIndexes}; impl Vecs { pub fn compute( @@ -11,7 +11,7 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - let close = price.usd.timeindexes_to_price_close.dateindex.u(); + let close = &price.usd.timeindexes_to_price_close.dateindex; for (price_ago, days) in self.price_ago.iter_mut_with_days() { price_ago.compute_all(starting_indexes, exit, |v| { diff --git a/crates/brk_computer/src/market/lookback/import.rs b/crates/brk_computer/src/market/lookback/import.rs index dab87c4b0..ef331f486 100644 --- a/crates/brk_computer/src/market/lookback/import.rs +++ b/crates/brk_computer/src/market/lookback/import.rs @@ -3,24 +3,12 @@ use brk_types::Version; use vecdb::Database; use super::{ByLookbackPeriod, Vecs}; -use crate::{ - indexes, - internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedDateLast}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let last = VecBuilderOptions::default().add_last(); - let price_ago = ByLookbackPeriod::try_new(|name, _days| { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("price_{name}_ago"), - Source::Compute, - version, - indexes, - last, - ) + ComputedDateLast::forced_import(db, &format!("price_{name}_ago"), version, indexes) })?; Ok(Self { price_ago }) diff --git a/crates/brk_computer/src/market/lookback/vecs.rs b/crates/brk_computer/src/market/lookback/vecs.rs index f5dafb3c1..fa0724e33 100644 --- a/crates/brk_computer/src/market/lookback/vecs.rs +++ b/crates/brk_computer/src/market/lookback/vecs.rs @@ -2,10 +2,10 @@ use brk_traversable::Traversable; use brk_types::Dollars; use super::ByLookbackPeriod; -use crate::internal::ComputedVecsFromDateIndex; +use crate::internal::ComputedDateLast; /// Price lookback metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub price_ago: ByLookbackPeriod>, + pub price_ago: ByLookbackPeriod>, } diff --git a/crates/brk_computer/src/market/moving_average/compute.rs b/crates/brk_computer/src/market/moving_average/compute.rs index d4d96b3c8..38e043113 100644 --- a/crates/brk_computer/src/market/moving_average/compute.rs +++ b/crates/brk_computer/src/market/moving_average/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use vecdb::Exit; use super::Vecs; -use crate::{price, utils::OptionExt, ComputeIndexes}; +use crate::{price, ComputeIndexes}; impl Vecs { pub fn compute( @@ -11,7 +11,7 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - let close = price.usd.timeindexes_to_price_close.dateindex.u(); + let close = &price.usd.timeindexes_to_price_close.dateindex; for (sma, period) in [ (&mut self.indexes_to_price_1w_sma, 7), diff --git a/crates/brk_computer/src/market/moving_average/import.rs b/crates/brk_computer/src/market/moving_average/import.rs index cf19ebb62..16c47dae2 100644 --- a/crates/brk_computer/src/market/moving_average/import.rs +++ b/crates/brk_computer/src/market/moving_average/import.rs @@ -1,11 +1,11 @@ use brk_error::Result; use brk_types::Version; -use vecdb::{Database, IterableCloneableVec}; +use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedRatioVecsFromDateIndex, DollarsTimesTenths, LazyVecsFromDateIndex}, + internal::{ComputedRatioVecsDate, DollarsTimesTenths, LazyDateLast}, price, }; @@ -16,7 +16,7 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, ) -> Result { - let indexes_to_price_1w_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_1w_sma = ComputedRatioVecsDate::forced_import( db, "price_1w_sma", None, @@ -25,7 +25,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_8d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_8d_sma = ComputedRatioVecsDate::forced_import( db, "price_8d_sma", None, @@ -34,7 +34,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_13d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_13d_sma = ComputedRatioVecsDate::forced_import( db, "price_13d_sma", None, @@ -43,7 +43,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_21d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_21d_sma = ComputedRatioVecsDate::forced_import( db, "price_21d_sma", None, @@ -52,7 +52,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_1m_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_1m_sma = ComputedRatioVecsDate::forced_import( db, "price_1m_sma", None, @@ -61,7 +61,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_34d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_34d_sma = ComputedRatioVecsDate::forced_import( db, "price_34d_sma", None, @@ -70,7 +70,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_55d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_55d_sma = ComputedRatioVecsDate::forced_import( db, "price_55d_sma", None, @@ -79,7 +79,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_89d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_89d_sma = ComputedRatioVecsDate::forced_import( db, "price_89d_sma", None, @@ -88,7 +88,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_111d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_111d_sma = ComputedRatioVecsDate::forced_import( db, "price_111d_sma", None, @@ -97,7 +97,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_144d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_144d_sma = ComputedRatioVecsDate::forced_import( db, "price_144d_sma", None, @@ -106,7 +106,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_200d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_200d_sma = ComputedRatioVecsDate::forced_import( db, "price_200d_sma", None, @@ -115,7 +115,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_350d_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_350d_sma = ComputedRatioVecsDate::forced_import( db, "price_350d_sma", None, @@ -124,7 +124,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_1y_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_1y_sma = ComputedRatioVecsDate::forced_import( db, "price_1y_sma", None, @@ -133,7 +133,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_2y_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_2y_sma = ComputedRatioVecsDate::forced_import( db, "price_2y_sma", None, @@ -142,7 +142,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_200w_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_200w_sma = ComputedRatioVecsDate::forced_import( db, "price_200w_sma", None, @@ -151,7 +151,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_4y_sma = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_4y_sma = ComputedRatioVecsDate::forced_import( db, "price_4y_sma", None, @@ -161,7 +161,7 @@ impl Vecs { price, )?; - let indexes_to_price_1w_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_1w_ema = ComputedRatioVecsDate::forced_import( db, "price_1w_ema", None, @@ -170,7 +170,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_8d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_8d_ema = ComputedRatioVecsDate::forced_import( db, "price_8d_ema", None, @@ -179,7 +179,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_12d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_12d_ema = ComputedRatioVecsDate::forced_import( db, "price_12d_ema", None, @@ -188,7 +188,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_13d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_13d_ema = ComputedRatioVecsDate::forced_import( db, "price_13d_ema", None, @@ -197,7 +197,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_21d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_21d_ema = ComputedRatioVecsDate::forced_import( db, "price_21d_ema", None, @@ -206,7 +206,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_26d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_26d_ema = ComputedRatioVecsDate::forced_import( db, "price_26d_ema", None, @@ -215,7 +215,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_1m_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_1m_ema = ComputedRatioVecsDate::forced_import( db, "price_1m_ema", None, @@ -224,7 +224,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_34d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_34d_ema = ComputedRatioVecsDate::forced_import( db, "price_34d_ema", None, @@ -233,7 +233,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_55d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_55d_ema = ComputedRatioVecsDate::forced_import( db, "price_55d_ema", None, @@ -242,7 +242,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_89d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_89d_ema = ComputedRatioVecsDate::forced_import( db, "price_89d_ema", None, @@ -251,7 +251,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_144d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_144d_ema = ComputedRatioVecsDate::forced_import( db, "price_144d_ema", None, @@ -260,7 +260,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_200d_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_200d_ema = ComputedRatioVecsDate::forced_import( db, "price_200d_ema", None, @@ -269,7 +269,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_1y_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_1y_ema = ComputedRatioVecsDate::forced_import( db, "price_1y_ema", None, @@ -278,7 +278,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_2y_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_2y_ema = ComputedRatioVecsDate::forced_import( db, "price_2y_ema", None, @@ -287,7 +287,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_200w_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_200w_ema = ComputedRatioVecsDate::forced_import( db, "price_200w_ema", None, @@ -296,7 +296,7 @@ impl Vecs { true, price, )?; - let indexes_to_price_4y_ema = ComputedRatioVecsFromDateIndex::forced_import( + let indexes_to_price_4y_ema = ComputedRatioVecsDate::forced_import( db, "price_4y_ema", None, @@ -308,35 +308,23 @@ impl Vecs { let price_200d_sma_source = indexes_to_price_200d_sma.price.as_ref().unwrap(); let indexes_to_price_200d_sma_x2_4 = - LazyVecsFromDateIndex::from_computed::>( + LazyDateLast::from_source::>( "price_200d_sma_x2_4", version, - price_200d_sma_source - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), price_200d_sma_source, ); let indexes_to_price_200d_sma_x0_8 = - LazyVecsFromDateIndex::from_computed::>( + LazyDateLast::from_source::>( "price_200d_sma_x0_8", version, - price_200d_sma_source - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), price_200d_sma_source, ); let price_350d_sma_source = indexes_to_price_350d_sma.price.as_ref().unwrap(); let indexes_to_price_350d_sma_x2 = - LazyVecsFromDateIndex::from_computed::>( + LazyDateLast::from_source::>( "price_350d_sma_x2", version, - price_350d_sma_source - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), price_350d_sma_source, ); diff --git a/crates/brk_computer/src/market/moving_average/vecs.rs b/crates/brk_computer/src/market/moving_average/vecs.rs index e49232adf..67f94c2c6 100644 --- a/crates/brk_computer/src/market/moving_average/vecs.rs +++ b/crates/brk_computer/src/market/moving_average/vecs.rs @@ -1,46 +1,46 @@ use brk_traversable::Traversable; use brk_types::Dollars; -use crate::internal::{ComputedRatioVecsFromDateIndex, LazyVecsFromDateIndex}; +use crate::internal::{ComputedRatioVecsDate, LazyDateLast}; /// Simple and exponential moving average metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_price_1w_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_8d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_13d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_21d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1m_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_34d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_55d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_89d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_111d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_144d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_350d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1y_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_2y_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200w_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_4y_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_1w_sma: ComputedRatioVecsDate, + pub indexes_to_price_8d_sma: ComputedRatioVecsDate, + pub indexes_to_price_13d_sma: ComputedRatioVecsDate, + pub indexes_to_price_21d_sma: ComputedRatioVecsDate, + pub indexes_to_price_1m_sma: ComputedRatioVecsDate, + pub indexes_to_price_34d_sma: ComputedRatioVecsDate, + pub indexes_to_price_55d_sma: ComputedRatioVecsDate, + pub indexes_to_price_89d_sma: ComputedRatioVecsDate, + pub indexes_to_price_111d_sma: ComputedRatioVecsDate, + pub indexes_to_price_144d_sma: ComputedRatioVecsDate, + pub indexes_to_price_200d_sma: ComputedRatioVecsDate, + pub indexes_to_price_350d_sma: ComputedRatioVecsDate, + pub indexes_to_price_1y_sma: ComputedRatioVecsDate, + pub indexes_to_price_2y_sma: ComputedRatioVecsDate, + pub indexes_to_price_200w_sma: ComputedRatioVecsDate, + pub indexes_to_price_4y_sma: ComputedRatioVecsDate, - pub indexes_to_price_1w_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_8d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_12d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_13d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_21d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_26d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1m_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_34d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_55d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_89d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_144d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1y_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_2y_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200w_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_4y_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_1w_ema: ComputedRatioVecsDate, + pub indexes_to_price_8d_ema: ComputedRatioVecsDate, + pub indexes_to_price_12d_ema: ComputedRatioVecsDate, + pub indexes_to_price_13d_ema: ComputedRatioVecsDate, + pub indexes_to_price_21d_ema: ComputedRatioVecsDate, + pub indexes_to_price_26d_ema: ComputedRatioVecsDate, + pub indexes_to_price_1m_ema: ComputedRatioVecsDate, + pub indexes_to_price_34d_ema: ComputedRatioVecsDate, + pub indexes_to_price_55d_ema: ComputedRatioVecsDate, + pub indexes_to_price_89d_ema: ComputedRatioVecsDate, + pub indexes_to_price_144d_ema: ComputedRatioVecsDate, + pub indexes_to_price_200d_ema: ComputedRatioVecsDate, + pub indexes_to_price_1y_ema: ComputedRatioVecsDate, + pub indexes_to_price_2y_ema: ComputedRatioVecsDate, + pub indexes_to_price_200w_ema: ComputedRatioVecsDate, + pub indexes_to_price_4y_ema: ComputedRatioVecsDate, - pub indexes_to_price_200d_sma_x2_4: LazyVecsFromDateIndex, - pub indexes_to_price_200d_sma_x0_8: LazyVecsFromDateIndex, - pub indexes_to_price_350d_sma_x2: LazyVecsFromDateIndex, + pub indexes_to_price_200d_sma_x2_4: LazyDateLast, + pub indexes_to_price_200d_sma_x0_8: LazyDateLast, + pub indexes_to_price_350d_sma_x2: LazyDateLast, } diff --git a/crates/brk_computer/src/market/range/compute.rs b/crates/brk_computer/src/market/range/compute.rs index c8ffc4ad1..e1b124fc3 100644 --- a/crates/brk_computer/src/market/range/compute.rs +++ b/crates/brk_computer/src/market/range/compute.rs @@ -3,7 +3,7 @@ use brk_types::StoredF32; use vecdb::Exit; use super::Vecs; -use crate::{price, utils::OptionExt, ComputeIndexes}; +use crate::{price, ComputeIndexes}; impl Vecs { pub fn compute( @@ -12,57 +12,49 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - let open = price.usd.timeindexes_to_price_open.dateindex.u(); - let low = price.usd.timeindexes_to_price_low.dateindex.u(); - let high = price.usd.timeindexes_to_price_high.dateindex.u(); + let open = &price.usd.timeindexes_to_price_open.dateindex; + let low = &price.usd.timeindexes_to_price_low.dateindex; + let high = &price.usd.timeindexes_to_price_high.dateindex; - self.indexes_to_price_1w_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min(starting_indexes.dateindex, low, 7, exit)?; - Ok(()) - })?; + self.indexes_to_price_1w_min.compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 7, exit)?; + Ok(()) + })?; - self.indexes_to_price_1w_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max(starting_indexes.dateindex, high, 7, exit)?; - Ok(()) - })?; + self.indexes_to_price_1w_max.compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 7, exit)?; + Ok(()) + })?; - self.indexes_to_price_2w_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min(starting_indexes.dateindex, low, 14, exit)?; - Ok(()) - })?; + self.indexes_to_price_2w_min.compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 14, exit)?; + Ok(()) + })?; - self.indexes_to_price_2w_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max(starting_indexes.dateindex, high, 14, exit)?; - Ok(()) - })?; + self.indexes_to_price_2w_max.compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 14, exit)?; + Ok(()) + })?; - self.indexes_to_price_1m_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min(starting_indexes.dateindex, low, 30, exit)?; - Ok(()) - })?; + self.indexes_to_price_1m_min.compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 30, exit)?; + Ok(()) + })?; - self.indexes_to_price_1m_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max(starting_indexes.dateindex, high, 30, exit)?; - Ok(()) - })?; + self.indexes_to_price_1m_max.compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 30, exit)?; + Ok(()) + })?; - self.indexes_to_price_1y_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min(starting_indexes.dateindex, low, 365, exit)?; - Ok(()) - })?; + self.indexes_to_price_1y_min.compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 365, exit)?; + Ok(()) + })?; - self.indexes_to_price_1y_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max(starting_indexes.dateindex, high, 365, exit)?; - Ok(()) - })?; + self.indexes_to_price_1y_max.compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 365, exit)?; + Ok(()) + })?; self.dateindex_to_price_true_range.compute_transform3( starting_indexes.dateindex, @@ -85,15 +77,14 @@ impl Vecs { exit, )?; - self.indexes_to_price_2w_choppiness_index - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_price_2w_choppiness_index.compute_all(starting_indexes, exit, |v| { let n = 14; let log10n = (n as f32).log10(); v.compute_transform3( starting_indexes.dateindex, &self.dateindex_to_price_true_range_2w_sum, - self.indexes_to_price_2w_max.dateindex.u(), - self.indexes_to_price_2w_min.dateindex.u(), + &self.indexes_to_price_2w_max.dateindex, + &self.indexes_to_price_2w_min.dateindex, |(i, tr_sum, max, min, ..)| { ( i, diff --git a/crates/brk_computer/src/market/range/import.rs b/crates/brk_computer/src/market/range/import.rs index d9f4c882e..d9b591634 100644 --- a/crates/brk_computer/src/market/range/import.rs +++ b/crates/brk_computer/src/market/range/import.rs @@ -3,80 +3,60 @@ use brk_types::Version; use vecdb::{Database, EagerVec, ImportableVec}; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedDateLast}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { let v1 = Version::ONE; - let last = VecBuilderOptions::default().add_last(); Ok(Self { - indexes_to_price_1w_min: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_1w_min: ComputedDateLast::forced_import( db, "price_1w_min", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_1w_max: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_1w_max: ComputedDateLast::forced_import( db, "price_1w_max", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_2w_min: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_2w_min: ComputedDateLast::forced_import( db, "price_2w_min", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_2w_max: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_2w_max: ComputedDateLast::forced_import( db, "price_2w_max", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_1m_min: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_1m_min: ComputedDateLast::forced_import( db, "price_1m_min", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_1m_max: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_1m_max: ComputedDateLast::forced_import( db, "price_1m_max", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_1y_min: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_1y_min: ComputedDateLast::forced_import( db, "price_1y_min", - Source::Compute, version + v1, indexes, - last, )?, - indexes_to_price_1y_max: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_1y_max: ComputedDateLast::forced_import( db, "price_1y_max", - Source::Compute, version + v1, indexes, - last, )?, dateindex_to_price_true_range: EagerVec::forced_import( db, @@ -88,13 +68,11 @@ impl Vecs { "price_true_range_2w_sum", version, )?, - indexes_to_price_2w_choppiness_index: ComputedVecsFromDateIndex::forced_import( + indexes_to_price_2w_choppiness_index: ComputedDateLast::forced_import( db, "price_2w_choppiness_index", - Source::Compute, version + v1, indexes, - VecBuilderOptions::default().add_last(), )?, }) } diff --git a/crates/brk_computer/src/market/range/vecs.rs b/crates/brk_computer/src/market/range/vecs.rs index 667a820ed..1980b06b5 100644 --- a/crates/brk_computer/src/market/range/vecs.rs +++ b/crates/brk_computer/src/market/range/vecs.rs @@ -2,20 +2,20 @@ use brk_traversable::Traversable; use brk_types::{DateIndex, Dollars, StoredF32}; use vecdb::{EagerVec, PcoVec}; -use crate::internal::ComputedVecsFromDateIndex; +use crate::internal::ComputedDateLast; /// Price range and choppiness metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_price_1w_min: ComputedVecsFromDateIndex, - pub indexes_to_price_1w_max: ComputedVecsFromDateIndex, - pub indexes_to_price_2w_min: ComputedVecsFromDateIndex, - pub indexes_to_price_2w_max: ComputedVecsFromDateIndex, - pub indexes_to_price_1m_min: ComputedVecsFromDateIndex, - pub indexes_to_price_1m_max: ComputedVecsFromDateIndex, - pub indexes_to_price_1y_min: ComputedVecsFromDateIndex, - pub indexes_to_price_1y_max: ComputedVecsFromDateIndex, + pub indexes_to_price_1w_min: ComputedDateLast, + pub indexes_to_price_1w_max: ComputedDateLast, + pub indexes_to_price_2w_min: ComputedDateLast, + pub indexes_to_price_2w_max: ComputedDateLast, + pub indexes_to_price_1m_min: ComputedDateLast, + pub indexes_to_price_1m_max: ComputedDateLast, + pub indexes_to_price_1y_min: ComputedDateLast, + pub indexes_to_price_1y_max: ComputedDateLast, pub dateindex_to_price_true_range: EagerVec>, pub dateindex_to_price_true_range_2w_sum: EagerVec>, - pub indexes_to_price_2w_choppiness_index: ComputedVecsFromDateIndex, + pub indexes_to_price_2w_choppiness_index: ComputedDateLast, } diff --git a/crates/brk_computer/src/market/returns/compute.rs b/crates/brk_computer/src/market/returns/compute.rs index 939b0cc9a..9886af0e3 100644 --- a/crates/brk_computer/src/market/returns/compute.rs +++ b/crates/brk_computer/src/market/returns/compute.rs @@ -3,7 +3,7 @@ use brk_types::StoredF32; use vecdb::Exit; use super::Vecs; -use crate::{utils::OptionExt, ComputeIndexes}; +use crate::ComputeIndexes; impl Vecs { pub fn compute(&mut self, starting_indexes: &ComputeIndexes, exit: &Exit) -> Result<()> { @@ -11,9 +11,10 @@ impl Vecs { let price_returns_dca = self.price_returns.as_dca_period(); for (cagr, returns, days) in self.cagr.zip_mut_with_period(&price_returns_dca) { cagr.compute_all(starting_indexes, exit, |v| { + // KISS: dateindex is no longer Option v.compute_cagr( starting_indexes.dateindex, - returns.dateindex.u(), + &returns.dateindex, days as usize, exit, )?; @@ -21,8 +22,8 @@ impl Vecs { })?; } - // Returns standard deviation (computed from 1d returns) - let _1d_price_returns_dateindex = self.price_returns._1d.dateindex.u(); + // KISS: dateindex is no longer Option + let _1d_price_returns_dateindex = &self.price_returns._1d.dateindex; self.indexes_to_1d_returns_1w_sd.compute_all( starting_indexes, diff --git a/crates/brk_computer/src/market/returns/import.rs b/crates/brk_computer/src/market/returns/import.rs index dabfa9608..07556cd87 100644 --- a/crates/brk_computer/src/market/returns/import.rs +++ b/crates/brk_computer/src/market/returns/import.rs @@ -7,9 +7,8 @@ use super::Vecs; use crate::{ indexes, internal::{ - ComputedStandardDeviationVecsFromDateIndex, ComputedVecsFromDateIndex, - LazyVecsFrom2FromDateIndex, PercentageDiffCloseDollars, Source, - StandardDeviationVecsOptions, VecBuilderOptions, + BinaryDateLast, ComputedDateLast, ComputedStandardDeviationVecsDate, + PercentageDiffCloseDollars, StandardDeviationVecsOptions, }, market::dca::ByDcaCagr, price, @@ -24,14 +23,13 @@ impl Vecs { lookback: &lookback::Vecs, ) -> Result { let v1 = Version::ONE; - let last = VecBuilderOptions::default().add_last(); - // Price returns (lazy, from price.close and lookback.price_ago) + // KISS: Price returns (lazy, from price.close and lookback.price_ago) let price_returns = LOOKBACK_PERIOD_NAMES .zip_ref(&lookback.price_ago) .map(|(name, price_ago)| { - LazyVecsFrom2FromDateIndex::from_computed::( + BinaryDateLast::from_computed_both_last::( &format!("{name}_price_returns"), version, &price.usd.timeindexes_to_price_close, @@ -41,79 +39,61 @@ impl Vecs { // CAGR (computed, 2y+ only) let cagr = ByDcaCagr::try_new(|name, _days| { - ComputedVecsFromDateIndex::forced_import( - db, - &format!("{name}_cagr"), - Source::Compute, - version, - indexes, - last, - ) + ComputedDateLast::forced_import(db, &format!("{name}_cagr"), version, indexes) })?; - // Returns standard deviation (computed from 1d returns) - let indexes_to_1d_returns_1w_sd = - ComputedStandardDeviationVecsFromDateIndex::forced_import( - db, - "1d_returns_1w_sd", - 7, - Source::Compute, - version + v1, - indexes, - StandardDeviationVecsOptions::default(), - None, - )?; - let indexes_to_1d_returns_1m_sd = - ComputedStandardDeviationVecsFromDateIndex::forced_import( - db, - "1d_returns_1m_sd", - 30, - Source::Compute, - version + v1, - indexes, - StandardDeviationVecsOptions::default(), - None, - )?; - let indexes_to_1d_returns_1y_sd = - ComputedStandardDeviationVecsFromDateIndex::forced_import( - db, - "1d_returns_1y_sd", - 365, - Source::Compute, - version + v1, - indexes, - StandardDeviationVecsOptions::default(), - None, - )?; + let indexes_to_1d_returns_1w_sd = ComputedStandardDeviationVecsDate::forced_import( + db, + "1d_returns_1w_sd", + 7, + version + v1, + indexes, + StandardDeviationVecsOptions::default(), + None, + )?; + let indexes_to_1d_returns_1m_sd = ComputedStandardDeviationVecsDate::forced_import( + db, + "1d_returns_1m_sd", + 30, + version + v1, + indexes, + StandardDeviationVecsOptions::default(), + None, + )?; + let indexes_to_1d_returns_1y_sd = ComputedStandardDeviationVecsDate::forced_import( + db, + "1d_returns_1y_sd", + 365, + version + v1, + indexes, + StandardDeviationVecsOptions::default(), + None, + )?; - // Downside returns and deviation (for Sortino ratio) let dateindex_to_downside_returns = EagerVec::forced_import(db, "downside_returns", version)?; - let indexes_to_downside_1w_sd = ComputedStandardDeviationVecsFromDateIndex::forced_import( + let indexes_to_downside_1w_sd = ComputedStandardDeviationVecsDate::forced_import( db, "downside_1w_sd", 7, - Source::Compute, version + v1, indexes, StandardDeviationVecsOptions::default(), None, )?; - let indexes_to_downside_1m_sd = ComputedStandardDeviationVecsFromDateIndex::forced_import( + let indexes_to_downside_1m_sd = ComputedStandardDeviationVecsDate::forced_import( db, "downside_1m_sd", 30, - Source::Compute, version + v1, indexes, StandardDeviationVecsOptions::default(), None, )?; - let indexes_to_downside_1y_sd = ComputedStandardDeviationVecsFromDateIndex::forced_import( + let indexes_to_downside_1y_sd = ComputedStandardDeviationVecsDate::forced_import( db, "downside_1y_sd", 365, - Source::Compute, version + v1, indexes, StandardDeviationVecsOptions::default(), diff --git a/crates/brk_computer/src/market/returns/vecs.rs b/crates/brk_computer/src/market/returns/vecs.rs index 10bf7236f..ed38a27e9 100644 --- a/crates/brk_computer/src/market/returns/vecs.rs +++ b/crates/brk_computer/src/market/returns/vecs.rs @@ -3,30 +3,27 @@ use brk_types::{Close, DateIndex, Dollars, StoredF32}; use vecdb::{EagerVec, PcoVec}; use crate::{ - internal::{ - ComputedStandardDeviationVecsFromDateIndex, ComputedVecsFromDateIndex, - LazyVecsFrom2FromDateIndex, - }, + internal::{BinaryDateLast, ComputedDateLast, ComputedStandardDeviationVecsDate}, market::{dca::ByDcaCagr, lookback::ByLookbackPeriod}, }; /// Price returns, CAGR, and returns standard deviation metrics #[derive(Clone, Traversable)] pub struct Vecs { - // Price returns (lazy, from price.close and lookback.price_ago) - pub price_returns: ByLookbackPeriod, Dollars>>, + // KISS: Price returns (lazy, from price.close and lookback.price_ago) + pub price_returns: ByLookbackPeriod, Dollars>>, // CAGR (computed from returns, 2y+ only) - pub cagr: ByDcaCagr>, + pub cagr: ByDcaCagr>, // Returns standard deviation (computed from 1d returns) - pub indexes_to_1d_returns_1w_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_1d_returns_1m_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_1d_returns_1y_sd: ComputedStandardDeviationVecsFromDateIndex, + pub indexes_to_1d_returns_1w_sd: ComputedStandardDeviationVecsDate, + pub indexes_to_1d_returns_1m_sd: ComputedStandardDeviationVecsDate, + pub indexes_to_1d_returns_1y_sd: ComputedStandardDeviationVecsDate, // Downside returns and deviation (for Sortino ratio) pub dateindex_to_downside_returns: EagerVec>, - pub indexes_to_downside_1w_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_downside_1m_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_downside_1y_sd: ComputedStandardDeviationVecsFromDateIndex, + pub indexes_to_downside_1w_sd: ComputedStandardDeviationVecsDate, + pub indexes_to_downside_1m_sd: ComputedStandardDeviationVecsDate, + pub indexes_to_downside_1y_sd: ComputedStandardDeviationVecsDate, } diff --git a/crates/brk_computer/src/market/volatility/import.rs b/crates/brk_computer/src/market/volatility/import.rs index ff54579f7..ae52d9a72 100644 --- a/crates/brk_computer/src/market/volatility/import.rs +++ b/crates/brk_computer/src/market/volatility/import.rs @@ -4,7 +4,8 @@ use vecdb::{IterableCloneableVec, LazyVecFrom2}; use super::super::returns; use super::Vecs; use crate::internal::{ - LazyVecsFromDateIndex, RatioF32, StoredF32TimesSqrt30, StoredF32TimesSqrt365, StoredF32TimesSqrt7, + LazyDateLast, RatioF32, StoredF32TimesSqrt30, StoredF32TimesSqrt365, + StoredF32TimesSqrt7, }; impl Vecs { @@ -12,134 +13,69 @@ impl Vecs { let v2 = Version::TWO; let indexes_to_price_1w_volatility = - LazyVecsFromDateIndex::from_computed::( + LazyDateLast::from_source::( "price_1w_volatility", version + v2, - returns - .indexes_to_1d_returns_1w_sd - .sd - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), &returns.indexes_to_1d_returns_1w_sd.sd, ); let indexes_to_price_1m_volatility = - LazyVecsFromDateIndex::from_computed::( + LazyDateLast::from_source::( "price_1m_volatility", version + v2, - returns - .indexes_to_1d_returns_1m_sd - .sd - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), &returns.indexes_to_1d_returns_1m_sd.sd, ); let indexes_to_price_1y_volatility = - LazyVecsFromDateIndex::from_computed::( + LazyDateLast::from_source::( "price_1y_volatility", version + v2, - returns - .indexes_to_1d_returns_1y_sd - .sd - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), &returns.indexes_to_1d_returns_1y_sd.sd, ); - let dateindex_to_sharpe_1w = returns - .price_returns - ._1w - .dateindex - .as_ref() - .zip(indexes_to_price_1w_volatility.dateindex.as_ref()) - .map(|(ret, vol)| { - LazyVecFrom2::transformed::( - "sharpe_1w", - version + v2, - ret.boxed_clone(), - vol.boxed_clone(), - ) - }); + // KISS: dateindex is no longer Option + let dateindex_to_sharpe_1w = LazyVecFrom2::transformed::( + "sharpe_1w", + version + v2, + returns.price_returns._1w.dateindex.boxed_clone(), + indexes_to_price_1w_volatility.dateindex.boxed_clone(), + ); - let dateindex_to_sharpe_1m = returns - .price_returns - ._1m - .dateindex - .as_ref() - .zip(indexes_to_price_1m_volatility.dateindex.as_ref()) - .map(|(ret, vol)| { - LazyVecFrom2::transformed::( - "sharpe_1m", - version + v2, - ret.boxed_clone(), - vol.boxed_clone(), - ) - }); + let dateindex_to_sharpe_1m = LazyVecFrom2::transformed::( + "sharpe_1m", + version + v2, + returns.price_returns._1m.dateindex.boxed_clone(), + indexes_to_price_1m_volatility.dateindex.boxed_clone(), + ); - let dateindex_to_sharpe_1y = returns - .price_returns - ._1y - .dateindex - .as_ref() - .zip(indexes_to_price_1y_volatility.dateindex.as_ref()) - .map(|(ret, vol)| { - LazyVecFrom2::transformed::( - "sharpe_1y", - version + v2, - ret.boxed_clone(), - vol.boxed_clone(), - ) - }); + let dateindex_to_sharpe_1y = LazyVecFrom2::transformed::( + "sharpe_1y", + version + v2, + returns.price_returns._1y.dateindex.boxed_clone(), + indexes_to_price_1y_volatility.dateindex.boxed_clone(), + ); // Sortino ratio = returns / downside volatility - let dateindex_to_sortino_1w = returns - .price_returns - ._1w - .dateindex - .as_ref() - .zip(returns.indexes_to_downside_1w_sd.sd.dateindex.as_ref()) - .map(|(ret, downside_sd)| { - LazyVecFrom2::transformed::( - "sortino_1w", - version + v2, - ret.boxed_clone(), - downside_sd.boxed_clone(), - ) - }); + let dateindex_to_sortino_1w = LazyVecFrom2::transformed::( + "sortino_1w", + version + v2, + returns.price_returns._1w.dateindex.boxed_clone(), + returns.indexes_to_downside_1w_sd.sd.dateindex.boxed_clone(), + ); - let dateindex_to_sortino_1m = returns - .price_returns - ._1m - .dateindex - .as_ref() - .zip(returns.indexes_to_downside_1m_sd.sd.dateindex.as_ref()) - .map(|(ret, downside_sd)| { - LazyVecFrom2::transformed::( - "sortino_1m", - version + v2, - ret.boxed_clone(), - downside_sd.boxed_clone(), - ) - }); + let dateindex_to_sortino_1m = LazyVecFrom2::transformed::( + "sortino_1m", + version + v2, + returns.price_returns._1m.dateindex.boxed_clone(), + returns.indexes_to_downside_1m_sd.sd.dateindex.boxed_clone(), + ); - let dateindex_to_sortino_1y = returns - .price_returns - ._1y - .dateindex - .as_ref() - .zip(returns.indexes_to_downside_1y_sd.sd.dateindex.as_ref()) - .map(|(ret, downside_sd)| { - LazyVecFrom2::transformed::( - "sortino_1y", - version + v2, - ret.boxed_clone(), - downside_sd.boxed_clone(), - ) - }); + let dateindex_to_sortino_1y = LazyVecFrom2::transformed::( + "sortino_1y", + version + v2, + returns.price_returns._1y.dateindex.boxed_clone(), + returns.indexes_to_downside_1y_sd.sd.dateindex.boxed_clone(), + ); Self { indexes_to_price_1w_volatility, diff --git a/crates/brk_computer/src/market/volatility/vecs.rs b/crates/brk_computer/src/market/volatility/vecs.rs index 3b59a53f0..304d32a05 100644 --- a/crates/brk_computer/src/market/volatility/vecs.rs +++ b/crates/brk_computer/src/market/volatility/vecs.rs @@ -2,20 +2,21 @@ use brk_traversable::Traversable; use brk_types::{DateIndex, StoredF32}; use vecdb::LazyVecFrom2; -use crate::internal::LazyVecsFromDateIndex; +use crate::internal::LazyDateLast; /// Price volatility metrics (derived from returns standard deviation) #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_price_1w_volatility: LazyVecsFromDateIndex, - pub indexes_to_price_1m_volatility: LazyVecsFromDateIndex, - pub indexes_to_price_1y_volatility: LazyVecsFromDateIndex, + pub indexes_to_price_1w_volatility: LazyDateLast, + pub indexes_to_price_1m_volatility: LazyDateLast, + pub indexes_to_price_1y_volatility: LazyDateLast, - pub dateindex_to_sharpe_1w: Option>, - pub dateindex_to_sharpe_1m: Option>, - pub dateindex_to_sharpe_1y: Option>, + // KISS: now concrete since source is KISS + pub dateindex_to_sharpe_1w: LazyVecFrom2, + pub dateindex_to_sharpe_1m: LazyVecFrom2, + pub dateindex_to_sharpe_1y: LazyVecFrom2, - pub dateindex_to_sortino_1w: Option>, - pub dateindex_to_sortino_1m: Option>, - pub dateindex_to_sortino_1y: Option>, + pub dateindex_to_sortino_1w: LazyVecFrom2, + pub dateindex_to_sortino_1m: LazyVecFrom2, + pub dateindex_to_sortino_1y: LazyVecFrom2, } diff --git a/crates/brk_computer/src/outputs/count/compute.rs b/crates/brk_computer/src/outputs/count/compute.rs index 0ab81f930..63ef59393 100644 --- a/crates/brk_computer/src/outputs/count/compute.rs +++ b/crates/brk_computer/src/outputs/count/compute.rs @@ -16,12 +16,12 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_count.compute_rest( + self.indexes_to_count.derive_from( indexer, indexes, starting_indexes, + &indexes.transaction.txindex_to_output_count, exit, - Some(&indexes.transaction.txindex_to_output_count), )?; self.indexes_to_utxo_count @@ -29,23 +29,26 @@ impl Vecs { let mut input_count_iter = inputs_count .indexes_to_count .height - .unwrap_cumulative() + .sum_cum + .cumulative + .0 .into_iter(); - let mut opreturn_count_iter = scripts_count + let mut opreturn_cumulative_iter = scripts_count .indexes_to_opreturn_count - .height_extra - .unwrap_cumulative() + .rest + .height_cumulative + .0 .into_iter(); v.compute_transform( starting_indexes.height, - self.indexes_to_count.height.unwrap_cumulative(), + &self.indexes_to_count.height.sum_cum.cumulative.0, |(h, output_count, ..)| { let input_count = input_count_iter.get_unwrap(h); - let opreturn_count = opreturn_count_iter.get_unwrap(h); + let opreturn_count = *opreturn_cumulative_iter.get_unwrap(h); let block_count = u64::from(h + 1_usize); // -1 > genesis output is unspendable let mut utxo_count = - *output_count - (*input_count - block_count) - *opreturn_count - 1; + *output_count - (*input_count - block_count) - opreturn_count - 1; // txid dup: e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468 // Block 91_722 https://mempool.space/block/00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e diff --git a/crates/brk_computer/src/outputs/count/import.rs b/crates/brk_computer/src/outputs/count/import.rs index 80f1a5fa8..035be476c 100644 --- a/crates/brk_computer/src/outputs/count/import.rs +++ b/crates/brk_computer/src/outputs/count/import.rs @@ -1,41 +1,32 @@ use brk_error::Result; use brk_types::Version; -use vecdb::{Database, IterableCloneableVec}; +use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromHeight, ComputedVecsFromTxindex, Source, VecBuilderOptions}, + internal::{ComputedBlockFull, DerivedTxFull}, }; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; + let indexes_to_count = DerivedTxFull::forced_import( + db, + "output_count", + version, + indexes, + )?; + + let indexes_to_utxo_count = ComputedBlockFull::forced_import( + db, + "exact_utxo_count", + version, + indexes, + )?; Ok(Self { - indexes_to_count: ComputedVecsFromTxindex::forced_import( - db, - "output_count", - Source::Vec(indexes.transaction.txindex_to_output_count.boxed_clone()), - version, - indexes, - full_stats(), - )?, - indexes_to_utxo_count: ComputedVecsFromHeight::forced_import( - db, - "exact_utxo_count", - Source::Compute, - version, - indexes, - full_stats(), - )?, + indexes_to_count, + indexes_to_utxo_count, }) } } diff --git a/crates/brk_computer/src/outputs/count/vecs.rs b/crates/brk_computer/src/outputs/count/vecs.rs index d16d76385..902d3d7dd 100644 --- a/crates/brk_computer/src/outputs/count/vecs.rs +++ b/crates/brk_computer/src/outputs/count/vecs.rs @@ -1,10 +1,10 @@ use brk_traversable::Traversable; use brk_types::StoredU64; -use crate::internal::{ComputedVecsFromHeight, ComputedVecsFromTxindex}; +use crate::internal::{ComputedBlockFull, DerivedTxFull}; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_count: ComputedVecsFromTxindex, - pub indexes_to_utxo_count: ComputedVecsFromHeight, + pub indexes_to_count: DerivedTxFull, + pub indexes_to_utxo_count: ComputedBlockFull, } diff --git a/crates/brk_computer/src/pools/mod.rs b/crates/brk_computer/src/pools/mod.rs index a13134bfc..b8f900408 100644 --- a/crates/brk_computer/src/pools/mod.rs +++ b/crates/brk_computer/src/pools/mod.rs @@ -81,10 +81,9 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, starting_indexes: &ComputeIndexes, - price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { - self.compute_(indexer, indexes, starting_indexes, price, exit)?; + self.compute_(indexer, indexes, starting_indexes, exit)?; let _lock = exit.lock(); self.db.compact()?; Ok(()) @@ -95,13 +94,12 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, starting_indexes: &ComputeIndexes, - price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { self.compute_height_to_pool(indexer, indexes, starting_indexes, exit)?; self.vecs.par_iter_mut().try_for_each(|(_, vecs)| { - vecs.compute(indexes, starting_indexes, &self.height_to_pool, price, exit) + vecs.compute(indexes, starting_indexes, &self.height_to_pool, exit) })?; Ok(()) diff --git a/crates/brk_computer/src/pools/vecs.rs b/crates/brk_computer/src/pools/vecs.rs index 0b44c1bf1..b43054428 100644 --- a/crates/brk_computer/src/pools/vecs.rs +++ b/crates/brk_computer/src/pools/vecs.rs @@ -10,10 +10,9 @@ use crate::{ blocks, indexes::{self, ComputeIndexes}, internal::{ - ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, ComputedVecsFromHeight, - DollarsPlus, LazyValueVecsFrom2FromHeight, LazyVecsFrom2FromDateIndex, - LazyVecsFrom2FromHeight, MaskSats, PercentageU32F32, SatsPlus, SatsPlusToBitcoin, Source, - VecBuilderOptions, + BinaryBlockSumCum, BinaryDateLast, ComputedBlockSumCum, ComputedDateLast, + DerivedValueBlockSumCum, DollarsPlus, MaskSats, PercentageU32F32, SatsPlus, + SatsPlusToBitcoin, ValueBinaryBlock, }, price, transactions, }; @@ -22,21 +21,22 @@ use crate::{ pub struct Vecs { slug: PoolSlug, - pub indexes_to_blocks_mined: ComputedVecsFromHeight, - pub indexes_to_1w_blocks_mined: ComputedVecsFromDateIndex, - pub indexes_to_1m_blocks_mined: ComputedVecsFromDateIndex, - pub indexes_to_1y_blocks_mined: ComputedVecsFromDateIndex, + pub indexes_to_blocks_mined: ComputedBlockSumCum, + pub indexes_to_1w_blocks_mined: ComputedDateLast, + pub indexes_to_1m_blocks_mined: ComputedDateLast, + pub indexes_to_1y_blocks_mined: ComputedDateLast, pub height_to_subsidy: LazyVecFrom2, pub height_to_fee: LazyVecFrom2, - pub indexes_to_subsidy: ComputedValueVecsFromHeight, - pub indexes_to_fee: ComputedValueVecsFromHeight, - pub indexes_to_coinbase: LazyValueVecsFrom2FromHeight, - pub indexes_to_dominance: LazyVecsFrom2FromHeight, - pub indexes_to_1d_dominance: LazyVecsFrom2FromHeight, - pub indexes_to_1w_dominance: LazyVecsFrom2FromDateIndex, - pub indexes_to_1m_dominance: LazyVecsFrom2FromDateIndex, - pub indexes_to_1y_dominance: LazyVecsFrom2FromDateIndex, - pub indexes_to_days_since_block: ComputedVecsFromDateIndex, + pub indexes_to_subsidy: DerivedValueBlockSumCum, + pub indexes_to_fee: DerivedValueBlockSumCum, + pub indexes_to_coinbase: ValueBinaryBlock, + pub indexes_to_dominance: BinaryBlockSumCum, + pub indexes_to_1d_dominance: BinaryBlockSumCum, + // KISS: both sources are ComputedVecsDateLast + pub indexes_to_1w_dominance: BinaryDateLast, + pub indexes_to_1m_dominance: BinaryDateLast, + pub indexes_to_1y_dominance: BinaryDateLast, + pub indexes_to_days_since_block: ComputedDateLast, } impl Vecs { @@ -50,143 +50,90 @@ impl Vecs { transactions: &transactions::Vecs, ) -> Result { let suffix = |s: &str| format!("{}_{s}", slug); - let compute_dollars = price.is_some(); let version = parent_version; - let last = VecBuilderOptions::default().add_last(); - let sum_cum = VecBuilderOptions::default().add_sum().add_cumulative(); + let indexes_to_blocks_mined = + ComputedBlockSumCum::forced_import(db, &suffix("blocks_mined"), version, indexes)?; - macro_rules! import_di { - ($name:expr) => { - ComputedVecsFromDateIndex::forced_import( - db, - &suffix($name), - Source::Compute, - version, - indexes, - last.clone(), - )? - }; - } - - let indexes_to_blocks_mined = ComputedVecsFromHeight::forced_import( - db, - &suffix("blocks_mined"), - Source::Compute, - version, - indexes, - sum_cum, - )?; - - let indexes_to_1w_blocks_mined = import_di!("1w_blocks_mined"); - let indexes_to_1m_blocks_mined = import_di!("1m_blocks_mined"); - let indexes_to_1y_blocks_mined = import_di!("1y_blocks_mined"); + let indexes_to_1w_blocks_mined = + ComputedDateLast::forced_import(db, &suffix("1w_blocks_mined"), version, indexes)?; + let indexes_to_1m_blocks_mined = + ComputedDateLast::forced_import(db, &suffix("1m_blocks_mined"), version, indexes)?; + let indexes_to_1y_blocks_mined = + ComputedDateLast::forced_import(db, &suffix("1y_blocks_mined"), version, indexes)?; + // KISS: height is now a concrete field (no Option) let height_to_subsidy = LazyVecFrom2::transformed::( - &suffix("subsidy"), + &suffix("height_subsidy"), version, - indexes_to_blocks_mined - .height - .as_ref() - .unwrap() - .boxed_clone(), - blocks - .rewards - .indexes_to_subsidy - .sats - .height - .as_ref() - .unwrap() - .boxed_clone(), + indexes_to_blocks_mined.height.boxed_clone(), + blocks.rewards.indexes_to_subsidy.sats.height.boxed_clone(), ); - let indexes_to_subsidy = ComputedValueVecsFromHeight::forced_import( + let indexes_to_subsidy = DerivedValueBlockSumCum::forced_import( db, &suffix("subsidy"), - Source::Vec(height_to_subsidy.boxed_clone()), version, - sum_cum, - compute_dollars, indexes, + height_to_subsidy.boxed_clone(), + price, )?; + // KISS: height.sum_cum.sum.0 is now a concrete field let height_to_fee = LazyVecFrom2::transformed::( - &suffix("fee"), + &suffix("height_fee"), version, - indexes_to_blocks_mined - .height - .as_ref() - .unwrap() - .boxed_clone(), + indexes_to_blocks_mined.height.boxed_clone(), transactions .fees .indexes_to_fee .sats .height - .unwrap_sum() + .sum_cum + .sum + .0 .boxed_clone(), ); - let indexes_to_fee = ComputedValueVecsFromHeight::forced_import( + let indexes_to_fee = DerivedValueBlockSumCum::forced_import( db, &suffix("fee"), - Source::Vec(height_to_fee.boxed_clone()), version, - sum_cum, - compute_dollars, indexes, + height_to_fee.boxed_clone(), + price, )?; Ok(Self { - indexes_to_dominance: LazyVecsFrom2FromHeight::from_computed::( + indexes_to_dominance: BinaryBlockSumCum::from_computed::( &suffix("dominance"), version, - indexes_to_blocks_mined - .height - .as_ref() - .unwrap() - .boxed_clone(), - blocks - .count - .indexes_to_block_count - .height - .as_ref() - .unwrap() - .boxed_clone(), + indexes_to_blocks_mined.height.boxed_clone(), + blocks.count.indexes_to_block_count.height.boxed_clone(), &indexes_to_blocks_mined, &blocks.count.indexes_to_block_count, ), - indexes_to_1d_dominance: LazyVecsFrom2FromHeight::from_computed::( + indexes_to_1d_dominance: BinaryBlockSumCum::from_computed::( &suffix("1d_dominance"), version, - indexes_to_blocks_mined - .height - .as_ref() - .unwrap() - .boxed_clone(), - blocks - .count - .indexes_to_block_count - .height - .as_ref() - .unwrap() - .boxed_clone(), + indexes_to_blocks_mined.height.boxed_clone(), + blocks.count.indexes_to_block_count.height.boxed_clone(), &indexes_to_blocks_mined, &blocks.count.indexes_to_block_count, ), - indexes_to_1w_dominance: LazyVecsFrom2FromDateIndex::from_computed::( + indexes_to_1w_dominance: BinaryDateLast::from_computed_both_last::( &suffix("1w_dominance"), version, &indexes_to_1w_blocks_mined, &blocks.count.indexes_to_1w_block_count, ), - indexes_to_1m_dominance: LazyVecsFrom2FromDateIndex::from_computed::( + indexes_to_1m_dominance: BinaryDateLast::from_computed_both_last::( &suffix("1m_dominance"), version, &indexes_to_1m_blocks_mined, &blocks.count.indexes_to_1m_block_count, ), - indexes_to_1y_dominance: LazyVecsFrom2FromDateIndex::from_computed::( + indexes_to_1y_dominance: BinaryDateLast::from_computed_both_last::( &suffix("1y_dominance"), version, &indexes_to_1y_blocks_mined, @@ -197,7 +144,7 @@ impl Vecs { indexes_to_1w_blocks_mined, indexes_to_1m_blocks_mined, indexes_to_1y_blocks_mined, - indexes_to_coinbase: LazyValueVecsFrom2FromHeight::from_computed::< + indexes_to_coinbase: ValueBinaryBlock::from_derived::< SatsPlus, SatsPlusToBitcoin, DollarsPlus, @@ -213,17 +160,20 @@ impl Vecs { height_to_fee, indexes_to_subsidy, indexes_to_fee, - indexes_to_days_since_block: import_di!("days_since_block"), + indexes_to_days_since_block: ComputedDateLast::forced_import( + db, + &suffix("days_since_block"), + version, + indexes, + )?, }) } - #[allow(clippy::too_many_arguments)] pub fn compute( &mut self, indexes: &indexes::Vecs, starting_indexes: &ComputeIndexes, height_to_pool: &impl IterableVec, - price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { self.indexes_to_blocks_mined @@ -250,7 +200,7 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_sum( starting_indexes.dateindex, - self.indexes_to_blocks_mined.dateindex.unwrap_sum(), + self.indexes_to_blocks_mined.dateindex.sum.inner(), 7, exit, )?; @@ -261,7 +211,7 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_sum( starting_indexes.dateindex, - self.indexes_to_blocks_mined.dateindex.unwrap_sum(), + self.indexes_to_blocks_mined.dateindex.sum.inner(), 30, exit, )?; @@ -272,36 +222,30 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_sum( starting_indexes.dateindex, - self.indexes_to_blocks_mined.dateindex.unwrap_sum(), + self.indexes_to_blocks_mined.dateindex.sum.inner(), 365, exit, )?; Ok(()) })?; - self.indexes_to_subsidy.compute_rest( + self.indexes_to_subsidy.derive_from( indexes, - price, starting_indexes, + &self.height_to_subsidy, exit, - Some(&self.height_to_subsidy), )?; - self.indexes_to_fee.compute_rest( - indexes, - price, - starting_indexes, - exit, - Some(&self.height_to_fee), - )?; + self.indexes_to_fee + .derive_from(indexes, starting_indexes, &self.height_to_fee, exit)?; self.indexes_to_days_since_block .compute_all(starting_indexes, exit, |v| { let mut prev = None; v.compute_transform2( starting_indexes.dateindex, - self.indexes_to_blocks_mined.dateindex.unwrap_sum(), - self.indexes_to_blocks_mined.dateindex.unwrap_cumulative(), + self.indexes_to_blocks_mined.dateindex.sum.inner(), + self.indexes_to_blocks_mined.dateindex.cumulative.inner(), |(i, sum, cumulative, slf)| { if prev.is_none() { let i = i.to_usize(); diff --git a/crates/brk_computer/src/price/sats/compute.rs b/crates/brk_computer/src/price/sats/compute.rs index 32d0d7963..1d8e0be17 100644 --- a/crates/brk_computer/src/price/sats/compute.rs +++ b/crates/brk_computer/src/price/sats/compute.rs @@ -4,7 +4,7 @@ use vecdb::Exit; use super::Vecs; use super::super::usd; -use crate::{utils::OptionExt, ComputeIndexes}; +use crate::ComputeIndexes; impl Vecs { pub fn compute( @@ -63,7 +63,7 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_transform( starting_indexes.dateindex, - usd.timeindexes_to_price_open.dateindex.u(), + &usd.timeindexes_to_price_open.dateindex, |(i, open, ..)| (i, Open::new(Sats::ONE_BTC / *open)), exit, )?; @@ -74,7 +74,7 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_transform( starting_indexes.dateindex, - usd.timeindexes_to_price_low.dateindex.u(), + &usd.timeindexes_to_price_low.dateindex, |(i, low, ..)| (i, High::new(Sats::ONE_BTC / *low)), exit, )?; @@ -85,7 +85,7 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_transform( starting_indexes.dateindex, - usd.timeindexes_to_price_high.dateindex.u(), + &usd.timeindexes_to_price_high.dateindex, |(i, high, ..)| (i, Low::new(Sats::ONE_BTC / *high)), exit, )?; @@ -96,7 +96,7 @@ impl Vecs { .compute_all(starting_indexes, exit, |v| { v.compute_transform( starting_indexes.dateindex, - usd.timeindexes_to_price_close.dateindex.u(), + &usd.timeindexes_to_price_close.dateindex, |(i, close, ..)| (i, Close::new(Sats::ONE_BTC / *close)), exit, )?; @@ -127,22 +127,10 @@ impl Vecs { // DateIndex OHLC in sats self.dateindex_to_price_ohlc_in_sats.compute_transform4( starting_indexes.dateindex, - self.timeindexes_to_price_open_in_sats - .dateindex - .as_ref() - .unwrap(), - self.timeindexes_to_price_high_in_sats - .dateindex - .as_ref() - .unwrap(), - self.timeindexes_to_price_low_in_sats - .dateindex - .as_ref() - .unwrap(), - self.timeindexes_to_price_close_in_sats - .dateindex - .as_ref() - .unwrap(), + &self.timeindexes_to_price_open_in_sats.dateindex, + &self.timeindexes_to_price_high_in_sats.dateindex, + &self.timeindexes_to_price_low_in_sats.dateindex, + &self.timeindexes_to_price_close_in_sats.dateindex, |(i, open, high, low, close, _)| { ( i, @@ -160,16 +148,10 @@ impl Vecs { // Period OHLC in sats self.weekindex_to_price_ohlc_in_sats.compute_transform4( starting_indexes.weekindex, - self.timeindexes_to_price_open_in_sats - .weekindex - .unwrap_first(), - self.timeindexes_to_price_high_in_sats - .weekindex - .unwrap_max(), - self.timeindexes_to_price_low_in_sats.weekindex.unwrap_min(), - self.timeindexes_to_price_close_in_sats - .weekindex - .unwrap_last(), + &*self.timeindexes_to_price_open_in_sats.weekindex, + &*self.timeindexes_to_price_high_in_sats.weekindex, + &*self.timeindexes_to_price_low_in_sats.weekindex, + &*self.timeindexes_to_price_close_in_sats.weekindex, |(i, open, high, low, close, _)| { ( i, @@ -187,18 +169,10 @@ impl Vecs { self.difficultyepoch_to_price_ohlc_in_sats .compute_transform4( starting_indexes.difficultyepoch, - self.chainindexes_to_price_open_in_sats - .difficultyepoch - .unwrap_first(), - self.chainindexes_to_price_high_in_sats - .difficultyepoch - .unwrap_max(), - self.chainindexes_to_price_low_in_sats - .difficultyepoch - .unwrap_min(), - self.chainindexes_to_price_close_in_sats - .difficultyepoch - .unwrap_last(), + &*self.chainindexes_to_price_open_in_sats.difficultyepoch, + &*self.chainindexes_to_price_high_in_sats.difficultyepoch, + &*self.chainindexes_to_price_low_in_sats.difficultyepoch, + &*self.chainindexes_to_price_close_in_sats.difficultyepoch, |(i, open, high, low, close, _)| { ( i, @@ -215,18 +189,10 @@ impl Vecs { self.monthindex_to_price_ohlc_in_sats.compute_transform4( starting_indexes.monthindex, - self.timeindexes_to_price_open_in_sats - .monthindex - .unwrap_first(), - self.timeindexes_to_price_high_in_sats - .monthindex - .unwrap_max(), - self.timeindexes_to_price_low_in_sats - .monthindex - .unwrap_min(), - self.timeindexes_to_price_close_in_sats - .monthindex - .unwrap_last(), + &*self.timeindexes_to_price_open_in_sats.monthindex, + &*self.timeindexes_to_price_high_in_sats.monthindex, + &*self.timeindexes_to_price_low_in_sats.monthindex, + &*self.timeindexes_to_price_close_in_sats.monthindex, |(i, open, high, low, close, _)| { ( i, @@ -243,18 +209,10 @@ impl Vecs { self.quarterindex_to_price_ohlc_in_sats.compute_transform4( starting_indexes.quarterindex, - self.timeindexes_to_price_open_in_sats - .quarterindex - .unwrap_first(), - self.timeindexes_to_price_high_in_sats - .quarterindex - .unwrap_max(), - self.timeindexes_to_price_low_in_sats - .quarterindex - .unwrap_min(), - self.timeindexes_to_price_close_in_sats - .quarterindex - .unwrap_last(), + &*self.timeindexes_to_price_open_in_sats.quarterindex, + &*self.timeindexes_to_price_high_in_sats.quarterindex, + &*self.timeindexes_to_price_low_in_sats.quarterindex, + &*self.timeindexes_to_price_close_in_sats.quarterindex, |(i, open, high, low, close, _)| { ( i, @@ -272,18 +230,10 @@ impl Vecs { self.semesterindex_to_price_ohlc_in_sats .compute_transform4( starting_indexes.semesterindex, - self.timeindexes_to_price_open_in_sats - .semesterindex - .unwrap_first(), - self.timeindexes_to_price_high_in_sats - .semesterindex - .unwrap_max(), - self.timeindexes_to_price_low_in_sats - .semesterindex - .unwrap_min(), - self.timeindexes_to_price_close_in_sats - .semesterindex - .unwrap_last(), + &*self.timeindexes_to_price_open_in_sats.semesterindex, + &*self.timeindexes_to_price_high_in_sats.semesterindex, + &*self.timeindexes_to_price_low_in_sats.semesterindex, + &*self.timeindexes_to_price_close_in_sats.semesterindex, |(i, open, high, low, close, _)| { ( i, @@ -300,16 +250,10 @@ impl Vecs { self.yearindex_to_price_ohlc_in_sats.compute_transform4( starting_indexes.yearindex, - self.timeindexes_to_price_open_in_sats - .yearindex - .unwrap_first(), - self.timeindexes_to_price_high_in_sats - .yearindex - .unwrap_max(), - self.timeindexes_to_price_low_in_sats.yearindex.unwrap_min(), - self.timeindexes_to_price_close_in_sats - .yearindex - .unwrap_last(), + &*self.timeindexes_to_price_open_in_sats.yearindex, + &*self.timeindexes_to_price_high_in_sats.yearindex, + &*self.timeindexes_to_price_low_in_sats.yearindex, + &*self.timeindexes_to_price_close_in_sats.yearindex, |(i, open, high, low, close, _)| { ( i, @@ -326,18 +270,10 @@ impl Vecs { self.decadeindex_to_price_ohlc_in_sats.compute_transform4( starting_indexes.decadeindex, - self.timeindexes_to_price_open_in_sats - .decadeindex - .unwrap_first(), - self.timeindexes_to_price_high_in_sats - .decadeindex - .unwrap_max(), - self.timeindexes_to_price_low_in_sats - .decadeindex - .unwrap_min(), - self.timeindexes_to_price_close_in_sats - .decadeindex - .unwrap_last(), + &*self.timeindexes_to_price_open_in_sats.decadeindex, + &*self.timeindexes_to_price_high_in_sats.decadeindex, + &*self.timeindexes_to_price_low_in_sats.decadeindex, + &*self.timeindexes_to_price_close_in_sats.decadeindex, |(i, open, high, low, close, _)| { ( i, diff --git a/crates/brk_computer/src/price/sats/import.rs b/crates/brk_computer/src/price/sats/import.rs index 6300a962d..2443c3676 100644 --- a/crates/brk_computer/src/price/sats/import.rs +++ b/crates/brk_computer/src/price/sats/import.rs @@ -5,20 +5,14 @@ use vecdb::{Database, EagerVec, ImportableVec}; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeightStrict, Source, VecBuilderOptions}, + internal::{ + ComputedChainFirst, ComputedChainLast, ComputedChainMax, ComputedChainMin, + ComputedDateLast, ComputedVecsDateFirst, ComputedVecsDateMax, ComputedVecsDateMin, + }, }; impl Vecs { - pub fn forced_import( - db: &Database, - version: Version, - indexes: &indexes::Vecs, - ) -> Result { - let first = || VecBuilderOptions::default().add_first(); - let last = || VecBuilderOptions::default().add_last(); - let min = || VecBuilderOptions::default().add_min(); - let max = || VecBuilderOptions::default().add_max(); - + pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { Ok(Self { dateindex_to_price_ohlc_in_sats: EagerVec::forced_import( db, @@ -30,65 +24,53 @@ impl Vecs { "price_ohlc_in_sats", version, )?, - timeindexes_to_price_open_in_sats: ComputedVecsFromDateIndex::forced_import( - db, - "price_open_in_sats", - Source::Compute, - version, - indexes, - first(), - )?, - timeindexes_to_price_high_in_sats: ComputedVecsFromDateIndex::forced_import( - db, - "price_high_in_sats", - Source::Compute, - version, - indexes, - max(), - )?, - timeindexes_to_price_low_in_sats: ComputedVecsFromDateIndex::forced_import( - db, - "price_low_in_sats", - Source::Compute, - version, - indexes, - min(), - )?, - timeindexes_to_price_close_in_sats: ComputedVecsFromDateIndex::forced_import( - db, - "price_close_in_sats", - Source::Compute, - version, - indexes, - last(), - )?, - chainindexes_to_price_open_in_sats: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_open_in_sats: ComputedVecsDateFirst::forced_import( db, "price_open_in_sats", version, indexes, - first(), )?, - chainindexes_to_price_high_in_sats: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_high_in_sats: ComputedVecsDateMax::forced_import( db, "price_high_in_sats", version, indexes, - max(), )?, - chainindexes_to_price_low_in_sats: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_low_in_sats: ComputedVecsDateMin::forced_import( db, "price_low_in_sats", version, indexes, - min(), )?, - chainindexes_to_price_close_in_sats: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_close_in_sats: ComputedDateLast::forced_import( + db, + "price_close_in_sats", + version, + indexes, + )?, + chainindexes_to_price_open_in_sats: ComputedChainFirst::forced_import( + db, + "price_open_in_sats", + version, + indexes, + )?, + chainindexes_to_price_high_in_sats: ComputedChainMax::forced_import( + db, + "price_high_in_sats", + version, + indexes, + )?, + chainindexes_to_price_low_in_sats: ComputedChainMin::forced_import( + db, + "price_low_in_sats", + version, + indexes, + )?, + chainindexes_to_price_close_in_sats: ComputedChainLast::forced_import( db, "price_close_in_sats", version, indexes, - last(), )?, weekindex_to_price_ohlc_in_sats: EagerVec::forced_import( db, diff --git a/crates/brk_computer/src/price/sats/vecs.rs b/crates/brk_computer/src/price/sats/vecs.rs index 75aec7eee..28d1d4578 100644 --- a/crates/brk_computer/src/price/sats/vecs.rs +++ b/crates/brk_computer/src/price/sats/vecs.rs @@ -1,11 +1,14 @@ use brk_traversable::Traversable; use brk_types::{ - Close, DateIndex, DecadeIndex, DifficultyEpoch, Height, High, Low, MonthIndex, - OHLCSats, Open, QuarterIndex, Sats, SemesterIndex, WeekIndex, YearIndex, + Close, DateIndex, DecadeIndex, DifficultyEpoch, Height, High, Low, MonthIndex, OHLCSats, Open, + QuarterIndex, Sats, SemesterIndex, WeekIndex, YearIndex, }; use vecdb::{BytesVec, EagerVec}; -use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeightStrict}; +use crate::internal::{ + ComputedChainFirst, ComputedChainLast, ComputedChainMax, ComputedChainMin, ComputedDateLast, + ComputedVecsDateFirst, ComputedVecsDateMax, ComputedVecsDateMin, +}; #[derive(Clone, Traversable)] pub struct Vecs { @@ -14,16 +17,16 @@ pub struct Vecs { pub height_to_price_ohlc_in_sats: EagerVec>, // Computed time indexes in sats - pub timeindexes_to_price_open_in_sats: ComputedVecsFromDateIndex>, - pub timeindexes_to_price_high_in_sats: ComputedVecsFromDateIndex>, - pub timeindexes_to_price_low_in_sats: ComputedVecsFromDateIndex>, - pub timeindexes_to_price_close_in_sats: ComputedVecsFromDateIndex>, + pub timeindexes_to_price_open_in_sats: ComputedVecsDateFirst>, + pub timeindexes_to_price_high_in_sats: ComputedVecsDateMax>, + pub timeindexes_to_price_low_in_sats: ComputedVecsDateMin>, + pub timeindexes_to_price_close_in_sats: ComputedDateLast>, - // Computed chain indexes in sats - pub chainindexes_to_price_open_in_sats: ComputedVecsFromHeightStrict>, - pub chainindexes_to_price_high_in_sats: ComputedVecsFromHeightStrict>, - pub chainindexes_to_price_low_in_sats: ComputedVecsFromHeightStrict>, - pub chainindexes_to_price_close_in_sats: ComputedVecsFromHeightStrict>, + // Computed chain indexes in sats (KISS types) + pub chainindexes_to_price_open_in_sats: ComputedChainFirst>, + pub chainindexes_to_price_high_in_sats: ComputedChainMax>, + pub chainindexes_to_price_low_in_sats: ComputedChainMin>, + pub chainindexes_to_price_close_in_sats: ComputedChainLast>, // Period OHLC in sats pub weekindex_to_price_ohlc_in_sats: EagerVec>, diff --git a/crates/brk_computer/src/price/usd/compute.rs b/crates/brk_computer/src/price/usd/compute.rs index 569fad6f9..b5c7a8c32 100644 --- a/crates/brk_computer/src/price/usd/compute.rs +++ b/crates/brk_computer/src/price/usd/compute.rs @@ -104,10 +104,10 @@ impl Vecs { // Period OHLC aggregates self.weekindex_to_price_ohlc.compute_transform4( starting_indexes.weekindex, - self.timeindexes_to_price_open.weekindex.unwrap_first(), - self.timeindexes_to_price_high.weekindex.unwrap_max(), - self.timeindexes_to_price_low.weekindex.unwrap_min(), - self.timeindexes_to_price_close.weekindex.unwrap_last(), + &*self.timeindexes_to_price_open.weekindex, + &*self.timeindexes_to_price_high.weekindex, + &*self.timeindexes_to_price_low.weekindex, + &*self.timeindexes_to_price_close.weekindex, |(i, open, high, low, close, _)| { ( i, @@ -124,14 +124,10 @@ impl Vecs { self.difficultyepoch_to_price_ohlc.compute_transform4( starting_indexes.difficultyepoch, - self.chainindexes_to_price_open - .difficultyepoch - .unwrap_first(), - self.chainindexes_to_price_high.difficultyepoch.unwrap_max(), - self.chainindexes_to_price_low.difficultyepoch.unwrap_min(), - self.chainindexes_to_price_close - .difficultyepoch - .unwrap_last(), + &*self.chainindexes_to_price_open.difficultyepoch, + &*self.chainindexes_to_price_high.difficultyepoch, + &*self.chainindexes_to_price_low.difficultyepoch, + &*self.chainindexes_to_price_close.difficultyepoch, |(i, open, high, low, close, _)| { ( i, @@ -148,10 +144,10 @@ impl Vecs { self.monthindex_to_price_ohlc.compute_transform4( starting_indexes.monthindex, - self.timeindexes_to_price_open.monthindex.unwrap_first(), - self.timeindexes_to_price_high.monthindex.unwrap_max(), - self.timeindexes_to_price_low.monthindex.unwrap_min(), - self.timeindexes_to_price_close.monthindex.unwrap_last(), + &*self.timeindexes_to_price_open.monthindex, + &*self.timeindexes_to_price_high.monthindex, + &*self.timeindexes_to_price_low.monthindex, + &*self.timeindexes_to_price_close.monthindex, |(i, open, high, low, close, _)| { ( i, @@ -168,10 +164,10 @@ impl Vecs { self.quarterindex_to_price_ohlc.compute_transform4( starting_indexes.quarterindex, - self.timeindexes_to_price_open.quarterindex.unwrap_first(), - self.timeindexes_to_price_high.quarterindex.unwrap_max(), - self.timeindexes_to_price_low.quarterindex.unwrap_min(), - self.timeindexes_to_price_close.quarterindex.unwrap_last(), + &*self.timeindexes_to_price_open.quarterindex, + &*self.timeindexes_to_price_high.quarterindex, + &*self.timeindexes_to_price_low.quarterindex, + &*self.timeindexes_to_price_close.quarterindex, |(i, open, high, low, close, _)| { ( i, @@ -188,10 +184,10 @@ impl Vecs { self.semesterindex_to_price_ohlc.compute_transform4( starting_indexes.semesterindex, - self.timeindexes_to_price_open.semesterindex.unwrap_first(), - self.timeindexes_to_price_high.semesterindex.unwrap_max(), - self.timeindexes_to_price_low.semesterindex.unwrap_min(), - self.timeindexes_to_price_close.semesterindex.unwrap_last(), + &*self.timeindexes_to_price_open.semesterindex, + &*self.timeindexes_to_price_high.semesterindex, + &*self.timeindexes_to_price_low.semesterindex, + &*self.timeindexes_to_price_close.semesterindex, |(i, open, high, low, close, _)| { ( i, @@ -208,10 +204,10 @@ impl Vecs { self.yearindex_to_price_ohlc.compute_transform4( starting_indexes.yearindex, - self.timeindexes_to_price_open.yearindex.unwrap_first(), - self.timeindexes_to_price_high.yearindex.unwrap_max(), - self.timeindexes_to_price_low.yearindex.unwrap_min(), - self.timeindexes_to_price_close.yearindex.unwrap_last(), + &*self.timeindexes_to_price_open.yearindex, + &*self.timeindexes_to_price_high.yearindex, + &*self.timeindexes_to_price_low.yearindex, + &*self.timeindexes_to_price_close.yearindex, |(i, open, high, low, close, _)| { ( i, @@ -228,10 +224,10 @@ impl Vecs { self.decadeindex_to_price_ohlc.compute_transform4( starting_indexes.decadeindex, - self.timeindexes_to_price_open.decadeindex.unwrap_first(), - self.timeindexes_to_price_high.decadeindex.unwrap_max(), - self.timeindexes_to_price_low.decadeindex.unwrap_min(), - self.timeindexes_to_price_close.decadeindex.unwrap_last(), + &*self.timeindexes_to_price_open.decadeindex, + &*self.timeindexes_to_price_high.decadeindex, + &*self.timeindexes_to_price_low.decadeindex, + &*self.timeindexes_to_price_close.decadeindex, |(i, open, high, low, close, _)| { ( i, diff --git a/crates/brk_computer/src/price/usd/import.rs b/crates/brk_computer/src/price/usd/import.rs index 76efc6c9c..e5f16d45c 100644 --- a/crates/brk_computer/src/price/usd/import.rs +++ b/crates/brk_computer/src/price/usd/import.rs @@ -6,7 +6,10 @@ use super::super::ohlc; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeightStrict, Source, VecBuilderOptions}, + internal::{ + ComputedChainFirst, ComputedChainLast, ComputedChainMax, ComputedChainMin, + ComputedDateLast, ComputedVecsDateFirst, ComputedVecsDateMax, ComputedVecsDateMin, + }, }; impl Vecs { @@ -16,11 +19,6 @@ impl Vecs { indexes: &indexes::Vecs, ohlc: &ohlc::Vecs, ) -> Result { - let first = || VecBuilderOptions::default().add_first(); - let last = || VecBuilderOptions::default().add_last(); - let min = || VecBuilderOptions::default().add_min(); - let max = || VecBuilderOptions::default().add_max(); - let height_to_price_ohlc = LazyVecFrom1::init( "price_ohlc", version, @@ -101,65 +99,53 @@ impl Vecs { height_to_price_high_in_cents, height_to_price_low_in_cents, height_to_price_open_in_cents, - timeindexes_to_price_open: ComputedVecsFromDateIndex::forced_import( - db, - "price_open", - Source::Compute, - version, - indexes, - first(), - )?, - timeindexes_to_price_high: ComputedVecsFromDateIndex::forced_import( - db, - "price_high", - Source::Compute, - version, - indexes, - max(), - )?, - timeindexes_to_price_low: ComputedVecsFromDateIndex::forced_import( - db, - "price_low", - Source::Compute, - version, - indexes, - min(), - )?, - timeindexes_to_price_close: ComputedVecsFromDateIndex::forced_import( - db, - "price_close", - Source::Compute, - version, - indexes, - last(), - )?, - chainindexes_to_price_open: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_open: ComputedVecsDateFirst::forced_import( db, "price_open", version, indexes, - first(), )?, - chainindexes_to_price_high: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_high: ComputedVecsDateMax::forced_import( db, "price_high", version, indexes, - max(), )?, - chainindexes_to_price_low: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_low: ComputedVecsDateMin::forced_import( db, "price_low", version, indexes, - min(), )?, - chainindexes_to_price_close: ComputedVecsFromHeightStrict::forced_import( + timeindexes_to_price_close: ComputedDateLast::forced_import( + db, + "price_close", + version, + indexes, + )?, + chainindexes_to_price_open: ComputedChainFirst::forced_import( + db, + "price_open", + version, + indexes, + )?, + chainindexes_to_price_high: ComputedChainMax::forced_import( + db, + "price_high", + version, + indexes, + )?, + chainindexes_to_price_low: ComputedChainMin::forced_import( + db, + "price_low", + version, + indexes, + )?, + chainindexes_to_price_close: ComputedChainLast::forced_import( db, "price_close", version, indexes, - last(), )?, weekindex_to_price_ohlc: EagerVec::forced_import(db, "price_ohlc", version)?, difficultyepoch_to_price_ohlc: EagerVec::forced_import(db, "price_ohlc", version)?, diff --git a/crates/brk_computer/src/price/usd/vecs.rs b/crates/brk_computer/src/price/usd/vecs.rs index f6a8b4084..997dc9f26 100644 --- a/crates/brk_computer/src/price/usd/vecs.rs +++ b/crates/brk_computer/src/price/usd/vecs.rs @@ -5,15 +5,21 @@ use brk_types::{ }; use vecdb::{BytesVec, EagerVec, LazyVecFrom1}; -use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeightStrict}; +use crate::internal::{ + ComputedChainFirst, ComputedChainLast, ComputedChainMax, ComputedChainMin, ComputedDateLast, + ComputedVecsDateFirst, ComputedVecsDateMax, ComputedVecsDateMin, +}; #[derive(Clone, Traversable)] pub struct Vecs { // Derived price data in cents - pub dateindex_to_price_close_in_cents: LazyVecFrom1, DateIndex, OHLCCents>, - pub dateindex_to_price_high_in_cents: LazyVecFrom1, DateIndex, OHLCCents>, + pub dateindex_to_price_close_in_cents: + LazyVecFrom1, DateIndex, OHLCCents>, + pub dateindex_to_price_high_in_cents: + LazyVecFrom1, DateIndex, OHLCCents>, pub dateindex_to_price_low_in_cents: LazyVecFrom1, DateIndex, OHLCCents>, - pub dateindex_to_price_open_in_cents: LazyVecFrom1, DateIndex, OHLCCents>, + pub dateindex_to_price_open_in_cents: + LazyVecFrom1, DateIndex, OHLCCents>, pub height_to_price_close_in_cents: LazyVecFrom1, Height, OHLCCents>, pub height_to_price_high_in_cents: LazyVecFrom1, Height, OHLCCents>, pub height_to_price_low_in_cents: LazyVecFrom1, Height, OHLCCents>, @@ -24,16 +30,16 @@ pub struct Vecs { pub height_to_price_ohlc: LazyVecFrom1, // Computed time indexes - pub timeindexes_to_price_close: ComputedVecsFromDateIndex>, - pub timeindexes_to_price_high: ComputedVecsFromDateIndex>, - pub timeindexes_to_price_low: ComputedVecsFromDateIndex>, - pub timeindexes_to_price_open: ComputedVecsFromDateIndex>, + pub timeindexes_to_price_close: ComputedDateLast>, + pub timeindexes_to_price_high: ComputedVecsDateMax>, + pub timeindexes_to_price_low: ComputedVecsDateMin>, + pub timeindexes_to_price_open: ComputedVecsDateFirst>, - // Computed chain indexes - pub chainindexes_to_price_close: ComputedVecsFromHeightStrict>, - pub chainindexes_to_price_high: ComputedVecsFromHeightStrict>, - pub chainindexes_to_price_low: ComputedVecsFromHeightStrict>, - pub chainindexes_to_price_open: ComputedVecsFromHeightStrict>, + // Computed chain indexes (KISS types) + pub chainindexes_to_price_close: ComputedChainLast>, + pub chainindexes_to_price_high: ComputedChainMax>, + pub chainindexes_to_price_low: ComputedChainMin>, + pub chainindexes_to_price_open: ComputedChainFirst>, // Period OHLC pub weekindex_to_price_ohlc: EagerVec>, diff --git a/crates/brk_computer/src/scripts/count/compute.rs b/crates/brk_computer/src/scripts/count/compute.rs index d0754b8d3..8297c8047 100644 --- a/crates/brk_computer/src/scripts/count/compute.rs +++ b/crates/brk_computer/src/scripts/count/compute.rs @@ -4,7 +4,7 @@ use brk_types::StoredU64; use vecdb::{Exit, TypedVecIterator}; use super::Vecs; -use crate::{indexes, utils::OptionExt, ComputeIndexes}; +use crate::{indexes, ComputeIndexes}; impl Vecs { pub fn compute( @@ -147,14 +147,14 @@ impl Vecs { })?; // Compute segwit_count = p2wpkh + p2wsh + p2tr - let mut p2wsh_iter = self.indexes_to_p2wsh_count.height.u().into_iter(); - let mut p2tr_iter = self.indexes_to_p2tr_count.height.u().into_iter(); + let mut p2wsh_iter = self.indexes_to_p2wsh_count.height.into_iter(); + let mut p2tr_iter = self.indexes_to_p2tr_count.height.into_iter(); self.indexes_to_segwit_count .compute_all(indexes, starting_indexes, exit, |v| { v.compute_transform( starting_indexes.height, - self.indexes_to_p2wpkh_count.height.u(), + &self.indexes_to_p2wpkh_count.height, |(h, p2wpkh, ..)| { let sum = *p2wpkh + *p2wsh_iter.get_unwrap(h) + *p2tr_iter.get_unwrap(h); (h, StoredU64::from(sum)) diff --git a/crates/brk_computer/src/scripts/count/import.rs b/crates/brk_computer/src/scripts/count/import.rs index 9067c2685..f422227c8 100644 --- a/crates/brk_computer/src/scripts/count/import.rs +++ b/crates/brk_computer/src/scripts/count/import.rs @@ -6,11 +6,9 @@ use super::Vecs; use crate::{ indexes, internal::{ - ComputedVecsFromHeight, LazyVecsFrom2FromHeight, PercentageU64F32, Source, - VecBuilderOptions, + ComputedBlockFull, BinaryBlockFull, PercentageU64F32, }, outputs, - utils::OptionExt, }; impl Vecs { @@ -20,116 +18,87 @@ impl Vecs { indexes: &indexes::Vecs, outputs: &outputs::Vecs, ) -> Result { - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; - - let indexes_to_p2a_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2a_count = ComputedBlockFull::forced_import( db, "p2a_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2ms_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2ms_count = ComputedBlockFull::forced_import( db, "p2ms_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2pk33_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2pk33_count = ComputedBlockFull::forced_import( db, "p2pk33_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2pk65_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2pk65_count = ComputedBlockFull::forced_import( db, "p2pk65_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2pkh_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2pkh_count = ComputedBlockFull::forced_import( db, "p2pkh_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2sh_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2sh_count = ComputedBlockFull::forced_import( db, "p2sh_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2tr_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2tr_count = ComputedBlockFull::forced_import( db, "p2tr_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2wpkh_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2wpkh_count = ComputedBlockFull::forced_import( db, "p2wpkh_count", - Source::Compute, version, indexes, - full_stats(), )?; - let indexes_to_p2wsh_count = ComputedVecsFromHeight::forced_import( + let indexes_to_p2wsh_count = ComputedBlockFull::forced_import( db, "p2wsh_count", - Source::Compute, version, indexes, - full_stats(), )?; // Aggregate counts (computed from per-type counts) - let indexes_to_segwit_count = ComputedVecsFromHeight::forced_import( + let indexes_to_segwit_count = ComputedBlockFull::forced_import( db, "segwit_count", - Source::Compute, version, indexes, - full_stats(), )?; // Adoption ratios (lazy) // Uses outputs.count.indexes_to_count as denominator (total output count) // At height level: per-block ratio; at dateindex level: sum-based ratio (% of new outputs) let indexes_to_taproot_adoption = - LazyVecsFrom2FromHeight::from_height_and_txindex::( + BinaryBlockFull::from_height_and_txindex::( "taproot_adoption", version, - indexes_to_p2tr_count.height.u().boxed_clone(), - outputs.count.indexes_to_count.height.sum.u().boxed_clone(), + indexes_to_p2tr_count.height.boxed_clone(), + outputs.count.indexes_to_count.height.sum_cum.sum.0.boxed_clone(), &indexes_to_p2tr_count, &outputs.count.indexes_to_count, ); let indexes_to_segwit_adoption = - LazyVecsFrom2FromHeight::from_height_and_txindex::( + BinaryBlockFull::from_height_and_txindex::( "segwit_adoption", version, - indexes_to_segwit_count.height.u().boxed_clone(), - outputs.count.indexes_to_count.height.sum.u().boxed_clone(), + indexes_to_segwit_count.height.boxed_clone(), + outputs.count.indexes_to_count.height.sum_cum.sum.0.boxed_clone(), &indexes_to_segwit_count, &outputs.count.indexes_to_count, ); @@ -144,29 +113,23 @@ impl Vecs { indexes_to_p2tr_count, indexes_to_p2wpkh_count, indexes_to_p2wsh_count, - indexes_to_opreturn_count: ComputedVecsFromHeight::forced_import( + indexes_to_opreturn_count: ComputedBlockFull::forced_import( db, "opreturn_count", - Source::Compute, version, indexes, - full_stats(), )?, - indexes_to_emptyoutput_count: ComputedVecsFromHeight::forced_import( + indexes_to_emptyoutput_count: ComputedBlockFull::forced_import( db, "emptyoutput_count", - Source::Compute, version, indexes, - full_stats(), )?, - indexes_to_unknownoutput_count: ComputedVecsFromHeight::forced_import( + indexes_to_unknownoutput_count: ComputedBlockFull::forced_import( db, "unknownoutput_count", - Source::Compute, version, indexes, - full_stats(), )?, indexes_to_segwit_count, indexes_to_taproot_adoption, diff --git a/crates/brk_computer/src/scripts/count/vecs.rs b/crates/brk_computer/src/scripts/count/vecs.rs index 7c990e3fb..60f1870a2 100644 --- a/crates/brk_computer/src/scripts/count/vecs.rs +++ b/crates/brk_computer/src/scripts/count/vecs.rs @@ -1,32 +1,32 @@ use brk_traversable::Traversable; use brk_types::{StoredF32, StoredU64}; -use crate::internal::{ComputedVecsFromHeight, LazyVecsFrom2FromHeight}; +use crate::internal::{ComputedBlockFull, BinaryBlockFull}; #[derive(Clone, Traversable)] pub struct Vecs { // Per-type output counts - pub indexes_to_p2a_count: ComputedVecsFromHeight, - pub indexes_to_p2ms_count: ComputedVecsFromHeight, - pub indexes_to_p2pk33_count: ComputedVecsFromHeight, - pub indexes_to_p2pk65_count: ComputedVecsFromHeight, - pub indexes_to_p2pkh_count: ComputedVecsFromHeight, - pub indexes_to_p2sh_count: ComputedVecsFromHeight, - pub indexes_to_p2tr_count: ComputedVecsFromHeight, - pub indexes_to_p2wpkh_count: ComputedVecsFromHeight, - pub indexes_to_p2wsh_count: ComputedVecsFromHeight, - pub indexes_to_opreturn_count: ComputedVecsFromHeight, - pub indexes_to_emptyoutput_count: ComputedVecsFromHeight, - pub indexes_to_unknownoutput_count: ComputedVecsFromHeight, + pub indexes_to_p2a_count: ComputedBlockFull, + pub indexes_to_p2ms_count: ComputedBlockFull, + pub indexes_to_p2pk33_count: ComputedBlockFull, + pub indexes_to_p2pk65_count: ComputedBlockFull, + pub indexes_to_p2pkh_count: ComputedBlockFull, + pub indexes_to_p2sh_count: ComputedBlockFull, + pub indexes_to_p2tr_count: ComputedBlockFull, + pub indexes_to_p2wpkh_count: ComputedBlockFull, + pub indexes_to_p2wsh_count: ComputedBlockFull, + pub indexes_to_opreturn_count: ComputedBlockFull, + pub indexes_to_emptyoutput_count: ComputedBlockFull, + pub indexes_to_unknownoutput_count: ComputedBlockFull, // Aggregate counts /// SegWit output count (p2wpkh + p2wsh + p2tr) - pub indexes_to_segwit_count: ComputedVecsFromHeight, + pub indexes_to_segwit_count: ComputedBlockFull, // Adoption ratios (lazy) // Denominator is outputs.count.indexes_to_count (total output count) /// Taproot adoption: p2tr / total_outputs * 100 - pub indexes_to_taproot_adoption: LazyVecsFrom2FromHeight, + pub indexes_to_taproot_adoption: BinaryBlockFull, /// SegWit adoption: segwit / total_outputs * 100 - pub indexes_to_segwit_adoption: LazyVecsFrom2FromHeight, + pub indexes_to_segwit_adoption: BinaryBlockFull, } diff --git a/crates/brk_computer/src/scripts/value/compute.rs b/crates/brk_computer/src/scripts/value/compute.rs index d94085b6f..3451c404a 100644 --- a/crates/brk_computer/src/scripts/value/compute.rs +++ b/crates/brk_computer/src/scripts/value/compute.rs @@ -15,71 +15,72 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - // Validate computed versions against dependencies - let dep_version = indexer.vecs.txout.height_to_first_txoutindex.version() - + indexer.vecs.txout.txoutindex_to_outputtype.version() - + indexer.vecs.txout.txoutindex_to_value.version(); - self.height_to_opreturn_value - .validate_computed_version_or_reset(dep_version)?; - - // Get target height - let target_len = indexer.vecs.txout.height_to_first_txoutindex.len(); - if target_len == 0 { - return Ok(()); - } - let target_height = Height::from(target_len - 1); - - // Find starting height for this vec - let current_len = self.height_to_opreturn_value.len(); - let starting_height = Height::from(current_len.min(starting_indexes.height.to_usize())); - - if starting_height > target_height { - return Ok(()); - } - - // Prepare iterators - let mut height_to_first_txoutindex = - indexer.vecs.txout.height_to_first_txoutindex.iter()?; - let mut txoutindex_to_outputtype = indexer.vecs.txout.txoutindex_to_outputtype.iter()?; - let mut txoutindex_to_value = indexer.vecs.txout.txoutindex_to_value.iter()?; - - // Iterate blocks - for h in starting_height.to_usize()..=target_height.to_usize() { - let height = Height::from(h); - - // Get output range for this block - let first_txoutindex = height_to_first_txoutindex.get_unwrap(height); - let next_first_txoutindex = if height < target_height { - height_to_first_txoutindex.get_unwrap(height.incremented()) - } else { - TxOutIndex::from(indexer.vecs.txout.txoutindex_to_value.len()) - }; - - // Sum opreturn values - let mut opreturn_value = Sats::ZERO; - for i in first_txoutindex.to_usize()..next_first_txoutindex.to_usize() { - let txoutindex = TxOutIndex::from(i); - let outputtype = txoutindex_to_outputtype.get_unwrap(txoutindex); - - if outputtype == OutputType::OpReturn { - let value = txoutindex_to_value.get_unwrap(txoutindex); - opreturn_value += value; - } - } - - self.height_to_opreturn_value - .truncate_push(height, opreturn_value)?; - } - - self.height_to_opreturn_value.write()?; - - // Compute derived vecs (dateindex aggregations, etc.) - self.indexes_to_opreturn_value.compute_rest( + self.indexes_to_opreturn_value.compute_all( indexes, price, starting_indexes, exit, - Some(&self.height_to_opreturn_value), + |height_vec| { + // Validate computed versions against dependencies + let dep_version = indexer.vecs.txout.height_to_first_txoutindex.version() + + indexer.vecs.txout.txoutindex_to_outputtype.version() + + indexer.vecs.txout.txoutindex_to_value.version(); + height_vec.validate_computed_version_or_reset(dep_version)?; + + // Get target height + let target_len = indexer.vecs.txout.height_to_first_txoutindex.len(); + if target_len == 0 { + return Ok(()); + } + let target_height = Height::from(target_len - 1); + + // Find starting height for this vec + let current_len = height_vec.len(); + let starting_height = + Height::from(current_len.min(starting_indexes.height.to_usize())); + + if starting_height > target_height { + return Ok(()); + } + + // Prepare iterators + let mut height_to_first_txoutindex = + indexer.vecs.txout.height_to_first_txoutindex.iter()?; + let mut txoutindex_to_outputtype = + indexer.vecs.txout.txoutindex_to_outputtype.iter()?; + let mut txoutindex_to_value = indexer.vecs.txout.txoutindex_to_value.iter()?; + + // Iterate blocks + for h in starting_height.to_usize()..=target_height.to_usize() { + let height = Height::from(h); + + // Get output range for this block + let first_txoutindex = height_to_first_txoutindex.get_unwrap(height); + let next_first_txoutindex = if height < target_height { + height_to_first_txoutindex.get_unwrap(height.incremented()) + } else { + TxOutIndex::from(indexer.vecs.txout.txoutindex_to_value.len()) + }; + + // Sum opreturn values + let mut opreturn_value = Sats::ZERO; + for i in first_txoutindex.to_usize()..next_first_txoutindex.to_usize() { + let txoutindex = TxOutIndex::from(i); + let outputtype = txoutindex_to_outputtype.get_unwrap(txoutindex); + + if outputtype == OutputType::OpReturn { + let value = txoutindex_to_value.get_unwrap(txoutindex); + opreturn_value += value; + } + } + + height_vec.truncate_push(height, opreturn_value)?; + } + + height_vec.write()?; + + Ok(()) + }, )?; Ok(()) diff --git a/crates/brk_computer/src/scripts/value/import.rs b/crates/brk_computer/src/scripts/value/import.rs index 42d653d74..fc3dd7600 100644 --- a/crates/brk_computer/src/scripts/value/import.rs +++ b/crates/brk_computer/src/scripts/value/import.rs @@ -1,12 +1,9 @@ use brk_error::Result; use brk_types::Version; -use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec}; +use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedValueVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ValueBlockFull}; impl Vecs { pub fn forced_import( @@ -15,24 +12,15 @@ impl Vecs { indexes: &indexes::Vecs, compute_dollars: bool, ) -> Result { - let height_to_opreturn_value = EagerVec::forced_import(db, "opreturn_value", version)?; - - let indexes_to_opreturn_value = ComputedValueVecsFromHeight::forced_import( + let indexes_to_opreturn_value = ValueBlockFull::forced_import( db, "opreturn_value", - Source::Vec(height_to_opreturn_value.boxed_clone()), version, - VecBuilderOptions::default() - .add_sum() - .add_cumulative() - .add_average() - .add_minmax(), - compute_dollars, indexes, + compute_dollars, )?; Ok(Self { - height_to_opreturn_value, indexes_to_opreturn_value, }) } diff --git a/crates/brk_computer/src/scripts/value/vecs.rs b/crates/brk_computer/src/scripts/value/vecs.rs index 28f8c7fd1..3ddab2dcf 100644 --- a/crates/brk_computer/src/scripts/value/vecs.rs +++ b/crates/brk_computer/src/scripts/value/vecs.rs @@ -1,11 +1,8 @@ use brk_traversable::Traversable; -use brk_types::{Height, Sats}; -use vecdb::{EagerVec, PcoVec}; -use crate::internal::ComputedValueVecsFromHeight; +use crate::internal::ValueBlockFull; #[derive(Clone, Traversable)] pub struct Vecs { - pub height_to_opreturn_value: EagerVec>, - pub indexes_to_opreturn_value: ComputedValueVecsFromHeight, + pub indexes_to_opreturn_value: ValueBlockFull, } diff --git a/crates/brk_computer/src/supply/burned/compute.rs b/crates/brk_computer/src/supply/burned/compute.rs index a73537c3b..840a13ede 100644 --- a/crates/brk_computer/src/supply/burned/compute.rs +++ b/crates/brk_computer/src/supply/burned/compute.rs @@ -3,7 +3,7 @@ use brk_types::{Height, Sats}; use vecdb::{AnyStoredVec, AnyVec, Exit, GenericStoredVec, TypedVecIterator, VecIndex}; use super::Vecs; -use crate::{blocks, indexes, price, scripts, utils::OptionExt, ComputeIndexes}; +use crate::{blocks, indexes, price, scripts, ComputeIndexes}; impl Vecs { pub fn compute( @@ -15,99 +15,97 @@ impl Vecs { price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { - // Validate computed versions against dependencies - let opreturn_dep_version = scripts.value.height_to_opreturn_value.version(); - self.height_to_opreturn - .validate_computed_version_or_reset(opreturn_dep_version)?; - - let unspendable_dep_version = self.height_to_opreturn.version() - + blocks - .rewards - .indexes_to_unclaimed_rewards - .sats - .height - .u() - .version(); - self.height_to_unspendable - .validate_computed_version_or_reset(unspendable_dep_version)?; - - // 1. Copy per-block opreturn values from scripts - let scripts_target = scripts.value.height_to_opreturn_value.len(); - if scripts_target > 0 { - let target_height = Height::from(scripts_target - 1); - let current_len = self.height_to_opreturn.len(); - let starting_height = Height::from(current_len.min(starting_indexes.height.to_usize())); - - if starting_height <= target_height { - let mut opreturn_value_iter = scripts.value.height_to_opreturn_value.into_iter(); - - for h in starting_height.to_usize()..=target_height.to_usize() { - let height = Height::from(h); - let value = opreturn_value_iter.get_unwrap(height); - self.height_to_opreturn.truncate_push(height, value)?; - } - } - } - - self.height_to_opreturn.write()?; - - // 2. Compute per-block unspendable = opreturn + unclaimed_rewards + genesis (at height 0) - let opreturn_target = self.height_to_opreturn.len(); - if opreturn_target > 0 { - let target_height = Height::from(opreturn_target - 1); - let current_len = self.height_to_unspendable.len(); - let starting_height = Height::from(current_len.min(starting_indexes.height.to_usize())); - - if starting_height <= target_height { - let mut opreturn_iter = self.height_to_opreturn.into_iter(); - let mut unclaimed_rewards_iter = blocks - .rewards - .indexes_to_unclaimed_rewards - .sats - .height - .u() - .into_iter(); - - for h in starting_height.to_usize()..=target_height.to_usize() { - let height = Height::from(h); - - // Genesis block 50 BTC is unspendable (only at height 0) - let genesis = if height == Height::ZERO { - Sats::FIFTY_BTC - } else { - Sats::ZERO - }; - - // Per-block opreturn value - let opreturn = opreturn_iter.get_unwrap(height); - - // Per-block unclaimed rewards - let unclaimed = unclaimed_rewards_iter.get_unwrap(height); - - let unspendable = genesis + opreturn + unclaimed; - self.height_to_unspendable - .truncate_push(height, unspendable)?; - } - } - } - - self.height_to_unspendable.write()?; - - // Compute index aggregations - self.indexes_to_opreturn.compute_rest( + // 1. Compute opreturn supply - copy per-block opreturn values from scripts + self.indexes_to_opreturn.compute_all( indexes, price, starting_indexes, exit, - Some(&self.height_to_opreturn), + |height_vec| { + // Validate computed versions against dependencies + // KISS: height is now inside indexes_to_opreturn_value.sats.height + let opreturn_dep_version = + scripts.value.indexes_to_opreturn_value.sats.height.version(); + height_vec.validate_computed_version_or_reset(opreturn_dep_version)?; + + // Copy per-block opreturn values from scripts + let scripts_target = scripts.value.indexes_to_opreturn_value.sats.height.len(); + if scripts_target > 0 { + let target_height = Height::from(scripts_target - 1); + let current_len = height_vec.len(); + let starting_height = + Height::from(current_len.min(starting_indexes.height.to_usize())); + + if starting_height <= target_height { + let mut opreturn_value_iter = + scripts.value.indexes_to_opreturn_value.sats.height.into_iter(); + + for h in starting_height.to_usize()..=target_height.to_usize() { + let height = Height::from(h); + let value = opreturn_value_iter.get_unwrap(height); + height_vec.truncate_push(height, value)?; + } + } + } + + height_vec.write()?; + Ok(()) + }, )?; - self.indexes_to_unspendable.compute_rest( + // 2. Compute unspendable supply = opreturn + unclaimed_rewards + genesis (at height 0) + // Get reference to opreturn height vec for computing unspendable + let opreturn_height = &self.indexes_to_opreturn.sats.height; + let unclaimed_height = &blocks.rewards.indexes_to_unclaimed_rewards.sats.height; + + self.indexes_to_unspendable.compute_all( indexes, price, starting_indexes, exit, - Some(&self.height_to_unspendable), + |height_vec| { + // KISS: height is now a concrete field (no Option) + let unspendable_dep_version = + opreturn_height.version() + unclaimed_height.version(); + height_vec.validate_computed_version_or_reset(unspendable_dep_version)?; + + let opreturn_target = opreturn_height.len(); + if opreturn_target > 0 { + let target_height = Height::from(opreturn_target - 1); + let current_len = height_vec.len(); + let starting_height = + Height::from(current_len.min(starting_indexes.height.to_usize())); + + if starting_height <= target_height { + let mut opreturn_iter = opreturn_height.into_iter(); + // KISS: height is now a concrete field (no Option) + let mut unclaimed_rewards_iter = unclaimed_height.into_iter(); + + for h in starting_height.to_usize()..=target_height.to_usize() { + let height = Height::from(h); + + // Genesis block 50 BTC is unspendable (only at height 0) + let genesis = if height == Height::ZERO { + Sats::FIFTY_BTC + } else { + Sats::ZERO + }; + + // Per-block opreturn value + let opreturn = opreturn_iter.get_unwrap(height); + + // Per-block unclaimed rewards + let unclaimed = unclaimed_rewards_iter.get_unwrap(height); + + let unspendable = genesis + opreturn + unclaimed; + height_vec.truncate_push(height, unspendable)?; + } + } + } + + height_vec.write()?; + Ok(()) + }, )?; Ok(()) diff --git a/crates/brk_computer/src/supply/burned/import.rs b/crates/brk_computer/src/supply/burned/import.rs index 704b106de..6ab3f2036 100644 --- a/crates/brk_computer/src/supply/burned/import.rs +++ b/crates/brk_computer/src/supply/burned/import.rs @@ -1,12 +1,9 @@ use brk_error::Result; use brk_types::Version; -use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec}; +use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedValueVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ValueBlockSumCum}; impl Vecs { pub fn forced_import( @@ -15,33 +12,23 @@ impl Vecs { indexes: &indexes::Vecs, compute_dollars: bool, ) -> Result { - let height_to_opreturn = EagerVec::forced_import(db, "opreturn_supply", version)?; - - let indexes_to_opreturn = ComputedValueVecsFromHeight::forced_import( + let indexes_to_opreturn = ValueBlockSumCum::forced_import( db, "opreturn_supply", - Source::Vec(height_to_opreturn.boxed_clone()), version, - VecBuilderOptions::default().add_last().add_cumulative(), - compute_dollars, indexes, + compute_dollars, )?; - let height_to_unspendable = EagerVec::forced_import(db, "unspendable_supply", version)?; - - let indexes_to_unspendable = ComputedValueVecsFromHeight::forced_import( + let indexes_to_unspendable = ValueBlockSumCum::forced_import( db, "unspendable_supply", - Source::Vec(height_to_unspendable.boxed_clone()), version, - VecBuilderOptions::default().add_last().add_cumulative(), - compute_dollars, indexes, + compute_dollars, )?; Ok(Self { - height_to_opreturn, - height_to_unspendable, indexes_to_opreturn, indexes_to_unspendable, }) diff --git a/crates/brk_computer/src/supply/burned/vecs.rs b/crates/brk_computer/src/supply/burned/vecs.rs index 5234344e3..e1ebdc109 100644 --- a/crates/brk_computer/src/supply/burned/vecs.rs +++ b/crates/brk_computer/src/supply/burned/vecs.rs @@ -1,14 +1,10 @@ use brk_traversable::Traversable; -use brk_types::{Height, Sats}; -use vecdb::{EagerVec, PcoVec}; -use crate::internal::ComputedValueVecsFromHeight; +use crate::internal::ValueBlockSumCum; /// Burned/unspendable supply metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub height_to_opreturn: EagerVec>, - pub height_to_unspendable: EagerVec>, - pub indexes_to_opreturn: ComputedValueVecsFromHeight, - pub indexes_to_unspendable: ComputedValueVecsFromHeight, + pub indexes_to_opreturn: ValueBlockSumCum, + pub indexes_to_unspendable: ValueBlockSumCum, } diff --git a/crates/brk_computer/src/supply/circulating/import.rs b/crates/brk_computer/src/supply/circulating/import.rs index f455a7f1e..2d38ded16 100644 --- a/crates/brk_computer/src/supply/circulating/import.rs +++ b/crates/brk_computer/src/supply/circulating/import.rs @@ -4,7 +4,7 @@ use vecdb::{IterableCloneableVec, LazyVecFrom1}; use super::Vecs; use crate::{ distribution, - internal::{DollarsIdentity, LazyValueVecsFromDateIndex, SatsIdentity, SatsToBitcoin}, + internal::{DollarsIdentity, LazyValueDateLast, SatsIdentity, SatsToBitcoin}, }; impl Vecs { @@ -38,8 +38,8 @@ impl Vecs { ) }); - // Create lazy identity wrapper around the FULL supply (not half!) - let indexes = LazyValueVecsFromDateIndex::from_source::< + // Create lazy identity wrapper around the FULL supply (not half!) - KISS + let indexes = LazyValueDateLast::from_source::< SatsIdentity, SatsToBitcoin, DollarsIdentity, diff --git a/crates/brk_computer/src/supply/circulating/vecs.rs b/crates/brk_computer/src/supply/circulating/vecs.rs index cfac77c16..f927015e2 100644 --- a/crates/brk_computer/src/supply/circulating/vecs.rs +++ b/crates/brk_computer/src/supply/circulating/vecs.rs @@ -2,13 +2,13 @@ use brk_traversable::Traversable; use brk_types::{Bitcoin, Dollars, Height, Sats}; use vecdb::LazyVecFrom1; -use crate::internal::LazyValueVecsFromDateIndex; +use crate::internal::LazyValueDateLast; -/// Circulating supply - lazy references to distribution's actual supply +/// Circulating supply - lazy references to distribution's actual supply (KISS) #[derive(Clone, Traversable)] pub struct Vecs { pub height_to_sats: LazyVecFrom1, pub height_to_btc: LazyVecFrom1, pub height_to_usd: Option>, - pub indexes: LazyValueVecsFromDateIndex, + pub indexes: LazyValueDateLast, } diff --git a/crates/brk_computer/src/supply/inflation/compute.rs b/crates/brk_computer/src/supply/inflation/compute.rs index 7b6ae0c6b..94ed73992 100644 --- a/crates/brk_computer/src/supply/inflation/compute.rs +++ b/crates/brk_computer/src/supply/inflation/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use vecdb::Exit; use super::Vecs; -use crate::{blocks, distribution, utils::OptionExt, ComputeIndexes}; +use crate::{blocks, distribution, ComputeIndexes}; impl Vecs { pub fn compute( @@ -21,15 +21,12 @@ impl Vecs { .indexes_to_supply; self.indexes.compute_all(starting_indexes, exit, |v| { + // KISS: dateindex.sum is now a concrete field v.compute_transform2( starting_indexes.dateindex, - blocks - .rewards - .indexes_to_subsidy - .sats - .dateindex - .unwrap_sum(), - circulating_supply.sats.dateindex.u(), + &blocks.rewards.indexes_to_subsidy.sats.dateindex.sum_cum.sum.0, + // KISS: dateindex is no longer Option + &circulating_supply.sats_dateindex, |(i, subsidy_1d_sum, supply, ..)| { let inflation = if *supply > 0 { 365.0 * *subsidy_1d_sum as f64 / *supply as f64 * 100.0 diff --git a/crates/brk_computer/src/supply/inflation/import.rs b/crates/brk_computer/src/supply/inflation/import.rs index b46b076b9..2ee8ae2b5 100644 --- a/crates/brk_computer/src/supply/inflation/import.rs +++ b/crates/brk_computer/src/supply/inflation/import.rs @@ -3,20 +3,15 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedVecsDateAverage}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let indexes_to_inflation_rate = ComputedVecsFromDateIndex::forced_import( + let indexes_to_inflation_rate = ComputedVecsDateAverage::forced_import( db, "inflation_rate", - Source::Compute, version, indexes, - VecBuilderOptions::default().add_average(), )?; Ok(Self { diff --git a/crates/brk_computer/src/supply/inflation/vecs.rs b/crates/brk_computer/src/supply/inflation/vecs.rs index 02bef6cb7..ecfcaef7a 100644 --- a/crates/brk_computer/src/supply/inflation/vecs.rs +++ b/crates/brk_computer/src/supply/inflation/vecs.rs @@ -1,10 +1,10 @@ use brk_traversable::Traversable; use brk_types::StoredF32; -use crate::internal::ComputedVecsFromDateIndex; +use crate::internal::ComputedVecsDateAverage; /// Inflation rate metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes: ComputedVecsFromDateIndex, + pub indexes: ComputedVecsDateAverage, } diff --git a/crates/brk_computer/src/supply/market_cap/import.rs b/crates/brk_computer/src/supply/market_cap/import.rs index 6744c5d40..98a526365 100644 --- a/crates/brk_computer/src/supply/market_cap/import.rs +++ b/crates/brk_computer/src/supply/market_cap/import.rs @@ -4,7 +4,7 @@ use vecdb::{IterableCloneableVec, LazyVecFrom1}; use super::Vecs; use crate::{ distribution, - internal::{DollarsIdentity, LazyVecsFromDateIndex}, + internal::{DollarsIdentity, LazyDateLast}, }; impl Vecs { @@ -22,12 +22,12 @@ impl Vecs { }) }); - // Market cap by indexes (lazy from distribution's supply in USD) + // Market cap by indexes (lazy from distribution's supply in USD) - KISS let indexes = supply_metrics.indexes_to_supply.dollars.as_ref().map(|d| { - LazyVecsFromDateIndex::from_computed::( + // KISS: dateindex is no longer Option, use from_source + LazyDateLast::from_source::( "market_cap", version, - d.dateindex.as_ref().map(|v| v.boxed_clone()), d, ) }); diff --git a/crates/brk_computer/src/supply/market_cap/vecs.rs b/crates/brk_computer/src/supply/market_cap/vecs.rs index 6ebfe490d..c4cf12a92 100644 --- a/crates/brk_computer/src/supply/market_cap/vecs.rs +++ b/crates/brk_computer/src/supply/market_cap/vecs.rs @@ -2,12 +2,12 @@ use brk_traversable::Traversable; use brk_types::{Dollars, Height}; use vecdb::LazyVecFrom1; -use crate::internal::LazyVecsFromDateIndex; +use crate::internal::LazyDateLast; -/// Market cap metrics - lazy references to supply in USD +/// Market cap metrics - lazy references to supply in USD (KISS) /// (market_cap = circulating_supply * price, already computed in distribution) #[derive(Clone, Traversable)] pub struct Vecs { pub height: Option>, - pub indexes: Option>, + pub indexes: Option>, } diff --git a/crates/brk_computer/src/supply/velocity/compute.rs b/crates/brk_computer/src/supply/velocity/compute.rs index ea42c88db..358880997 100644 --- a/crates/brk_computer/src/supply/velocity/compute.rs +++ b/crates/brk_computer/src/supply/velocity/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use vecdb::Exit; use super::Vecs; -use crate::{distribution, transactions, utils::OptionExt, ComputeIndexes}; +use crate::{distribution, transactions, ComputeIndexes}; impl Vecs { pub fn compute( @@ -20,17 +20,13 @@ impl Vecs { .supply .indexes_to_supply; - // BTC velocity + // BTC velocity - KISS: dateindex is no longer Option self.indexes_to_btc .compute_all(starting_indexes, exit, |v| { v.compute_divide( starting_indexes.dateindex, - transactions - .volume - .indexes_to_annualized_volume_btc - .dateindex - .u(), - circulating_supply.bitcoin.dateindex.u(), + &transactions.volume.indexes_to_annualized_volume_btc.dateindex, + &*circulating_supply.bitcoin.dateindex, exit, )?; Ok(()) @@ -38,18 +34,14 @@ impl Vecs { // USD velocity if let Some(usd_velocity) = self.indexes_to_usd.as_mut() - && let Some(volume_usd) = transactions - .volume - .indexes_to_annualized_volume_usd - .dateindex - .as_ref() && let Some(supply_usd) = circulating_supply.dollars.as_ref() { + // KISS: dateindex is no longer Option usd_velocity.compute_all(starting_indexes, exit, |v| { v.compute_divide( starting_indexes.dateindex, - volume_usd, - supply_usd.dateindex.u(), + &transactions.volume.indexes_to_annualized_volume_usd.dateindex, + &supply_usd.dateindex, exit, )?; Ok(()) diff --git a/crates/brk_computer/src/supply/velocity/import.rs b/crates/brk_computer/src/supply/velocity/import.rs index a9dc05aab..e47d7a305 100644 --- a/crates/brk_computer/src/supply/velocity/import.rs +++ b/crates/brk_computer/src/supply/velocity/import.rs @@ -3,10 +3,7 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedVecsDateAverage}; impl Vecs { pub fn forced_import( @@ -15,23 +12,19 @@ impl Vecs { indexes: &indexes::Vecs, compute_dollars: bool, ) -> Result { - let indexes_to_btc = ComputedVecsFromDateIndex::forced_import( + let indexes_to_btc = ComputedVecsDateAverage::forced_import( db, "btc_velocity", - Source::Compute, version, indexes, - VecBuilderOptions::default().add_average(), )?; let indexes_to_usd = compute_dollars.then(|| { - ComputedVecsFromDateIndex::forced_import( + ComputedVecsDateAverage::forced_import( db, "usd_velocity", - Source::Compute, version, indexes, - VecBuilderOptions::default().add_average(), ) .unwrap() }); diff --git a/crates/brk_computer/src/supply/velocity/vecs.rs b/crates/brk_computer/src/supply/velocity/vecs.rs index 1e4e4ec6c..0951b2b35 100644 --- a/crates/brk_computer/src/supply/velocity/vecs.rs +++ b/crates/brk_computer/src/supply/velocity/vecs.rs @@ -1,11 +1,11 @@ use brk_traversable::Traversable; use brk_types::StoredF64; -use crate::internal::ComputedVecsFromDateIndex; +use crate::internal::ComputedVecsDateAverage; /// Velocity metrics (annualized volume / circulating supply) #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_btc: ComputedVecsFromDateIndex, - pub indexes_to_usd: Option>, + pub indexes_to_btc: ComputedVecsDateAverage, + pub indexes_to_usd: Option>, } diff --git a/crates/brk_computer/src/traits.rs b/crates/brk_computer/src/traits/mod.rs similarity index 92% rename from crates/brk_computer/src/traits.rs rename to crates/brk_computer/src/traits/mod.rs index 9cd4bed27..b2ad60590 100644 --- a/crates/brk_computer/src/traits.rs +++ b/crates/brk_computer/src/traits/mod.rs @@ -4,6 +4,11 @@ use vecdb::{ AnyStoredVec, AnyVec, EagerVec, Exit, GenericStoredVec, IterableVec, PcoVec, VecIndex, Version, }; +mod pricing; + +// TODO: Re-export when Phase 3 (Pricing migration) is complete +// pub use pricing::{Priced, Pricing, Unpriced}; + const DCA_AMOUNT: Dollars = Dollars::mint(100.0); pub trait ComputeDCAStackViaLen { @@ -123,7 +128,7 @@ impl ComputeDCAStackViaLen for EagerVec> { } pub trait ComputeDCAAveragePriceViaLen { - fn compute_dca_avg_price_via_len( + fn compute_dca_average_price_via_len( &mut self, max_from: DateIndex, stacks: &impl IterableVec, @@ -131,7 +136,7 @@ pub trait ComputeDCAAveragePriceViaLen { exit: &Exit, ) -> Result<()>; - fn compute_dca_avg_price_via_from( + fn compute_dca_average_price_via_from( &mut self, max_from: DateIndex, stacks: &impl IterableVec, @@ -141,7 +146,7 @@ pub trait ComputeDCAAveragePriceViaLen { } impl ComputeDCAAveragePriceViaLen for EagerVec> { - fn compute_dca_avg_price_via_len( + fn compute_dca_average_price_via_len( &mut self, max_from: DateIndex, stacks: &impl IterableVec, @@ -161,15 +166,15 @@ impl ComputeDCAAveragePriceViaLen for EagerVec> { .enumerate() .skip(index.to_usize()) .try_for_each(|(i, stack)| { - let mut avg_price = Dollars::from(f64::NAN); + let mut average_price = Dollars::from(f64::NAN); if i > first_price_date { - avg_price = DCA_AMOUNT + average_price = DCA_AMOUNT * len .min(i.to_usize() + 1) .min(i.checked_sub(first_price_date).unwrap().to_usize() + 1) / Bitcoin::from(stack); } - self.truncate_push_at(i, avg_price) + self.truncate_push_at(i, average_price) })?; let _lock = exit.lock(); @@ -178,7 +183,7 @@ impl ComputeDCAAveragePriceViaLen for EagerVec> { Ok(()) } - fn compute_dca_avg_price_via_from( + fn compute_dca_average_price_via_from( &mut self, max_from: DateIndex, stacks: &impl IterableVec, @@ -196,11 +201,11 @@ impl ComputeDCAAveragePriceViaLen for EagerVec> { .enumerate() .skip(index.to_usize()) .try_for_each(|(i, stack)| { - let mut avg_price = Dollars::from(f64::NAN); + let mut average_price = Dollars::from(f64::NAN); if i >= from { - avg_price = DCA_AMOUNT * (i.to_usize() + 1 - from) / Bitcoin::from(stack); + average_price = DCA_AMOUNT * (i.to_usize() + 1 - from) / Bitcoin::from(stack); } - self.truncate_push_at(i, avg_price) + self.truncate_push_at(i, average_price) })?; let _lock = exit.lock(); diff --git a/crates/brk_computer/src/traits/pricing.rs b/crates/brk_computer/src/traits/pricing.rs new file mode 100644 index 000000000..31ccbebe2 --- /dev/null +++ b/crates/brk_computer/src/traits/pricing.rs @@ -0,0 +1,123 @@ +//! Compile-time type-state for price-dependent data. +//! +// TODO: Remove this once Phase 3 (Pricing migration) is complete +#![allow(dead_code)] +//! +//! This module provides the `Pricing` trait which enables compile-time +//! differentiation between priced and unpriced data variants. Instead of +//! using `Option` for price-dependent fields, structs use `P: Pricing` +//! with associated types that are either concrete types (for `Priced`) or +//! `()` (for `Unpriced`). +//! +//! Benefits: +//! - LSP/autocomplete visibility: no Options cluttering suggestions +//! - Compile-time guarantees: cannot access price data on `Unpriced` variants +//! - Zero runtime overhead: `()` is a ZST (zero-sized type) + +use brk_traversable::Traversable; + +/// Type-state trait for price-dependent data. +/// +/// Implements the type-state pattern using associated types: +/// - `Priced`: associated types resolve to concrete data types +/// - `Unpriced`: associated types resolve to `()` +/// +/// # Associated Types +/// +/// | Type | Usage | Priced | Unpriced | +/// |------|-------|--------|----------| +/// | `Data` | Computer top-level | `PricingData` | `()` | +/// | `PriceRef<'a>` | Function params | `&price::Vecs` | `()` | +/// | `ComputedDollarsHeight` | Value wrappers (Height) | `ComputedBlock` | `()` | +/// | `ComputedDollarsDateIndex` | Value wrappers (DateIndex) | `ComputedVecsDate` | `()` | +/// | `StdDevBandsUsd` | StdDev USD bands | `StdDevBandsUsdData` | `()` | +/// | `RatioUsd` | Ratio USD variants | `RatioUsdData` | `()` | +/// | `BasePriced` | Base metrics | `BasePricedData` | `()` | +/// | `ExtendedPriced` | Extended metrics | `ExtendedPricedData` | `()` | +/// | `AdjustedPriced` | Adjusted metrics | `AdjustedPricedData` | `()` | +/// | `RelToAllPriced` | Rel-to-all metrics | `RelToAllPricedData` | `()` | +pub trait Pricing: 'static + Clone + Send + Sync { + // === Top-level === + + /// Top-level pricing data - PricingData for Priced, () for Unpriced + type Data: Clone + Send + Sync + Traversable; + + /// Reference to price vecs for import functions + type PriceRef<'a>: Copy; + + // === Value wrappers (used in 20+ places) === + + /// Computed dollars with Height index + type ComputedDollarsHeight: Clone + Send + Sync + Traversable; + + /// Computed dollars with DateIndex index + type ComputedDollarsDateIndex: Clone + Send + Sync + Traversable; + + // === Specialized structs === + + /// StdDev USD bands (13 fields grouped) + type StdDevBandsUsd: Clone + Send + Sync + Traversable; + + /// Ratio USD data + type RatioUsd: Clone + Send + Sync + Traversable; + + // === Distribution metrics === + + /// Base-level priced metrics (realized + unrealized) + type BasePriced: Clone + Send + Sync + Traversable; + + /// Extended-level priced metrics + type ExtendedPriced: Clone + Send + Sync + Traversable; + + /// Adjusted metrics + type AdjustedPriced: Clone + Send + Sync + Traversable; + + /// Dollar-based relative-to-all metrics + type RelToAllPriced: Clone + Send + Sync + Traversable; +} + +/// Marker type for priced data. +/// +/// When `P = Priced`, all associated types resolve to their concrete +/// data types containing price-denominated values. +#[derive(Clone, Copy, Default, Debug)] +pub struct Priced; + +/// Marker type for unpriced data. +/// +/// When `P = Unpriced`, all associated types resolve to `()`, +/// effectively removing those fields at compile time with zero overhead. +#[derive(Clone, Copy, Default, Debug)] +pub struct Unpriced; + +// Note: The actual type implementations for `Priced` and `Unpriced` +// will be added in Phase 3 when we migrate the concrete data types. +// For now, we provide placeholder implementations using () for all types +// to allow incremental migration. + +impl Pricing for Priced { + // Placeholder implementations - will be replaced with concrete types in Phase 3 + type Data = (); + type PriceRef<'a> = (); + type ComputedDollarsHeight = (); + type ComputedDollarsDateIndex = (); + type StdDevBandsUsd = (); + type RatioUsd = (); + type BasePriced = (); + type ExtendedPriced = (); + type AdjustedPriced = (); + type RelToAllPriced = (); +} + +impl Pricing for Unpriced { + type Data = (); + type PriceRef<'a> = (); + type ComputedDollarsHeight = (); + type ComputedDollarsDateIndex = (); + type StdDevBandsUsd = (); + type RatioUsd = (); + type BasePriced = (); + type ExtendedPriced = (); + type AdjustedPriced = (); + type RelToAllPriced = (); +} diff --git a/crates/brk_computer/src/transactions/compute.rs b/crates/brk_computer/src/transactions/compute.rs index 99eaa1600..0a29a2763 100644 --- a/crates/brk_computer/src/transactions/compute.rs +++ b/crates/brk_computer/src/transactions/compute.rs @@ -37,7 +37,6 @@ impl Vecs { inputs, &self.size, starting_indexes, - price, exit, )?; diff --git a/crates/brk_computer/src/transactions/count/import.rs b/crates/brk_computer/src/transactions/count/import.rs index 8345224ff..612d581ca 100644 --- a/crates/brk_computer/src/transactions/count/import.rs +++ b/crates/brk_computer/src/transactions/count/import.rs @@ -6,7 +6,7 @@ use vecdb::{Database, IterableCloneableVec, LazyVecFrom2}; use super::Vecs; use crate::{ indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, + internal::ComputedBlockFull, }; impl Vecs { @@ -16,15 +16,6 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; - let txindex_to_is_coinbase = LazyVecFrom2::init( "is_coinbase", version, @@ -39,13 +30,11 @@ impl Vecs { ); Ok(Self { - indexes_to_tx_count: ComputedVecsFromHeight::forced_import( + indexes_to_tx_count: ComputedBlockFull::forced_import( db, "tx_count", - Source::Compute, version, indexes, - full_stats(), )?, txindex_to_is_coinbase, }) diff --git a/crates/brk_computer/src/transactions/count/vecs.rs b/crates/brk_computer/src/transactions/count/vecs.rs index b1c5e30e2..3262e01cd 100644 --- a/crates/brk_computer/src/transactions/count/vecs.rs +++ b/crates/brk_computer/src/transactions/count/vecs.rs @@ -2,10 +2,10 @@ use brk_traversable::Traversable; use brk_types::{Height, StoredBool, StoredU64, TxIndex}; use vecdb::LazyVecFrom2; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::ComputedBlockFull; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_tx_count: ComputedVecsFromHeight, + pub indexes_to_tx_count: ComputedBlockFull, pub txindex_to_is_coinbase: LazyVecFrom2, } diff --git a/crates/brk_computer/src/transactions/fees/compute.rs b/crates/brk_computer/src/transactions/fees/compute.rs index ef3682c1c..21b83987f 100644 --- a/crates/brk_computer/src/transactions/fees/compute.rs +++ b/crates/brk_computer/src/transactions/fees/compute.rs @@ -5,7 +5,7 @@ use vecdb::{Exit, unlikely}; use super::Vecs; use super::super::size; -use crate::{indexes, inputs, price, ComputeIndexes}; +use crate::{indexes, inputs, ComputeIndexes}; impl Vecs { #[allow(clippy::too_many_arguments)] @@ -16,7 +16,6 @@ impl Vecs { txins: &inputs::Vecs, size_vecs: &size::Vecs, starting_indexes: &ComputeIndexes, - price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { self.txindex_to_input_value.compute_sum_from_indexes( @@ -58,21 +57,20 @@ impl Vecs { exit, )?; - self.indexes_to_fee.compute_rest( + self.indexes_to_fee.derive_from( indexer, indexes, starting_indexes, + &self.txindex_to_fee, exit, - Some(&self.txindex_to_fee), - price, )?; - self.indexes_to_fee_rate.compute_rest( + self.indexes_to_fee_rate.derive_from( indexer, indexes, starting_indexes, + &self.txindex_to_fee_rate, exit, - Some(&self.txindex_to_fee_rate), )?; Ok(()) diff --git a/crates/brk_computer/src/transactions/fees/import.rs b/crates/brk_computer/src/transactions/fees/import.rs index 6cacfda1e..2fc725cff 100644 --- a/crates/brk_computer/src/transactions/fees/import.rs +++ b/crates/brk_computer/src/transactions/fees/import.rs @@ -1,12 +1,12 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_types::Version; -use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec}; +use vecdb::{Database, EagerVec, ImportableVec}; use super::Vecs; use crate::{ indexes, - internal::{ComputedValueVecsFromTxindex, ComputedVecsFromTxindex, Source, VecBuilderOptions}, + internal::{ComputedTxDistribution, ValueDerivedTxFull}, price, }; @@ -18,13 +18,6 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, ) -> Result { - let stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - }; - let txindex_to_input_value = EagerVec::forced_import(db, "input_value", version)?; let txindex_to_output_value = EagerVec::forced_import(db, "output_value", version)?; let txindex_to_fee = EagerVec::forced_import(db, "fee", version)?; @@ -35,28 +28,20 @@ impl Vecs { txindex_to_output_value, txindex_to_fee: txindex_to_fee.clone(), txindex_to_fee_rate: txindex_to_fee_rate.clone(), - indexes_to_fee: ComputedValueVecsFromTxindex::forced_import( + indexes_to_fee: ValueDerivedTxFull::forced_import( db, "fee", - indexer, - indexes, - Source::Vec(txindex_to_fee.boxed_clone()), version, + indexes, + indexer, price, - VecBuilderOptions::default() - .add_sum() - .add_cumulative() - .add_percentiles() - .add_minmax() - .add_average(), + &txindex_to_fee, )?, - indexes_to_fee_rate: ComputedVecsFromTxindex::forced_import( + indexes_to_fee_rate: ComputedTxDistribution::forced_import( db, "fee_rate", - Source::Vec(txindex_to_fee_rate.boxed_clone()), version, indexes, - stats(), )?, }) } diff --git a/crates/brk_computer/src/transactions/fees/vecs.rs b/crates/brk_computer/src/transactions/fees/vecs.rs index f5fca6697..04899e2db 100644 --- a/crates/brk_computer/src/transactions/fees/vecs.rs +++ b/crates/brk_computer/src/transactions/fees/vecs.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::{FeeRate, Sats, TxIndex}; use vecdb::{EagerVec, PcoVec}; -use crate::internal::{ComputedValueVecsFromTxindex, ComputedVecsFromTxindex}; +use crate::internal::{ComputedTxDistribution, ValueDerivedTxFull}; #[derive(Clone, Traversable)] pub struct Vecs { @@ -10,6 +10,6 @@ pub struct Vecs { pub txindex_to_output_value: EagerVec>, pub txindex_to_fee: EagerVec>, pub txindex_to_fee_rate: EagerVec>, - pub indexes_to_fee: ComputedValueVecsFromTxindex, - pub indexes_to_fee_rate: ComputedVecsFromTxindex, + pub indexes_to_fee: ValueDerivedTxFull, + pub indexes_to_fee_rate: ComputedTxDistribution, } diff --git a/crates/brk_computer/src/transactions/size/compute.rs b/crates/brk_computer/src/transactions/size/compute.rs index ec89eef25..74c5fb160 100644 --- a/crates/brk_computer/src/transactions/size/compute.rs +++ b/crates/brk_computer/src/transactions/size/compute.rs @@ -13,20 +13,20 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.indexes_to_tx_weight.compute_rest( + self.indexes_to_tx_weight.derive_from( indexer, indexes, starting_indexes, + &self.txindex_to_weight, exit, - Some(&self.txindex_to_weight), )?; - self.indexes_to_tx_vsize.compute_rest( + self.indexes_to_tx_vsize.derive_from( indexer, indexes, starting_indexes, + &self.txindex_to_vsize, exit, - Some(&self.txindex_to_vsize), )?; Ok(()) diff --git a/crates/brk_computer/src/transactions/size/import.rs b/crates/brk_computer/src/transactions/size/import.rs index 95319b21d..fbc5c4970 100644 --- a/crates/brk_computer/src/transactions/size/import.rs +++ b/crates/brk_computer/src/transactions/size/import.rs @@ -4,10 +4,7 @@ use brk_types::{TxIndex, VSize, Version, Weight}; use vecdb::{Database, IterableCloneableVec, LazyVecFrom2, VecIndex}; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromTxindex, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedTxDistribution}; impl Vecs { pub fn forced_import( @@ -16,13 +13,6 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - }; - let txindex_to_weight = LazyVecFrom2::init( "weight", version, @@ -52,23 +42,15 @@ impl Vecs { }, ); + let indexes_to_tx_vsize = + ComputedTxDistribution::forced_import(db, "tx_vsize", version, indexes)?; + + let indexes_to_tx_weight = + ComputedTxDistribution::forced_import(db, "tx_weight", version, indexes)?; + Ok(Self { - indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import( - db, - "tx_vsize", - Source::Vec(txindex_to_vsize.boxed_clone()), - version, - indexes, - stats(), - )?, - indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import( - db, - "tx_weight", - Source::Vec(txindex_to_weight.boxed_clone()), - version, - indexes, - stats(), - )?, + indexes_to_tx_vsize, + indexes_to_tx_weight, txindex_to_vsize, txindex_to_weight, }) diff --git a/crates/brk_computer/src/transactions/size/vecs.rs b/crates/brk_computer/src/transactions/size/vecs.rs index d4a49c568..34353ae32 100644 --- a/crates/brk_computer/src/transactions/size/vecs.rs +++ b/crates/brk_computer/src/transactions/size/vecs.rs @@ -2,12 +2,12 @@ use brk_traversable::Traversable; use brk_types::{StoredU32, TxIndex, VSize, Weight}; use vecdb::LazyVecFrom2; -use crate::internal::ComputedVecsFromTxindex; +use crate::internal::ComputedTxDistribution; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_tx_vsize: ComputedVecsFromTxindex, - pub indexes_to_tx_weight: ComputedVecsFromTxindex, + pub indexes_to_tx_vsize: ComputedTxDistribution, + pub indexes_to_tx_weight: ComputedTxDistribution, // Both derive directly from eager sources (base_size, total_size) to avoid Lazy <- Lazy pub txindex_to_vsize: LazyVecFrom2, pub txindex_to_weight: LazyVecFrom2, diff --git a/crates/brk_computer/src/transactions/versions/compute.rs b/crates/brk_computer/src/transactions/versions/compute.rs index 7866ae3fb..10382fdf3 100644 --- a/crates/brk_computer/src/transactions/versions/compute.rs +++ b/crates/brk_computer/src/transactions/versions/compute.rs @@ -4,7 +4,7 @@ use brk_types::{StoredU64, TxVersion}; use vecdb::{Exit, TypedVecIterator}; use super::Vecs; -use crate::{indexes, internal::ComputedVecsFromHeight, ComputeIndexes}; +use crate::{indexes, internal::ComputedBlockSumCum, ComputeIndexes}; impl Vecs { pub fn compute( @@ -15,7 +15,7 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let compute_indexes_to_tx_vany = - |indexes_to_tx_vany: &mut ComputedVecsFromHeight, txversion: TxVersion| { + |indexes_to_tx_vany: &mut ComputedBlockSumCum, txversion: TxVersion| { let mut txindex_to_txversion_iter = indexer.vecs.tx.txindex_to_txversion.iter()?; indexes_to_tx_vany.compute_all(indexes, starting_indexes, exit, |vec| { vec.compute_filtered_count_from_indexes( diff --git a/crates/brk_computer/src/transactions/versions/import.rs b/crates/brk_computer/src/transactions/versions/import.rs index 6857ad1e0..84500c1e9 100644 --- a/crates/brk_computer/src/transactions/versions/import.rs +++ b/crates/brk_computer/src/transactions/versions/import.rs @@ -3,39 +3,28 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{ - indexes, - internal::{ComputedVecsFromHeight, Source, VecBuilderOptions}, -}; +use crate::{indexes, internal::ComputedBlockSumCum}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { - let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); - Ok(Self { - indexes_to_tx_v1: ComputedVecsFromHeight::forced_import( + indexes_to_tx_v1: ComputedBlockSumCum::forced_import( db, "tx_v1", - Source::Compute, version, indexes, - sum_cum(), )?, - indexes_to_tx_v2: ComputedVecsFromHeight::forced_import( + indexes_to_tx_v2: ComputedBlockSumCum::forced_import( db, "tx_v2", - Source::Compute, version, indexes, - sum_cum(), )?, - indexes_to_tx_v3: ComputedVecsFromHeight::forced_import( + indexes_to_tx_v3: ComputedBlockSumCum::forced_import( db, "tx_v3", - Source::Compute, version, indexes, - sum_cum(), )?, }) } diff --git a/crates/brk_computer/src/transactions/versions/vecs.rs b/crates/brk_computer/src/transactions/versions/vecs.rs index acb9e4243..b7b4be019 100644 --- a/crates/brk_computer/src/transactions/versions/vecs.rs +++ b/crates/brk_computer/src/transactions/versions/vecs.rs @@ -1,11 +1,11 @@ use brk_traversable::Traversable; use brk_types::StoredU64; -use crate::internal::ComputedVecsFromHeight; +use crate::internal::ComputedBlockSumCum; #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_tx_v1: ComputedVecsFromHeight, - pub indexes_to_tx_v2: ComputedVecsFromHeight, - pub indexes_to_tx_v3: ComputedVecsFromHeight, + pub indexes_to_tx_v1: ComputedBlockSumCum, + pub indexes_to_tx_v2: ComputedBlockSumCum, + pub indexes_to_tx_v3: ComputedBlockSumCum, } diff --git a/crates/brk_computer/src/transactions/volume/compute.rs b/crates/brk_computer/src/transactions/volume/compute.rs index db16c2089..6793ebd41 100644 --- a/crates/brk_computer/src/transactions/volume/compute.rs +++ b/crates/brk_computer/src/transactions/volume/compute.rs @@ -34,46 +34,42 @@ impl Vecs { Ok(()) })?; - self.indexes_to_annualized_volume - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_sent_sum.sats.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; + self.indexes_to_annualized_volume.compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + &self.indexes_to_sent_sum.sats.dateindex.0, + 365, + exit, + )?; + Ok(()) + })?; - self.indexes_to_annualized_volume_btc - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_sent_sum.bitcoin.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; + self.indexes_to_annualized_volume_btc.compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + &*self.indexes_to_sent_sum.bitcoin.dateindex, + 365, + exit, + )?; + Ok(()) + })?; if let Some(indexes_to_sent_sum) = self.indexes_to_sent_sum.dollars.as_ref() { - self.indexes_to_annualized_volume_usd - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - indexes_to_sent_sum.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; + self.indexes_to_annualized_volume_usd.compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + &indexes_to_sent_sum.dateindex.0, + 365, + exit, + )?; + Ok(()) + })?; } - self.indexes_to_tx_per_sec - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_tx_per_sec.compute_all(starting_indexes, exit, |v| { v.compute_transform2( starting_indexes.dateindex, - count_vecs.indexes_to_tx_count.dateindex.unwrap_sum(), + &count_vecs.indexes_to_tx_count.dateindex.sum_cum.sum.0, &indexes.time.dateindex_to_date, |(i, tx_count, date, ..)| { let completion = date.completion(); @@ -89,11 +85,10 @@ impl Vecs { Ok(()) })?; - self.indexes_to_inputs_per_sec - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_inputs_per_sec.compute_all(starting_indexes, exit, |v| { v.compute_transform2( starting_indexes.dateindex, - inputs_count.indexes_to_count.dateindex.unwrap_sum(), + &inputs_count.indexes_to_count.dateindex.sum_cum.sum.0, &indexes.time.dateindex_to_date, |(i, input_count, date, ..)| { let completion = date.completion(); @@ -109,11 +104,10 @@ impl Vecs { Ok(()) })?; - self.indexes_to_outputs_per_sec - .compute_all(starting_indexes, exit, |v| { + self.indexes_to_outputs_per_sec.compute_all(starting_indexes, exit, |v| { v.compute_transform2( starting_indexes.dateindex, - outputs_count.indexes_to_count.dateindex.unwrap_sum(), + &outputs_count.indexes_to_count.dateindex.sum_cum.sum.0, &indexes.time.dateindex_to_date, |(i, output_count, date, ..)| { let completion = date.completion(); diff --git a/crates/brk_computer/src/transactions/volume/import.rs b/crates/brk_computer/src/transactions/volume/import.rs index 14ce7a1f5..738d74491 100644 --- a/crates/brk_computer/src/transactions/volume/import.rs +++ b/crates/brk_computer/src/transactions/volume/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, Source, VecBuilderOptions}, + internal::{ComputedDateLast, ValueBlockSum}, }; impl Vecs { @@ -16,65 +16,50 @@ impl Vecs { compute_dollars: bool, ) -> Result { let v2 = Version::TWO; - let last = || VecBuilderOptions::default().add_last(); Ok(Self { - indexes_to_sent_sum: ComputedValueVecsFromHeight::forced_import( + indexes_to_sent_sum: ValueBlockSum::forced_import( db, "sent_sum", - Source::Compute, version, - VecBuilderOptions::default().add_sum(), - compute_dollars, indexes, + compute_dollars, )?, - indexes_to_annualized_volume: ComputedVecsFromDateIndex::forced_import( + indexes_to_annualized_volume: ComputedDateLast::forced_import( db, "annualized_volume", - Source::Compute, version, indexes, - last(), )?, - indexes_to_annualized_volume_btc: ComputedVecsFromDateIndex::forced_import( + indexes_to_annualized_volume_btc: ComputedDateLast::forced_import( db, "annualized_volume_btc", - Source::Compute, version, indexes, - last(), )?, - indexes_to_annualized_volume_usd: ComputedVecsFromDateIndex::forced_import( + indexes_to_annualized_volume_usd: ComputedDateLast::forced_import( db, "annualized_volume_usd", - Source::Compute, version, indexes, - last(), )?, - indexes_to_tx_per_sec: ComputedVecsFromDateIndex::forced_import( + indexes_to_tx_per_sec: ComputedDateLast::forced_import( db, "tx_per_sec", - Source::Compute, version + v2, indexes, - last(), )?, - indexes_to_outputs_per_sec: ComputedVecsFromDateIndex::forced_import( + indexes_to_outputs_per_sec: ComputedDateLast::forced_import( db, "outputs_per_sec", - Source::Compute, version + v2, indexes, - last(), )?, - indexes_to_inputs_per_sec: ComputedVecsFromDateIndex::forced_import( + indexes_to_inputs_per_sec: ComputedDateLast::forced_import( db, "inputs_per_sec", - Source::Compute, version + v2, indexes, - last(), )?, }) } diff --git a/crates/brk_computer/src/transactions/volume/vecs.rs b/crates/brk_computer/src/transactions/volume/vecs.rs index b02d521c5..0cef141c5 100644 --- a/crates/brk_computer/src/transactions/volume/vecs.rs +++ b/crates/brk_computer/src/transactions/volume/vecs.rs @@ -1,16 +1,16 @@ use brk_traversable::Traversable; use brk_types::{Bitcoin, Dollars, Sats, StoredF32}; -use crate::internal::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex}; +use crate::internal::{ComputedDateLast, ValueBlockSum}; /// Volume metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub indexes_to_sent_sum: ComputedValueVecsFromHeight, - pub indexes_to_annualized_volume: ComputedVecsFromDateIndex, - pub indexes_to_annualized_volume_btc: ComputedVecsFromDateIndex, - pub indexes_to_annualized_volume_usd: ComputedVecsFromDateIndex, - pub indexes_to_tx_per_sec: ComputedVecsFromDateIndex, - pub indexes_to_outputs_per_sec: ComputedVecsFromDateIndex, - pub indexes_to_inputs_per_sec: ComputedVecsFromDateIndex, + pub indexes_to_sent_sum: ValueBlockSum, + pub indexes_to_annualized_volume: ComputedDateLast, + pub indexes_to_annualized_volume_btc: ComputedDateLast, + pub indexes_to_annualized_volume_usd: ComputedDateLast, + pub indexes_to_tx_per_sec: ComputedDateLast, + pub indexes_to_outputs_per_sec: ComputedDateLast, + pub indexes_to_inputs_per_sec: ComputedDateLast, } diff --git a/crates/brk_mempool/Cargo.toml b/crates/brk_mempool/Cargo.toml index cac0c637a..661d20b1c 100644 --- a/crates/brk_mempool/Cargo.toml +++ b/crates/brk_mempool/Cargo.toml @@ -12,7 +12,7 @@ build = "build.rs" brk_error = { workspace = true } brk_rpc = { workspace = true } brk_types = { workspace = true } -derive_deref = { workspace = true } +derive_more = { workspace = true } log = { workspace = true } parking_lot = { workspace = true } rustc-hash = { workspace = true } diff --git a/crates/brk_mempool/src/addresses.rs b/crates/brk_mempool/src/addresses.rs index b4886fd22..0b3325e51 100644 --- a/crates/brk_mempool/src/addresses.rs +++ b/crates/brk_mempool/src/addresses.rs @@ -1,23 +1,14 @@ -use std::ops::Deref; - use brk_types::{AddressBytes, AddressMempoolStats, Transaction, Txid}; +use derive_more::Deref; use rustc_hash::{FxHashMap, FxHashSet}; /// Per-address stats with associated transaction set. pub type AddressStats = (AddressMempoolStats, FxHashSet); /// Tracks per-address mempool statistics. -#[derive(Default)] +#[derive(Default, Deref)] pub struct AddressTracker(FxHashMap); -impl Deref for AddressTracker { - type Target = FxHashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - impl AddressTracker { /// Add a transaction to address tracking. pub fn add_tx(&mut self, tx: &Transaction, txid: &Txid) { diff --git a/crates/brk_mempool/src/sync.rs b/crates/brk_mempool/src/sync.rs index d89c1808e..0360bfae8 100644 --- a/crates/brk_mempool/src/sync.rs +++ b/crates/brk_mempool/src/sync.rs @@ -10,7 +10,7 @@ use std::{ use brk_error::Result; use brk_rpc::Client; use brk_types::{MempoolEntryInfo, MempoolInfo, TxWithHex, Txid, TxidPrefix}; -use derive_deref::Deref; +use derive_more::Deref; use log::error; use parking_lot::{RwLock, RwLockReadGuard}; use rustc_hash::FxHashMap; diff --git a/crates/brk_mempool/src/tx_store.rs b/crates/brk_mempool/src/tx_store.rs index 726582cfc..7b2bdaf66 100644 --- a/crates/brk_mempool/src/tx_store.rs +++ b/crates/brk_mempool/src/tx_store.rs @@ -1,20 +1,11 @@ -use std::ops::Deref; - use brk_types::{TxWithHex, Txid}; +use derive_more::Deref; use rustc_hash::FxHashMap; /// Store of full transaction data for API access. -#[derive(Default)] +#[derive(Default, Deref)] pub struct TxStore(FxHashMap); -impl Deref for TxStore { - type Target = FxHashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - impl TxStore { /// Check if a transaction exists. pub fn contains(&self, txid: &Txid) -> bool { diff --git a/crates/brk_query/Cargo.toml b/crates/brk_query/Cargo.toml index 9f0fb7cea..54953618a 100644 --- a/crates/brk_query/Cargo.toml +++ b/crates/brk_query/Cargo.toml @@ -21,7 +21,7 @@ brk_reader = { workspace = true } brk_rpc = { workspace = true } brk_traversable = { workspace = true } brk_types = { workspace = true } -derive_deref = { workspace = true } +derive_more = { workspace = true } jiff = { workspace = true } # quickmatch = { path = "../../../quickmatch" } quickmatch = "0.1.8" diff --git a/crates/brk_query/src/impl/mining/block_fees.rs b/crates/brk_query/src/impl/mining/block_fees.rs index 4014f36c5..bfacd0169 100644 --- a/crates/brk_query/src/impl/mining/block_fees.rs +++ b/crates/brk_query/src/impl/mining/block_fees.rs @@ -15,13 +15,15 @@ impl Query { let iter = DateIndexIter::new(computer, start, current_height.to_usize()); + // KISS: dateindex.average.0 is now a concrete field let mut fees = computer .transactions .fees .indexes_to_fee .sats .dateindex - .unwrap_average() + .average + .0 .iter(); Ok(iter.collect(|di, ts, h| { diff --git a/crates/brk_query/src/impl/mining/block_rewards.rs b/crates/brk_query/src/impl/mining/block_rewards.rs index 84db5a3fd..9281bb914 100644 --- a/crates/brk_query/src/impl/mining/block_rewards.rs +++ b/crates/brk_query/src/impl/mining/block_rewards.rs @@ -16,13 +16,16 @@ impl Query { let iter = DateIndexIter::new(computer, start, current_height.to_usize()); // coinbase = subsidy + fees + // KISS: dateindex.distribution.average.0 is now a concrete field let mut rewards = computer .blocks .rewards .indexes_to_coinbase .sats .dateindex - .unwrap_average() + .distribution + .average + .0 .iter(); Ok(iter.collect(|di, ts, h| { diff --git a/crates/brk_query/src/impl/mining/block_sizes.rs b/crates/brk_query/src/impl/mining/block_sizes.rs index 568c739e8..2ba174a6d 100644 --- a/crates/brk_query/src/impl/mining/block_sizes.rs +++ b/crates/brk_query/src/impl/mining/block_sizes.rs @@ -20,14 +20,18 @@ impl Query { .size .indexes_to_block_size .dateindex - .unwrap_average() + .distribution + .average + .0 .iter(); let mut weights_vec = computer .blocks .weight .indexes_to_block_weight .dateindex - .unwrap_average() + .distribution + .average + .0 .iter(); let entries: Vec<_> = iter.collect(|di, ts, h| { diff --git a/crates/brk_query/src/impl/mining/dateindex_iter.rs b/crates/brk_query/src/impl/mining/dateindex_iter.rs index cece78765..ec9247c2d 100644 --- a/crates/brk_query/src/impl/mining/dateindex_iter.rs +++ b/crates/brk_query/src/impl/mining/dateindex_iter.rs @@ -52,8 +52,6 @@ impl<'a> DateIndexIter<'a> { .time .timeindexes_to_timestamp .dateindex - .as_ref() - .expect("timeindexes_to_timestamp.dateindex should exist") .iter(); let mut heights = self.computer.indexes.time.dateindex_to_first_height.iter(); diff --git a/crates/brk_query/src/impl/mining/epochs.rs b/crates/brk_query/src/impl/mining/epochs.rs index 6c93dad21..a058b4f93 100644 --- a/crates/brk_query/src/impl/mining/epochs.rs +++ b/crates/brk_query/src/impl/mining/epochs.rs @@ -21,14 +21,17 @@ pub fn iter_difficulty_epochs( .read_once(Height::from(end_height)) .unwrap_or_default(); - let mut epoch_to_height_iter = computer.indexes.block.difficultyepoch_to_first_height.iter(); + let mut epoch_to_height_iter = computer + .indexes + .block + .difficultyepoch_to_first_height + .iter(); let mut epoch_to_timestamp_iter = computer.blocks.time.difficultyepoch_to_timestamp.iter(); let mut epoch_to_difficulty_iter = computer .blocks .mining .indexes_to_difficulty .difficultyepoch - .unwrap_last() .iter(); let mut results = Vec::with_capacity(end_epoch.to_usize() - start_epoch.to_usize() + 1); diff --git a/crates/brk_query/src/impl/mining/hashrate.rs b/crates/brk_query/src/impl/mining/hashrate.rs index 57445f7c6..2913f4888 100644 --- a/crates/brk_query/src/impl/mining/hashrate.rs +++ b/crates/brk_query/src/impl/mining/hashrate.rs @@ -30,7 +30,6 @@ impl Query { .mining .indexes_to_hash_rate .dateindex - .unwrap_last() .read_once(current_dateindex)? as u128; // Calculate start height based on time period @@ -61,7 +60,6 @@ impl Query { .mining .indexes_to_hash_rate .dateindex - .unwrap_last() .iter(); let mut timestamp_iter = computer @@ -69,8 +67,6 @@ impl Query { .time .timeindexes_to_timestamp .dateindex - .as_ref() - .expect("timeindexes_to_timestamp.dateindex should exist") .iter(); let mut hashrates = Vec::with_capacity(total_days / step + 1); diff --git a/crates/brk_query/src/impl/mining/pools.rs b/crates/brk_query/src/impl/mining/pools.rs index 48e71e20b..6c76d2026 100644 --- a/crates/brk_query/src/impl/mining/pools.rs +++ b/crates/brk_query/src/impl/mining/pools.rs @@ -32,8 +32,8 @@ impl Query { for (pool_id, pool_vecs) in &computer.pools.vecs { let mut cumulative = pool_vecs .indexes_to_blocks_mined - .height_extra - .unwrap_cumulative() + .height_cumulative + .inner() .iter(); let count_at_end: u32 = *cumulative.get(current_height).unwrap_or_default(); @@ -102,8 +102,8 @@ impl Query { let mut cumulative = pool_vecs .indexes_to_blocks_mined - .height_extra - .unwrap_cumulative() + .height_cumulative + .inner() .iter(); // Get total blocks (all time) diff --git a/crates/brk_query/src/impl/mining/reward_stats.rs b/crates/brk_query/src/impl/mining/reward_stats.rs index e3d1d2342..f0eb2281a 100644 --- a/crates/brk_query/src/impl/mining/reward_stats.rs +++ b/crates/brk_query/src/impl/mining/reward_stats.rs @@ -12,30 +12,30 @@ impl Query { let end_block = current_height; let start_block = Height::from(current_height.to_usize().saturating_sub(block_count - 1)); + // KISS: height is now a concrete field (no Option) let mut coinbase_iter = computer .blocks .rewards .indexes_to_coinbase .sats .height - .as_ref() - .unwrap() .iter(); + // KISS: height.sum_cum.sum.0 is now a concrete field let mut fee_iter = computer .transactions .fees .indexes_to_fee .sats .height - .unwrap_sum() + .sum_cum + .sum + .0 .iter(); let mut tx_count_iter = computer .transactions .count .indexes_to_tx_count .height - .as_ref() - .unwrap() .iter(); let mut total_reward = Sats::ZERO; diff --git a/crates/brk_query/src/vecs.rs b/crates/brk_query/src/vecs.rs index 40a1657ef..f57b0f004 100644 --- a/crates/brk_query/src/vecs.rs +++ b/crates/brk_query/src/vecs.rs @@ -3,8 +3,10 @@ use std::{borrow::Cow, collections::BTreeMap}; use brk_computer::Computer; use brk_indexer::Indexer; use brk_traversable::{Traversable, TreeNode}; -use brk_types::{Index, IndexInfo, Limit, Metric, MetricCount, PaginatedMetrics, Pagination, PaginationIndex}; -use derive_deref::{Deref, DerefMut}; +use brk_types::{ + Index, IndexInfo, Limit, Metric, MetricCount, PaginatedMetrics, Pagination, PaginationIndex, +}; +use derive_more::{Deref, DerefMut}; use quickmatch::{QuickMatch, QuickMatchConfig}; use vecdb::AnyExportableVec; @@ -67,8 +69,7 @@ impl<'a> Vecs<'a> { .flat_map(|tree| tree.values()) .filter(|vec| vec.region_names().is_empty()) .count(); - this.counts.stored_endpoints = - this.counts.total_endpoints - this.counts.lazy_endpoints; + this.counts.stored_endpoints = this.counts.total_endpoints - this.counts.lazy_endpoints; this.indexes = this .index_to_metric_to_vec .keys() diff --git a/crates/brk_reader/Cargo.toml b/crates/brk_reader/Cargo.toml index 7ff55d418..0a403cb26 100644 --- a/crates/brk_reader/Cargo.toml +++ b/crates/brk_reader/Cargo.toml @@ -16,7 +16,7 @@ brk_error = { workspace = true } brk_rpc = { workspace = true } brk_types = { workspace = true } crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] } -derive_deref = { workspace = true } +derive_more = { workspace = true } log = { workspace = true } parking_lot = { workspace = true } rayon = { workspace = true } diff --git a/crates/brk_reader/src/blk_index_to_blk_path.rs b/crates/brk_reader/src/blk_index_to_blk_path.rs index c94619c91..2572a7a72 100644 --- a/crates/brk_reader/src/blk_index_to_blk_path.rs +++ b/crates/brk_reader/src/blk_index_to_blk_path.rs @@ -4,7 +4,7 @@ use std::{ path::{Path, PathBuf}, }; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; const BLK: &str = "blk"; const DOT_DAT: &str = ".dat"; diff --git a/crates/brk_reader/src/lib.rs b/crates/brk_reader/src/lib.rs index 96ed13e3d..6decf6d24 100644 --- a/crates/brk_reader/src/lib.rs +++ b/crates/brk_reader/src/lib.rs @@ -19,7 +19,7 @@ use brk_rpc::Client; use brk_types::{BlkMetadata, BlkPosition, BlockHash, Height, ReadBlock}; pub use crossbeam::channel::Receiver; use crossbeam::channel::bounded; -use derive_deref::Deref; +use derive_more::Deref; use log::error; use parking_lot::{RwLock, RwLockReadGuard}; use rayon::prelude::*; diff --git a/crates/brk_reader/src/xor_bytes.rs b/crates/brk_reader/src/xor_bytes.rs index 3747ace0d..5f9820272 100644 --- a/crates/brk_reader/src/xor_bytes.rs +++ b/crates/brk_reader/src/xor_bytes.rs @@ -1,6 +1,6 @@ use std::{fs, path::Path}; -use derive_deref::Deref; +use derive_more::Deref; pub const XOR_LEN: usize = 8; diff --git a/crates/brk_server/Cargo.toml b/crates/brk_server/Cargo.toml index d7fa60c6d..ebe39d7ac 100644 --- a/crates/brk_server/Cargo.toml +++ b/crates/brk_server/Cargo.toml @@ -23,6 +23,7 @@ brk_reader = { workspace = true } brk_rpc = { workspace = true } brk_types = { workspace = true } brk_traversable = { workspace = true } +derive_more = { workspace = true } vecdb = { workspace = true } jiff = { workspace = true } log = { workspace = true } diff --git a/crates/brk_server/src/state.rs b/crates/brk_server/src/state.rs index a6c3244fe..027454dc5 100644 --- a/crates/brk_server/src/state.rs +++ b/crates/brk_server/src/state.rs @@ -1,4 +1,6 @@ -use std::{ops::Deref, path::PathBuf, sync::Arc}; +use std::{path::PathBuf, sync::Arc}; + +use derive_more::Deref; use axum::{ body::{Body, Bytes}, @@ -13,20 +15,14 @@ use crate::{ extended::{ResponseExtended, ResultExtended}, }; -#[derive(Clone)] +#[derive(Clone, Deref)] pub struct AppState { + #[deref] pub query: AsyncQuery, pub path: Option, pub cache: Arc>, } -impl Deref for AppState { - type Target = AsyncQuery; - fn deref(&self) -> &Self::Target { - &self.query - } -} - impl AppState { /// JSON response with caching pub async fn cached_json( diff --git a/crates/brk_store/src/lib.rs b/crates/brk_store/src/lib.rs index 1c4c97015..666cde04d 100644 --- a/crates/brk_store/src/lib.rs +++ b/crates/brk_store/src/lib.rs @@ -276,8 +276,7 @@ where ingestion.write(ByteView::from(key), ByteView::from(value))?; } Item::Tomb(key) => { - // TODO: switch to write_weak_tombstone when lsm-tree ingestion API supports it - ingestion.write_tombstone(ByteView::from(key))?; + ingestion.write_weak_tombstone(ByteView::from(key))?; } } } diff --git a/crates/brk_traversable/Cargo.toml b/crates/brk_traversable/Cargo.toml index 420f20929..1b2b88bac 100644 --- a/crates/brk_traversable/Cargo.toml +++ b/crates/brk_traversable/Cargo.toml @@ -22,3 +22,7 @@ schemars = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } vecdb = { workspace = true } + +[dev-dependencies] +brk_traversable_derive = { workspace = true } +serde_json = { workspace = true } diff --git a/crates/brk_traversable/src/lib.rs b/crates/brk_traversable/src/lib.rs index 8c4c0995f..a68d5aa90 100644 --- a/crates/brk_traversable/src/lib.rs +++ b/crates/brk_traversable/src/lib.rs @@ -228,3 +228,15 @@ impl Traversable for BTreeMap { iter } } + +/// Unit type implementation - used as ZST placeholder for disabled features +/// (e.g., Unpriced variants where dollar fields are not needed) +impl Traversable for () { + fn to_tree_node(&self) -> TreeNode { + TreeNode::Branch(BTreeMap::new()) + } + + fn iter_any_exportable(&self) -> impl Iterator { + std::iter::empty() + } +} diff --git a/crates/brk_traversable/tests/derive_tests.rs b/crates/brk_traversable/tests/derive_tests.rs new file mode 100644 index 000000000..581306754 --- /dev/null +++ b/crates/brk_traversable/tests/derive_tests.rs @@ -0,0 +1,989 @@ +//! Integration tests for the Traversable derive macro. +//! +//! Tests struct patterns similar to those in brk_computer to ensure +//! the derive macro produces correct tree structures. + +use std::collections::BTreeSet; + +use brk_traversable::{Index, MetricLeaf, MetricLeafWithSchema, Traversable, TreeNode}; +use brk_traversable_derive::Traversable; + +// ============================================================================ +// Mock vec types for testing +// ============================================================================ + +/// Mock leaf vec that produces a Leaf node with given name and index +struct MockVec { + name: String, + index: Index, +} + +impl MockVec { + fn new(name: &str, index: Index) -> Self { + Self { + name: name.to_string(), + index, + } + } +} + +impl Traversable for MockVec { + fn to_tree_node(&self) -> TreeNode { + TreeNode::Leaf(MetricLeafWithSchema::new( + MetricLeaf::new( + self.name.clone(), + "MockType".to_string(), + BTreeSet::from([self.index]), + ), + serde_json::Value::Null, + )) + } + + fn iter_any_exportable(&self) -> impl Iterator { + std::iter::empty() + } +} + +// ============================================================================ +// Helper functions +// ============================================================================ + +fn get_leaf_indexes(node: &TreeNode) -> Option<&BTreeSet> { + match node { + TreeNode::Leaf(l) => Some(l.indexes()), + _ => None, + } +} + +fn get_leaf_name(node: &TreeNode) -> Option<&str> { + match node { + TreeNode::Leaf(l) => Some(l.name()), + _ => None, + } +} + +// ============================================================================ +// Case 1: LazyBlockValue pattern +// ============================================================================ +// LazyBlockValue (no merge on struct): +// - sats: wrap="sats" +// - rest: LazyDerivedBlockValue with flatten +// - bitcoin: plain field +// - dollars: Option, plain field + +#[derive(Traversable)] +struct MockLazyDerivedBlockValue { + pub bitcoin: MockVec, + pub dollars: Option, +} + +#[derive(Traversable)] +struct MockLazyBlockValue { + #[traversable(rename = "sats")] + pub sats: MockVec, + #[traversable(flatten)] + pub rest: MockLazyDerivedBlockValue, +} + +#[test] +fn lazy_block_value_flat_denomination_siblings() { + let value = MockLazyBlockValue { + sats: MockVec::new("metric", Index::Height), + rest: MockLazyDerivedBlockValue { + bitcoin: MockVec::new("metric_btc", Index::Height), + dollars: Some(MockVec::new("metric_usd", Index::Height)), + }, + }; + + let tree = value.to_tree_node(); + + // rename="sats" keeps the leaf directly as sats: Leaf + // flatten on rest lifts bitcoin, dollars as direct leaves + // Result: { sats: Leaf, bitcoin: Leaf, dollars: Leaf } + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3, "Expected sats, bitcoin, dollars. Got: {:?}", map.keys().collect::>()); + assert!(matches!(map.get("sats"), Some(TreeNode::Leaf(_)))); + assert!(matches!(map.get("bitcoin"), Some(TreeNode::Leaf(_)))); + assert!(matches!(map.get("dollars"), Some(TreeNode::Leaf(_)))); + } + _ => panic!("Expected branch"), + } +} + +#[test] +fn lazy_block_value_without_dollars() { + let value = MockLazyBlockValue { + sats: MockVec::new("metric", Index::Height), + rest: MockLazyDerivedBlockValue { + bitcoin: MockVec::new("metric_btc", Index::Height), + dollars: None, + }, + }; + + let tree = value.to_tree_node(); + + // Expected: { sats: Leaf, bitcoin: Leaf } (no dollars) + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2); + assert!(map.contains_key("sats")); + assert!(map.contains_key("bitcoin")); + assert!(!map.contains_key("dollars")); + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 2: DerivedDateLast pattern (merge collapses to Leaf) +// ============================================================================ +// DerivedDateLast (merge): +// - weekindex: LazyLast with wrap="last" +// - monthindex: LazyLast with wrap="last" +// - yearindex: LazyLast with wrap="last" +// All produce { last: Leaf } → merge collapses to single Leaf + +#[derive(Traversable)] +#[traversable(wrap = "last")] +struct MockLazyLast(MockVec); + +#[derive(Traversable)] +#[traversable(merge)] +struct MockDerivedDateLast { + pub weekindex: MockLazyLast, + pub monthindex: MockLazyLast, + pub yearindex: MockLazyLast, +} + +#[test] +fn derived_date_last_collapses_to_leaf() { + let value = MockDerivedDateLast { + weekindex: MockLazyLast(MockVec::new("metric", Index::WeekIndex)), + monthindex: MockLazyLast(MockVec::new("metric", Index::MonthIndex)), + yearindex: MockLazyLast(MockVec::new("metric", Index::YearIndex)), + }; + + let tree = value.to_tree_node(); + + // All fields produce { last: Leaf } with same metric name + // Merge lifts all "last" keys → same name → collapses to single Leaf + match &tree { + TreeNode::Leaf(leaf) => { + assert_eq!(leaf.name(), "metric"); + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::YearIndex)); + } + TreeNode::Branch(map) => { + panic!("Expected Leaf, got Branch: {:?}", map.keys().collect::>()); + } + } +} + +// ============================================================================ +// Case 3: ComputedDateLast pattern (base + collapsed rest) +// ============================================================================ +// ComputedDateLast (merge): +// - dateindex: wrap="base" +// - rest: DerivedDateLast with flatten → collapses to Leaf +// If all same metric name → collapses to single Leaf + +#[derive(Traversable)] +#[traversable(merge)] +struct MockComputedDateLast { + #[traversable(wrap = "base")] + pub dateindex: MockVec, + #[traversable(flatten)] + pub rest: MockDerivedDateLast, +} + +#[test] +fn computed_date_last_collapses_to_leaf() { + let value = MockComputedDateLast { + dateindex: MockVec::new("metric", Index::DateIndex), + rest: MockDerivedDateLast { + weekindex: MockLazyLast(MockVec::new("metric", Index::WeekIndex)), + monthindex: MockLazyLast(MockVec::new("metric", Index::MonthIndex)), + yearindex: MockLazyLast(MockVec::new("metric", Index::YearIndex)), + }, + }; + + let tree = value.to_tree_node(); + + // dateindex produces { base: Leaf("metric", DateIndex) } + // rest (flatten) produces Leaf("metric", Week+Month+Year) → inserted as "rest" key + // All same metric name → collapses to single Leaf + match &tree { + TreeNode::Leaf(leaf) => { + assert_eq!(leaf.name(), "metric"); + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::DateIndex)); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::YearIndex)); + } + TreeNode::Branch(map) => { + panic!("Expected Leaf, got Branch: {:?}", map.keys().collect::>()); + } + } +} + +// ============================================================================ +// Case 4: ValueDerivedDateLast pattern (denomination siblings) +// ============================================================================ +// ValueDerivedDateLast (no merge): +// - sats: DerivedDateLast (merge) → Leaf +// - bitcoin: LazyDateLast (merge) → Leaf +// - dollars: Option> (merge) → Leaf + +#[derive(Traversable)] +struct MockValueDerivedDateLast { + pub sats: MockDerivedDateLast, + pub bitcoin: MockDerivedDateLast, + pub dollars: Option, +} + +#[test] +fn value_derived_date_last_denomination_leaves() { + let value = MockValueDerivedDateLast { + sats: MockDerivedDateLast { + weekindex: MockLazyLast(MockVec::new("metric", Index::WeekIndex)), + monthindex: MockLazyLast(MockVec::new("metric", Index::MonthIndex)), + yearindex: MockLazyLast(MockVec::new("metric", Index::YearIndex)), + }, + bitcoin: MockDerivedDateLast { + weekindex: MockLazyLast(MockVec::new("metric_btc", Index::WeekIndex)), + monthindex: MockLazyLast(MockVec::new("metric_btc", Index::MonthIndex)), + yearindex: MockLazyLast(MockVec::new("metric_btc", Index::YearIndex)), + }, + dollars: Some(MockComputedDateLast { + dateindex: MockVec::new("metric_usd", Index::DateIndex), + rest: MockDerivedDateLast { + weekindex: MockLazyLast(MockVec::new("metric_usd", Index::WeekIndex)), + monthindex: MockLazyLast(MockVec::new("metric_usd", Index::MonthIndex)), + yearindex: MockLazyLast(MockVec::new("metric_usd", Index::YearIndex)), + }, + }), + }; + + let tree = value.to_tree_node(); + + // Each inner type has merge → collapses to Leaf + // Outer has no merge → stays as Branch with denomination keys + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3); + + // Each denomination is a collapsed Leaf + match map.get("sats") { + Some(TreeNode::Leaf(l)) => assert_eq!(l.name(), "metric"), + _ => panic!("Expected sats to be Leaf"), + } + match map.get("bitcoin") { + Some(TreeNode::Leaf(l)) => assert_eq!(l.name(), "metric_btc"), + _ => panic!("Expected bitcoin to be Leaf"), + } + match map.get("dollars") { + Some(TreeNode::Leaf(l)) => assert_eq!(l.name(), "metric_usd"), + _ => panic!("Expected dollars to be Leaf"), + } + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 5: SumCum pattern (sum + cumulative leaves) +// ============================================================================ +// SumCum produces { sum: Leaf, cumulative: Leaf } via wrap attributes + +#[derive(Traversable)] +#[traversable(wrap = "sum")] +struct MockSumVec(MockVec); + +#[derive(Traversable)] +#[traversable(wrap = "cumulative")] +struct MockCumulativeVec(MockVec); + +#[derive(Traversable)] +#[traversable(merge)] +struct MockSumCum { + pub sum: MockSumVec, + pub cumulative: MockCumulativeVec, +} + +#[test] +fn sum_cum_produces_two_leaves() { + let value = MockSumCum { + sum: MockSumVec(MockVec::new("metric_sum", Index::DateIndex)), + cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::DateIndex)), + }; + + let tree = value.to_tree_node(); + + // { sum: Leaf, cumulative: Leaf } - different metric names, no collapse + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2); + assert_eq!(get_leaf_name(map.get("sum").unwrap()), Some("metric_sum")); + assert_eq!(get_leaf_name(map.get("cumulative").unwrap()), Some("metric_cumulative")); + } + _ => panic!("Expected branch with sum and cumulative"), + } +} + +// ============================================================================ +// Case 6: DerivedDateSumCum pattern (multiple time periods merge) +// ============================================================================ +// DerivedDateSumCum (merge): +// - weekindex: SumCum → { sum: Leaf, cumulative: Leaf } +// - monthindex: SumCum → { sum: Leaf, cumulative: Leaf } +// Merge lifts all → merges same keys + +#[derive(Traversable)] +#[traversable(merge)] +struct MockDerivedDateSumCum { + pub weekindex: MockSumCum, + pub monthindex: MockSumCum, +} + +#[test] +fn derived_date_sum_cum_merges_time_periods() { + let value = MockDerivedDateSumCum { + weekindex: MockSumCum { + sum: MockSumVec(MockVec::new("metric_sum", Index::WeekIndex)), + cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::WeekIndex)), + }, + monthindex: MockSumCum { + sum: MockSumVec(MockVec::new("metric_sum", Index::MonthIndex)), + cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::MonthIndex)), + }, + }; + + let tree = value.to_tree_node(); + + // Each SumCum produces { sum, cumulative } + // Merge lifts from weekindex and monthindex + // Same keys merge → { sum: Leaf(Week+Month), cumulative: Leaf(Week+Month) } + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2, "Expected sum, cumulative. Got: {:?}", map.keys().collect::>()); + + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(sum_indexes.contains(&Index::WeekIndex)); + assert!(sum_indexes.contains(&Index::MonthIndex)); + + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::WeekIndex)); + assert!(cum_indexes.contains(&Index::MonthIndex)); + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 7: ComputedBlockSumCum pattern (base + rest with flatten) +// ============================================================================ +// ComputedBlockSumCum (merge): +// - height: wrap="base" +// - rest: DerivedComputedBlockSumCum with flatten +// - height_cumulative: CumulativeVec +// - dateindex: SumCum +// - dates: DerivedDateSumCum with flatten +// - difficultyepoch: SumCum + +#[derive(Traversable)] +#[traversable(merge)] +struct MockDerivedComputedBlockSumCum { + pub height_cumulative: MockCumulativeVec, + pub dateindex: MockSumCum, + #[traversable(flatten)] + pub dates: MockDerivedDateSumCum, +} + +#[derive(Traversable)] +#[traversable(merge)] +struct MockComputedBlockSumCum { + #[traversable(wrap = "base")] + pub height: MockVec, + #[traversable(flatten)] + pub rest: MockDerivedComputedBlockSumCum, +} + +#[test] +fn computed_block_sum_cum_base_sum_cumulative() { + let value = MockComputedBlockSumCum { + height: MockVec::new("metric", Index::Height), + rest: MockDerivedComputedBlockSumCum { + height_cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::Height)), + dateindex: MockSumCum { + sum: MockSumVec(MockVec::new("metric_sum", Index::DateIndex)), + cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::DateIndex)), + }, + dates: MockDerivedDateSumCum { + weekindex: MockSumCum { + sum: MockSumVec(MockVec::new("metric_sum", Index::WeekIndex)), + cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::WeekIndex)), + }, + monthindex: MockSumCum { + sum: MockSumVec(MockVec::new("metric_sum", Index::MonthIndex)), + cumulative: MockCumulativeVec(MockVec::new("metric_cumulative", Index::MonthIndex)), + }, + }, + }, + }; + + let tree = value.to_tree_node(); + + // Expected: { base, sum, cumulative } + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3, "Expected base, sum, cumulative. Got: {:?}", map.keys().collect::>()); + + // base: only Height + let base_indexes = get_leaf_indexes(map.get("base").unwrap()).unwrap(); + assert!(base_indexes.contains(&Index::Height)); + assert_eq!(base_indexes.len(), 1); + + // sum: DateIndex, WeekIndex, MonthIndex (NOT Height) + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(!sum_indexes.contains(&Index::Height)); + assert!(sum_indexes.contains(&Index::DateIndex)); + assert!(sum_indexes.contains(&Index::WeekIndex)); + assert!(sum_indexes.contains(&Index::MonthIndex)); + + // cumulative: Height + all time indexes + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::Height)); + assert!(cum_indexes.contains(&Index::DateIndex)); + assert!(cum_indexes.contains(&Index::WeekIndex)); + assert!(cum_indexes.contains(&Index::MonthIndex)); + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 8: ValueBlockSumCum pattern (denominations with nested aggregations) +// ============================================================================ +// ValueBlockSumCum (no merge): +// - sats: ComputedBlockSumCum (merge) → { base, sum, cumulative } +// - bitcoin: ComputedBlockSumCum (merge) → { base, sum, cumulative } +// - dollars: Option (merge) → { base, sum, cumulative } + +#[derive(Traversable)] +struct MockValueBlockSumCum { + pub sats: MockComputedBlockSumCum, + pub bitcoin: MockComputedBlockSumCum, + pub dollars: Option, +} + +#[test] +fn value_block_sum_cum_denominations_with_aggregations() { + let make_computed = |prefix: &str| MockComputedBlockSumCum { + height: MockVec::new(prefix, Index::Height), + rest: MockDerivedComputedBlockSumCum { + height_cumulative: MockCumulativeVec(MockVec::new(&format!("{prefix}_cumulative"), Index::Height)), + dateindex: MockSumCum { + sum: MockSumVec(MockVec::new(&format!("{prefix}_sum"), Index::DateIndex)), + cumulative: MockCumulativeVec(MockVec::new(&format!("{prefix}_cumulative"), Index::DateIndex)), + }, + dates: MockDerivedDateSumCum { + weekindex: MockSumCum { + sum: MockSumVec(MockVec::new(&format!("{prefix}_sum"), Index::WeekIndex)), + cumulative: MockCumulativeVec(MockVec::new(&format!("{prefix}_cumulative"), Index::WeekIndex)), + }, + monthindex: MockSumCum { + sum: MockSumVec(MockVec::new(&format!("{prefix}_sum"), Index::MonthIndex)), + cumulative: MockCumulativeVec(MockVec::new(&format!("{prefix}_cumulative"), Index::MonthIndex)), + }, + }, + }, + }; + + let value = MockValueBlockSumCum { + sats: make_computed("metric"), + bitcoin: make_computed("metric_btc"), + dollars: Some(make_computed("metric_usd")), + }; + + let tree = value.to_tree_node(); + + // Outer has no merge → denominations as branches + // Each inner has merge → { base, sum, cumulative } + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3); + + for denom in ["sats", "bitcoin", "dollars"] { + match map.get(denom) { + Some(TreeNode::Branch(inner)) => { + assert_eq!(inner.len(), 3, "Expected base, sum, cumulative for {denom}"); + assert!(inner.contains_key("base")); + assert!(inner.contains_key("sum")); + assert!(inner.contains_key("cumulative")); + } + _ => panic!("Expected branch for {denom}"), + } + } + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 9: Flatten of collapsed Leaf (edge case) +// ============================================================================ +// When flatten encounters a Leaf (from collapsed inner type), +// it inserts with field name as key. Merge on outer lifts wrapped values. + +#[derive(Traversable)] +#[traversable(merge)] +struct MockFlattenCollapsedLeaf { + #[traversable(wrap = "base")] + pub primary: MockVec, + #[traversable(flatten)] + pub collapsed: MockDerivedDateLast, // This collapses to Leaf +} + +#[test] +fn flatten_collapsed_leaf_uses_field_name() { + let value = MockFlattenCollapsedLeaf { + primary: MockVec::new("metric", Index::DateIndex), + collapsed: MockDerivedDateLast { + weekindex: MockLazyLast(MockVec::new("other_metric", Index::WeekIndex)), + monthindex: MockLazyLast(MockVec::new("other_metric", Index::MonthIndex)), + yearindex: MockLazyLast(MockVec::new("other_metric", Index::YearIndex)), + }, + }; + + let tree = value.to_tree_node(); + + // With merge on outer: + // - primary with wrap="base" → { base: Leaf } → merge lifts to base: Leaf + // - collapsed (already merged to Leaf) → flatten inserts as "collapsed": Leaf + // Result: { base: Leaf, collapsed: Leaf } + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2, "Expected base, collapsed. Got: {:?}", map.keys().collect::>()); + assert!(map.contains_key("base")); + assert!(map.contains_key("collapsed")); + + // Verify collapsed is a Leaf with the right indexes + match map.get("collapsed") { + Some(TreeNode::Leaf(l)) => { + assert_eq!(l.name(), "other_metric"); + let indexes = l.indexes(); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::YearIndex)); + } + _ => panic!("Expected collapsed to be Leaf"), + } + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 10: Rename attribute +// ============================================================================ + +#[derive(Traversable)] +struct MockRename { + #[traversable(rename = "custom_name")] + pub field: MockVec, +} + +#[test] +fn rename_attribute_changes_key() { + let value = MockRename { + field: MockVec::new("metric", Index::Height), + }; + + let tree = value.to_tree_node(); + + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 1); + assert!(map.contains_key("custom_name")); + assert!(!map.contains_key("field")); + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 11: Skip attribute +// ============================================================================ + +#[derive(Traversable)] +struct MockSkip { + pub included: MockVec, + #[traversable(skip)] + pub skipped: MockVec, +} + +#[test] +fn skip_attribute_excludes_field() { + let value = MockSkip { + included: MockVec::new("metric", Index::Height), + skipped: MockVec::new("should_not_appear", Index::Height), + }; + + let tree = value.to_tree_node(); + + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 1); + assert!(map.contains_key("included")); + assert!(!map.contains_key("skipped")); + } + _ => panic!("Expected branch"), + } +} + +// ============================================================================ +// Case 12: Transparent attribute (single-field delegation) +// ============================================================================ + +#[derive(Traversable)] +#[traversable(transparent)] +struct MockTransparent { + pub inner: MockVec, +} + +#[test] +fn transparent_delegates_to_inner() { + let value = MockTransparent { + inner: MockVec::new("metric", Index::Height), + }; + + let tree = value.to_tree_node(); + + // Should produce Leaf directly, not Branch { inner: Leaf } + match &tree { + TreeNode::Leaf(l) => { + assert_eq!(l.name(), "metric"); + } + _ => panic!("Expected Leaf (transparent delegation)"), + } +} + +// ============================================================================ +// Case 13: ValueBlockFull pattern (Full stats with multiple denominations) +// ============================================================================ +// ValueBlockFull pattern: +// - sats: ComputedBlockFull (merge) +// - bitcoin: LazyBlockFull (merge) +// - dollars: Option> (merge) +// +// Each ComputedBlockFull (merge): +// - height: wrap="base" +// - rest: DerivedComputedBlockFull (merge, flatten) +// - height_cumulative: CumulativeVec +// - dateindex: Full (distribution + sum_cum) +// - dates: DerivedDateFull (merge, flatten) +// - difficultyepoch: LazyFull + +// Mock for wrap="avg" +#[derive(Traversable)] +#[traversable(wrap = "avg")] +struct MockAvgVec(MockVec); + +// Mock for wrap="min" +#[derive(Traversable)] +#[traversable(wrap = "min")] +struct MockMinVec(MockVec); + +// Mock for wrap="max" +#[derive(Traversable)] +#[traversable(wrap = "max")] +struct MockMaxVec(MockVec); + +// Mock for wrap="median" +#[derive(Traversable)] +#[traversable(wrap = "median")] +struct MockMedianVec(MockVec); + +// MinMax struct +#[derive(Traversable)] +struct MockMinMax { + #[traversable(flatten)] + pub min: MockMinVec, + #[traversable(flatten)] + pub max: MockMaxVec, +} + +// Percentiles struct (simplified to just median for test) +#[derive(Traversable)] +struct MockPercentiles { + pub median: MockMedianVec, +} + +// Distribution = average + minmax + percentiles +#[derive(Traversable)] +struct MockDistribution { + pub average: MockAvgVec, + #[traversable(flatten)] + pub minmax: MockMinMax, + pub percentiles: MockPercentiles, +} + +// Full = Distribution + SumCum +#[derive(Traversable)] +struct MockFull { + pub distribution: MockDistribution, + pub sum_cum: MockSumCum, +} + +// LazyFull - all flattened +#[derive(Traversable)] +struct MockLazyFull { + #[traversable(flatten)] + pub avg: MockAvgVec, + #[traversable(flatten)] + pub min: MockMinVec, + #[traversable(flatten)] + pub max: MockMaxVec, + #[traversable(flatten)] + pub sum: MockSumVec, + #[traversable(flatten)] + pub cumulative: MockCumulativeVec, +} + +// DerivedDateFull (merge) - time periods with LazyFull +#[derive(Traversable)] +#[traversable(merge)] +struct MockDerivedDateFull { + pub weekindex: MockLazyFull, + pub monthindex: MockLazyFull, +} + +// DerivedComputedBlockFull (merge) +#[derive(Traversable)] +#[traversable(merge)] +struct MockDerivedComputedBlockFull { + pub height_cumulative: MockCumulativeVec, + pub dateindex: MockFull, + #[traversable(flatten)] + pub dates: MockDerivedDateFull, + pub difficultyepoch: MockLazyFull, +} + +// ComputedBlockFull (merge) +#[derive(Traversable)] +#[traversable(merge)] +struct MockComputedBlockFull { + #[traversable(wrap = "base")] + pub height: MockVec, + #[traversable(flatten)] + pub rest: MockDerivedComputedBlockFull, +} + +// ValueBlockFull - no merge (denominations as branches) +#[derive(Traversable)] +struct MockValueBlockFull { + pub sats: MockComputedBlockFull, + pub bitcoin: MockComputedBlockFull, + pub dollars: Option, +} + +fn make_lazy_full(name: &str, index: Index) -> MockLazyFull { + MockLazyFull { + avg: MockAvgVec(MockVec::new(&format!("{name}_avg"), index)), + min: MockMinVec(MockVec::new(&format!("{name}_min"), index)), + max: MockMaxVec(MockVec::new(&format!("{name}_max"), index)), + sum: MockSumVec(MockVec::new(&format!("{name}_sum"), index)), + cumulative: MockCumulativeVec(MockVec::new(&format!("{name}_cumulative"), index)), + } +} + +fn make_computed_block_full(name: &str) -> MockComputedBlockFull { + MockComputedBlockFull { + height: MockVec::new(name, Index::Height), + rest: MockDerivedComputedBlockFull { + height_cumulative: MockCumulativeVec(MockVec::new(&format!("{name}_cumulative"), Index::Height)), + dateindex: MockFull { + distribution: MockDistribution { + average: MockAvgVec(MockVec::new(&format!("{name}_avg"), Index::DateIndex)), + minmax: MockMinMax { + min: MockMinVec(MockVec::new(&format!("{name}_min"), Index::DateIndex)), + max: MockMaxVec(MockVec::new(&format!("{name}_max"), Index::DateIndex)), + }, + percentiles: MockPercentiles { + median: MockMedianVec(MockVec::new(&format!("{name}_median"), Index::DateIndex)), + }, + }, + sum_cum: MockSumCum { + sum: MockSumVec(MockVec::new(&format!("{name}_sum"), Index::DateIndex)), + cumulative: MockCumulativeVec(MockVec::new(&format!("{name}_cumulative"), Index::DateIndex)), + }, + }, + dates: MockDerivedDateFull { + weekindex: make_lazy_full(name, Index::WeekIndex), + monthindex: make_lazy_full(name, Index::MonthIndex), + }, + difficultyepoch: make_lazy_full(name, Index::DifficultyEpoch), + }, + } +} + +#[test] +fn value_block_full_denominations_as_branches() { + let value = MockValueBlockFull { + sats: make_computed_block_full("metric"), + bitcoin: make_computed_block_full("metric_btc"), + dollars: Some(make_computed_block_full("metric_usd")), + }; + + let tree = value.to_tree_node(); + + // Without merge on outer, denominations are branches + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3, "Expected sats, bitcoin, dollars"); + assert!(map.contains_key("sats")); + assert!(map.contains_key("bitcoin")); + assert!(map.contains_key("dollars")); + + // Each denomination should have deeply merged inner structure + // The merge recursively flattens: dateindex, difficultyepoch become flat metric keys + for denom in ["sats", "bitcoin", "dollars"] { + match map.get(denom) { + Some(TreeNode::Branch(inner)) => { + // Inner merge produces flat structure: + // base, cumulative, avg, average, min, max, sum, minmax, percentiles + assert!(inner.contains_key("base"), "{denom} missing base"); + assert!(inner.contains_key("cumulative"), "{denom} missing cumulative"); + assert!(inner.contains_key("avg"), "{denom} missing avg"); + assert!(inner.contains_key("sum"), "{denom} missing sum"); + // dateindex and difficultyepoch are merged in, not separate branches + assert!(!inner.contains_key("dateindex"), "{denom} should NOT have dateindex branch"); + assert!(!inner.contains_key("difficultyepoch"), "{denom} should NOT have difficultyepoch branch"); + } + _ => panic!("Expected branch for {denom}"), + } + } + } + _ => panic!("Expected branch at top level"), + } +} + +// ============================================================================ +// Case 14: ValueBlockFull with merge - smallest possible tree +// ============================================================================ +// When same metric names used across denominations, merge collapses them + +#[derive(Traversable)] +#[traversable(merge)] +struct MockValueBlockFullMerged { + pub sats: MockComputedBlockFull, + pub bitcoin: MockComputedBlockFull, + pub dollars: Option, +} + +#[test] +fn value_block_full_merged_same_names_collapse() { + // Using SAME metric names across all denominations + let value = MockValueBlockFullMerged { + sats: make_computed_block_full("metric"), + bitcoin: make_computed_block_full("metric"), // Same name! + dollars: Some(make_computed_block_full("metric")), // Same name! + }; + + let tree = value.to_tree_node(); + + // With merge and same metric names, all leaves collapse + // Result: flat tree with each metric type having all denomination indexes merged + match &tree { + TreeNode::Branch(map) => { + // Should be flat - no sats/bitcoin/dollars branches + assert!(!map.contains_key("sats"), "sats branch should be lifted"); + assert!(!map.contains_key("bitcoin"), "bitcoin branch should be lifted"); + assert!(!map.contains_key("dollars"), "dollars branch should be lifted"); + + // Should have metric keys: base, cumulative, dateindex, difficultyepoch + assert!(map.contains_key("base"), "Missing base key"); + assert!(map.contains_key("cumulative"), "Missing cumulative key"); + + // base should have all Height indexes merged (same metric name = collapsed) + if let Some(TreeNode::Leaf(l)) = map.get("base") { + assert_eq!(l.name(), "metric"); + // All 3 denominations have Height index + let indexes = l.indexes(); + assert!(indexes.contains(&Index::Height)); + } + + // cumulative should have multiple indexes merged + if let Some(TreeNode::Leaf(l)) = map.get("cumulative") { + assert_eq!(l.name(), "metric_cumulative"); + let indexes = l.indexes(); + // Height from height_cumulative, DateIndex from dateindex, Week/Month from dates, DifficultyEpoch + assert!(indexes.contains(&Index::Height)); + assert!(indexes.contains(&Index::DateIndex)); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::DifficultyEpoch)); + } + } + _ => panic!("Expected branch"), + } +} + +#[test] +fn computed_block_full_inner_structure() { + // Test the inner structure of a single ComputedBlockFull + let value = make_computed_block_full("metric"); + let tree = value.to_tree_node(); + + match &tree { + TreeNode::Branch(map) => { + println!("Keys: {:?}", map.keys().collect::>()); + + // Expected flat structure after all merges: + // base, cumulative, avg, sum, min, max, average, percentiles + // Note: dateindex and difficultyepoch are merged in, not separate branches + + // base from height with wrap="base" + assert!(map.contains_key("base")); + if let Some(TreeNode::Leaf(l)) = map.get("base") { + assert_eq!(l.name(), "metric"); + assert!(l.indexes().contains(&Index::Height)); + } + + // cumulative from height_cumulative + dateindex.sum_cum.cumulative + dates + difficultyepoch + assert!(map.contains_key("cumulative")); + if let Some(TreeNode::Leaf(l)) = map.get("cumulative") { + assert_eq!(l.name(), "metric_cumulative"); + let indexes = l.indexes(); + // Should have merged: Height, DateIndex, WeekIndex, MonthIndex, DifficultyEpoch + assert!(indexes.contains(&Index::Height), "Missing Height"); + assert!(indexes.contains(&Index::DateIndex), "Missing DateIndex"); + assert!(indexes.contains(&Index::WeekIndex), "Missing WeekIndex"); + assert!(indexes.contains(&Index::MonthIndex), "Missing MonthIndex"); + assert!(indexes.contains(&Index::DifficultyEpoch), "Missing DifficultyEpoch"); + } + + // avg, sum, min, max merged from dates + difficultyepoch LazyFull + assert!(map.contains_key("avg"), "Missing avg"); + assert!(map.contains_key("sum"), "Missing sum"); + assert!(map.contains_key("min"), "Missing min"); + assert!(map.contains_key("max"), "Missing max"); + + // average from dateindex.distribution.average + assert!(map.contains_key("average"), "Missing average"); + + // percentiles stays grouped + assert!(map.contains_key("percentiles"), "Missing percentiles"); + + // dateindex and difficultyepoch should NOT be separate branches + assert!(!map.contains_key("dateindex"), "dateindex should be merged in"); + assert!(!map.contains_key("difficultyepoch"), "difficultyepoch should be merged in"); + assert!(!map.contains_key("minmax"), "minmax should be flattened"); + } + _ => panic!("Expected branch"), + } +} diff --git a/crates/brk_traversable_derive/.gitignore b/crates/brk_traversable_derive/.gitignore new file mode 100644 index 000000000..88b06327a --- /dev/null +++ b/crates/brk_traversable_derive/.gitignore @@ -0,0 +1,2 @@ +*.md +!README.md diff --git a/crates/brk_traversable_derive/src/lib.rs b/crates/brk_traversable_derive/src/lib.rs index 03a25f5de..ff2ec8f1c 100644 --- a/crates/brk_traversable_derive/src/lib.rs +++ b/crates/brk_traversable_derive/src/lib.rs @@ -2,6 +2,48 @@ use proc_macro::TokenStream; use quote::quote; use syn::{Data, DeriveInput, Fields, Type, parse_macro_input}; +/// Struct-level attributes for Traversable derive +#[derive(Default)] +struct StructAttr { + /// If true, call .merge_branches().unwrap() on the final result + merge: bool, + /// If true, delegate to the single field (transparent newtype pattern) + transparent: bool, + /// If set, wrap the result in Branch { key: inner } + wrap: Option, +} + +fn get_struct_attr(attrs: &[syn::Attribute]) -> StructAttr { + let mut result = StructAttr::default(); + for attr in attrs { + if !attr.path().is_ident("traversable") { + continue; + } + + // Try parsing as single ident (merge, transparent) + if let Ok(ident) = attr.parse_args::() { + match ident.to_string().as_str() { + "merge" => result.merge = true, + "transparent" => result.transparent = true, + _ => {} + } + continue; + } + + // Try parsing as name-value (wrap = "...") + if let Ok(meta) = attr.parse_args::() + && meta.path.is_ident("wrap") + && let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &meta.value + { + result.wrap = Some(lit_str.value()); + } + } + result +} + #[proc_macro_derive(Traversable, attributes(traversable))] pub fn derive_traversable(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -9,6 +51,8 @@ pub fn derive_traversable(input: TokenStream) -> TokenStream { let generics = &input.generics; let (impl_generics, ty_generics, _) = generics.split_for_impl(); + let struct_attr = get_struct_attr(&input.attrs); + let Data::Struct(data) = &input.data else { return syn::Error::new_spanned( &input.ident, @@ -18,15 +62,24 @@ pub fn derive_traversable(input: TokenStream) -> TokenStream { .into(); }; - // Handle single-field tuple struct delegation + // Handle single-field tuple struct delegation (automatic transparent) if let Fields::Unnamed(fields) = &data.fields && fields.unnamed.len() == 1 { let where_clause = build_where_clause(generics, &[]); + let to_tree_node_body = if let Some(wrap_key) = &struct_attr.wrap { + quote! { + brk_traversable::TreeNode::wrap(#wrap_key, self.0.to_tree_node()) + } + } else { + quote! { + self.0.to_tree_node() + } + }; return TokenStream::from(quote! { impl #impl_generics Traversable for #name #ty_generics #where_clause { fn to_tree_node(&self) -> brk_traversable::TreeNode { - self.0.to_tree_node() + #to_tree_node_body } fn iter_any_exportable(&self) -> impl Iterator { @@ -51,11 +104,35 @@ pub fn derive_traversable(input: TokenStream) -> TokenStream { }); }; + // Handle transparent delegation for named structs (delegates to first field) + if struct_attr.transparent { + let first_field = named_fields + .named + .first() + .expect("transparent requires at least one field"); + let field_name = first_field + .ident + .as_ref() + .expect("named field must have ident"); + let where_clause = build_where_clause(generics, &[]); + return TokenStream::from(quote! { + impl #impl_generics Traversable for #name #ty_generics #where_clause { + fn to_tree_node(&self) -> brk_traversable::TreeNode { + self.#field_name.to_tree_node() + } + + fn iter_any_exportable(&self) -> impl Iterator { + self.#field_name.iter_any_exportable() + } + } + }); + } + let generic_params: Vec<_> = generics.type_params().map(|p| &p.ident).collect(); let (field_infos, generics_needing_traversable) = analyze_fields(named_fields, &generic_params); - let field_traversals = generate_field_traversals(&field_infos); + let field_traversals = generate_field_traversals(&field_infos, struct_attr.merge); let iterator_impl = generate_iterator_impl(&field_infos); let where_clause = build_where_clause(generics, &generics_needing_traversable); @@ -79,6 +156,8 @@ struct FieldInfo<'a> { name: &'a syn::Ident, is_option: bool, attr: FieldAttr, + rename: Option, + wrap: Option, } fn analyze_fields<'a>( @@ -89,12 +168,10 @@ fn analyze_fields<'a>( let mut generics_set = std::collections::BTreeSet::new(); for field in &fields.named { - let field_attr = get_field_attr(field); - - // Skip attribute means don't process at all - if field_attr.is_none() { + let Some((attr, rename, wrap)) = get_field_attr(field) else { + // Skip attribute means don't process at all continue; - } + }; if !matches!(field.vis, syn::Visibility::Public(_)) { continue; @@ -116,27 +193,52 @@ fn analyze_fields<'a>( field_infos.push(FieldInfo { name: field_name, is_option: is_option_type(&field.ty), - attr: field_attr.unwrap(), + attr, + rename, + wrap, }); } (field_infos, generics_set.into_iter().collect()) } -/// Returns None for skip, Some(attr) for normal/flatten -fn get_field_attr(field: &syn::Field) -> Option { +/// Returns None for skip, Some((attr, rename, wrap)) for normal/flatten +fn get_field_attr(field: &syn::Field) -> Option<(FieldAttr, Option, Option)> { + let mut attr_type = FieldAttr::Normal; + let mut rename = None; + let mut wrap = None; + for attr in &field.attrs { - if attr.path().is_ident("traversable") - && let Ok(ident) = attr.parse_args::() + if !attr.path().is_ident("traversable") { + continue; + } + + // Try parsing as a single ident (skip, flatten) + if let Ok(ident) = attr.parse_args::() { + match ident.to_string().as_str() { + "skip" => return None, + "flatten" => attr_type = FieldAttr::Flatten, + _ => {} + } + continue; + } + + // Try parsing as name-value pairs (rename = "...", wrap = "...") + if let Ok(meta) = attr.parse_args::() + && let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &meta.value { - return match ident.to_string().as_str() { - "skip" => None, - "flatten" => Some(FieldAttr::Flatten), - _ => Some(FieldAttr::Normal), - }; + if meta.path.is_ident("rename") { + rename = Some(lit_str.value()); + } else if meta.path.is_ident("wrap") { + wrap = Some(lit_str.value()); + } } } - Some(FieldAttr::Normal) + + Some((attr_type, rename, wrap)) } fn is_option_type(ty: &Type) -> bool { @@ -148,91 +250,47 @@ fn is_option_type(ty: &Type) -> bool { ) } -fn generate_field_traversals(infos: &[FieldInfo]) -> proc_macro2::TokenStream { +fn generate_field_traversals(infos: &[FieldInfo], merge: bool) -> proc_macro2::TokenStream { let has_flatten = infos.iter().any(|i| matches!(i.attr, FieldAttr::Flatten)); - let has_normal = infos.iter().any(|i| matches!(i.attr, FieldAttr::Normal)); - if !has_flatten { - // Fast path: no flatten, simple collection - let entries = infos.iter().map(|info| { - let field_name = info.name; - let field_name_str = field_name.to_string(); - - if info.is_option { - quote! { - self.#field_name.as_ref().map(|nested| (String::from(#field_name_str), nested.to_tree_node())) - } - } else { - quote! { - Some((String::from(#field_name_str), self.#field_name.to_tree_node())) - } - } - }); - - return quote! { - let collected: std::collections::BTreeMap<_, _> = [#(#entries,)*] - .into_iter() - .flatten() - .collect(); - - brk_traversable::TreeNode::Branch(collected) - }; - } - - // Has flatten fields - if !has_normal { - // Only flatten fields, no normal fields - need explicit type annotation - let flatten_entries = infos.iter() - .filter(|i| matches!(i.attr, FieldAttr::Flatten)) - .map(|info| { - let field_name = info.name; - - if info.is_option { - quote! { - if let Some(ref nested) = self.#field_name { - if let brk_traversable::TreeNode::Branch(map) = nested.to_tree_node() { - collected.extend(map); - } - } - } - } else { - quote! { - if let brk_traversable::TreeNode::Branch(map) = self.#field_name.to_tree_node() { - collected.extend(map); - } - } - } - }); - - return quote! { - let mut collected: std::collections::BTreeMap = - std::collections::BTreeMap::new(); - - #(#flatten_entries)* - - brk_traversable::TreeNode::Branch(collected) - }; - } - - // Has both normal and flatten fields - let normal_entries = infos.iter() + // Generate normal field entries + let normal_entries: Vec<_> = infos + .iter() .filter(|i| matches!(i.attr, FieldAttr::Normal)) .map(|info| { let field_name = info.name; - let field_name_str = field_name.to_string(); + // Use rename if specified, otherwise use field name + let key_str = info + .rename.as_deref() + .unwrap_or_else(|| field_name.to_string().leak()); + + // Generate tree node expression, optionally wrapped + let node_expr = if let Some(wrap_key) = &info.wrap { + quote! { brk_traversable::TreeNode::wrap(#wrap_key, nested.to_tree_node()) } + } else { + quote! { nested.to_tree_node() } + }; if info.is_option { quote! { - self.#field_name.as_ref().map(|nested| (String::from(#field_name_str), nested.to_tree_node())) + self.#field_name.as_ref().map(|nested| (String::from(#key_str), #node_expr)) } } else { + let node_expr_self = if let Some(wrap_key) = &info.wrap { + quote! { brk_traversable::TreeNode::wrap(#wrap_key, self.#field_name.to_tree_node()) } + } else { + quote! { self.#field_name.to_tree_node() } + }; quote! { - Some((String::from(#field_name_str), self.#field_name.to_tree_node())) + Some((String::from(#key_str), #node_expr_self)) } } - }); + }) + .collect(); - let flatten_entries = infos.iter() + // Generate flatten field entries + let flatten_entries: Vec<_> = infos + .iter() .filter(|i| matches!(i.attr, FieldAttr::Flatten)) .map(|info| { let field_name = info.name; @@ -240,29 +298,73 @@ fn generate_field_traversals(infos: &[FieldInfo]) -> proc_macro2::TokenStream { if info.is_option { quote! { if let Some(ref nested) = self.#field_name { - if let brk_traversable::TreeNode::Branch(map) = nested.to_tree_node() { - collected.extend(map); + match nested.to_tree_node() { + brk_traversable::TreeNode::Branch(map) => collected.extend(map), + leaf @ brk_traversable::TreeNode::Leaf(_) => { + // Collapsed leaf from child - insert with field name as key + collected.insert(String::from(stringify!(#field_name)), leaf); + } } } } } else { quote! { - if let brk_traversable::TreeNode::Branch(map) = self.#field_name.to_tree_node() { - collected.extend(map); + match self.#field_name.to_tree_node() { + brk_traversable::TreeNode::Branch(map) => collected.extend(map), + leaf @ brk_traversable::TreeNode::Leaf(_) => { + // Collapsed leaf from child - insert with field name as key + collected.insert(String::from(stringify!(#field_name)), leaf); + } } } } - }); + }) + .collect(); + + let final_expr = if merge { + quote! { brk_traversable::TreeNode::Branch(collected).merge_branches().unwrap() } + } else { + quote! { brk_traversable::TreeNode::Branch(collected) } + }; + + // Build collected map initialization based on what we have + let (init_collected, extend_flatten) = if !has_flatten { + // No flatten fields - simple collection, no need to extend + ( + quote! { + let collected: std::collections::BTreeMap<_, _> = [#(#normal_entries,)*] + .into_iter() + .flatten() + .collect(); + }, + quote! {}, + ) + } else if normal_entries.is_empty() { + // Only flatten fields - explicit type annotation needed + ( + quote! { + let mut collected: std::collections::BTreeMap = + std::collections::BTreeMap::new(); + }, + quote! { #(#flatten_entries)* }, + ) + } else { + // Both normal and flatten fields + ( + quote! { + let mut collected: std::collections::BTreeMap<_, _> = [#(#normal_entries,)*] + .into_iter() + .flatten() + .collect(); + }, + quote! { #(#flatten_entries)* }, + ) + }; quote! { - let mut collected: std::collections::BTreeMap<_, _> = [#(#normal_entries,)*] - .into_iter() - .flatten() - .collect(); - - #(#flatten_entries)* - - brk_traversable::TreeNode::Branch(collected) + #init_collected + #extend_flatten + #final_expr } } diff --git a/crates/brk_types/Cargo.toml b/crates/brk_types/Cargo.toml index 1ca9e3ac7..f884b90ea 100644 --- a/crates/brk_types/Cargo.toml +++ b/crates/brk_types/Cargo.toml @@ -12,7 +12,7 @@ build = "build.rs" bitcoin = { workspace = true } brk_error = { workspace = true } byteview = { workspace = true } -derive_deref = { workspace = true } +derive_more = { workspace = true } itoa = "1.0.17" jiff = { workspace = true } num_enum = "0.7.5" diff --git a/crates/brk_types/src/address.rs b/crates/brk_types/src/address.rs index cd8e90500..2efe06a1d 100644 --- a/crates/brk_types/src/address.rs +++ b/crates/brk_types/src/address.rs @@ -2,7 +2,7 @@ use std::{fmt, str::FromStr}; use bitcoin::ScriptBuf; use brk_error::Error; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize, Serializer}; diff --git a/crates/brk_types/src/addresshash.rs b/crates/brk_types/src/addresshash.rs index d63250899..b7aeafe24 100644 --- a/crates/brk_types/src/addresshash.rs +++ b/crates/brk_types/src/addresshash.rs @@ -1,5 +1,5 @@ use byteview::ByteView; -use derive_deref::Deref; +use derive_more::Deref; use vecdb::Bytes; use super::AddressBytes; diff --git a/crates/brk_types/src/block.rs b/crates/brk_types/src/block.rs index 2afaaa395..651a93d58 100644 --- a/crates/brk_types/src/block.rs +++ b/crates/brk_types/src/block.rs @@ -1,13 +1,16 @@ -use std::{borrow::Cow, ops::Deref}; +use std::borrow::Cow; + +use derive_more::Deref; use crate::BlkMetadata; use super::{BlockHash, Height}; -#[derive(Debug)] +#[derive(Debug, Deref)] pub struct Block { height: Height, hash: BlockHash, + #[deref] block: bitcoin::Block, } @@ -64,15 +67,9 @@ impl From for Block { } } -impl Deref for Block { - type Target = bitcoin::Block; - fn deref(&self) -> &Self::Target { - &self.block - } -} - -#[derive(Debug)] +#[derive(Debug, Deref)] pub struct ReadBlock { + #[deref] block: Block, metadata: BlkMetadata, tx_metadata: Vec, @@ -103,9 +100,3 @@ impl ReadBlock { } } -impl Deref for ReadBlock { - type Target = Block; - fn deref(&self) -> &Self::Target { - &self.block - } -} diff --git a/crates/brk_types/src/blockhash.rs b/crates/brk_types/src/blockhash.rs index 708b7ed6d..d56524c47 100644 --- a/crates/brk_types/src/blockhash.rs +++ b/crates/brk_types/src/blockhash.rs @@ -2,7 +2,7 @@ use std::{fmt, mem, str::FromStr}; use bitcoin::hashes::Hash; use brk_error::Error; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize, Serializer, de}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/blockhashprefix.rs b/crates/brk_types/src/blockhashprefix.rs index 32eba13d0..f9257c3f9 100644 --- a/crates/brk_types/src/blockhashprefix.rs +++ b/crates/brk_types/src/blockhashprefix.rs @@ -1,5 +1,5 @@ use byteview::ByteView; -use derive_deref::Deref; +use derive_more::Deref; use super::BlockHash; diff --git a/crates/brk_types/src/bytes.rs b/crates/brk_types/src/bytes.rs index 94b81f686..20d4b7c32 100644 --- a/crates/brk_types/src/bytes.rs +++ b/crates/brk_types/src/bytes.rs @@ -1,4 +1,4 @@ -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::Bytes; diff --git a/crates/brk_types/src/datarangeformat.rs b/crates/brk_types/src/datarangeformat.rs index 068bd0091..4d3ff5e9e 100644 --- a/crates/brk_types/src/datarangeformat.rs +++ b/crates/brk_types/src/datarangeformat.rs @@ -1,13 +1,13 @@ -use std::ops::Deref; - +use derive_more::Deref; use schemars::JsonSchema; use serde::Deserialize; use crate::{DataRange, Format}; /// Data range with output format for API query parameters -#[derive(Default, Debug, Deserialize, JsonSchema)] +#[derive(Default, Debug, Deref, Deserialize, JsonSchema)] pub struct DataRangeFormat { + #[deref] #[serde(flatten)] pub range: DataRange, @@ -37,9 +37,3 @@ impl DataRangeFormat { } } -impl Deref for DataRangeFormat { - type Target = DataRange; - fn deref(&self) -> &Self::Target { - &self.range - } -} diff --git a/crates/brk_types/src/dollars.rs b/crates/brk_types/src/dollars.rs index f853d04af..f5d0a57cb 100644 --- a/crates/brk_types/src/dollars.rs +++ b/crates/brk_types/src/dollars.rs @@ -6,7 +6,7 @@ use std::{ ops::{Add, AddAssign, Div, Mul, Neg, Sub}, }; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco}; diff --git a/crates/brk_types/src/emptyaddressindex.rs b/crates/brk_types/src/emptyaddressindex.rs index cd89e5d0b..bb459360f 100644 --- a/crates/brk_types/src/emptyaddressindex.rs +++ b/crates/brk_types/src/emptyaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/emptyoutputindex.rs b/crates/brk_types/src/emptyoutputindex.rs index 75d856881..30c7f9054 100644 --- a/crates/brk_types/src/emptyoutputindex.rs +++ b/crates/brk_types/src/emptyoutputindex.rs @@ -1,6 +1,6 @@ use std::{fmt, ops::Add}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/height.rs b/crates/brk_types/src/height.rs index c77d053ff..b8743c20c 100644 --- a/crates/brk_types/src/height.rs +++ b/crates/brk_types/src/height.rs @@ -5,7 +5,7 @@ use std::{ }; use byteview::ByteView; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, CheckedSub, Formattable, FromCoarserIndex, Pco, PrintableIndex, Stamp}; diff --git a/crates/brk_types/src/indexes.rs b/crates/brk_types/src/indexes.rs index 3d4ad1670..c97d4e954 100644 --- a/crates/brk_types/src/indexes.rs +++ b/crates/brk_types/src/indexes.rs @@ -1,4 +1,4 @@ -use std::ops::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use crate::{ DateIndex, DecadeIndex, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height, MonthIndex, @@ -68,8 +68,10 @@ impl Indexes { /// Extended indexes with time-based granularities. /// Used by brk_computer for time-series aggregation. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Deref, DerefMut)] pub struct ComputeIndexes { + #[deref] + #[deref_mut] indexes: Indexes, pub dateindex: DateIndex, pub weekindex: WeekIndex, @@ -111,15 +113,3 @@ impl ComputeIndexes { } } -impl Deref for ComputeIndexes { - type Target = Indexes; - fn deref(&self) -> &Self::Target { - &self.indexes - } -} - -impl DerefMut for ComputeIndexes { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.indexes - } -} diff --git a/crates/brk_types/src/limit.rs b/crates/brk_types/src/limit.rs index 5b01c17a5..289edb015 100644 --- a/crates/brk_types/src/limit.rs +++ b/crates/brk_types/src/limit.rs @@ -1,4 +1,4 @@ -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::Deserialize; diff --git a/crates/brk_types/src/loadedaddressindex.rs b/crates/brk_types/src/loadedaddressindex.rs index 3bb475d12..57af7a729 100644 --- a/crates/brk_types/src/loadedaddressindex.rs +++ b/crates/brk_types/src/loadedaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/metric.rs b/crates/brk_types/src/metric.rs index 58c1a1ff9..35f4772fc 100644 --- a/crates/brk_types/src/metric.rs +++ b/crates/brk_types/src/metric.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::Deserialize; diff --git a/crates/brk_types/src/metricdata.rs b/crates/brk_types/src/metricdata.rs index 397ee0e3e..cb53ae547 100644 --- a/crates/brk_types/src/metricdata.rs +++ b/crates/brk_types/src/metricdata.rs @@ -10,7 +10,7 @@ use vecdb::AnySerializableVec; /// All metric data endpoints return this structure when format is JSON. /// This type is not instantiated - use `MetricData::serialize()` to write JSON bytes directly. #[derive(JsonSchema, Deserialize)] -pub struct MetricData { +pub struct MetricData { /// Total number of data points in the metric pub total: usize, /// Start index (inclusive) of the returned range @@ -18,7 +18,7 @@ pub struct MetricData { /// End index (exclusive) of the returned range pub to: usize, /// The metric data - pub data: Vec, + pub data: Vec, } impl MetricData { diff --git a/crates/brk_types/src/metrics.rs b/crates/brk_types/src/metrics.rs index 86cc87fc5..ea4f75178 100644 --- a/crates/brk_types/src/metrics.rs +++ b/crates/brk_types/src/metrics.rs @@ -1,6 +1,6 @@ use std::{fmt, mem}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::Deserialize; diff --git a/crates/brk_types/src/metricselection.rs b/crates/brk_types/src/metricselection.rs index 53c5a781c..c3abf7136 100644 --- a/crates/brk_types/src/metricselection.rs +++ b/crates/brk_types/src/metricselection.rs @@ -1,12 +1,11 @@ -use std::ops::Deref; - +use derive_more::Deref; use schemars::JsonSchema; use serde::Deserialize; use crate::{DataRangeFormat, Index, Metric, Metrics}; /// Selection of metrics to query -#[derive(Debug, Deserialize, JsonSchema)] +#[derive(Debug, Deref, Deserialize, JsonSchema)] pub struct MetricSelection { /// Requested metrics #[serde(alias = "m")] @@ -16,17 +15,11 @@ pub struct MetricSelection { #[serde(alias = "i")] pub index: Index, + #[deref] #[serde(flatten)] pub range: DataRangeFormat, } -impl Deref for MetricSelection { - type Target = DataRangeFormat; - fn deref(&self) -> &Self::Target { - &self.range - } -} - impl From<(Index, Metric, DataRangeFormat)> for MetricSelection { #[inline] fn from((index, metric, range): (Index, Metric, DataRangeFormat)) -> Self { diff --git a/crates/brk_types/src/ohlc.rs b/crates/brk_types/src/ohlc.rs index 0a5ea3927..226d49d57 100644 --- a/crates/brk_types/src/ohlc.rs +++ b/crates/brk_types/src/ohlc.rs @@ -4,7 +4,7 @@ use std::{ ops::{Add, AddAssign, Div}, }; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{ Deserialize, Deserializer, Serialize, Serializer, diff --git a/crates/brk_types/src/opreturnindex.rs b/crates/brk_types/src/opreturnindex.rs index cd2a42801..7fa85ff42 100644 --- a/crates/brk_types/src/opreturnindex.rs +++ b/crates/brk_types/src/opreturnindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2aaddressindex.rs b/crates/brk_types/src/p2aaddressindex.rs index ee74d7418..23f41bdac 100644 --- a/crates/brk_types/src/p2aaddressindex.rs +++ b/crates/brk_types/src/p2aaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2abytes.rs b/crates/brk_types/src/p2abytes.rs index 6d8f02470..b5e49a64d 100644 --- a/crates/brk_types/src/p2abytes.rs +++ b/crates/brk_types/src/p2abytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2msoutputindex.rs b/crates/brk_types/src/p2msoutputindex.rs index 69287c988..f0d7229a3 100644 --- a/crates/brk_types/src/p2msoutputindex.rs +++ b/crates/brk_types/src/p2msoutputindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2pk33addressindex.rs b/crates/brk_types/src/p2pk33addressindex.rs index 4a58d6769..97789e2d3 100644 --- a/crates/brk_types/src/p2pk33addressindex.rs +++ b/crates/brk_types/src/p2pk33addressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2pk33bytes.rs b/crates/brk_types/src/p2pk33bytes.rs index 1084ac3c9..d55fd7349 100644 --- a/crates/brk_types/src/p2pk33bytes.rs +++ b/crates/brk_types/src/p2pk33bytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2pk65addressindex.rs b/crates/brk_types/src/p2pk65addressindex.rs index bddde6a67..2dc85fabb 100644 --- a/crates/brk_types/src/p2pk65addressindex.rs +++ b/crates/brk_types/src/p2pk65addressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2pk65bytes.rs b/crates/brk_types/src/p2pk65bytes.rs index cb2734414..a2236d586 100644 --- a/crates/brk_types/src/p2pk65bytes.rs +++ b/crates/brk_types/src/p2pk65bytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2pkhaddressindex.rs b/crates/brk_types/src/p2pkhaddressindex.rs index 65629dac4..b0d57ea03 100644 --- a/crates/brk_types/src/p2pkhaddressindex.rs +++ b/crates/brk_types/src/p2pkhaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2pkhbytes.rs b/crates/brk_types/src/p2pkhbytes.rs index 2f9412b4b..949680af5 100644 --- a/crates/brk_types/src/p2pkhbytes.rs +++ b/crates/brk_types/src/p2pkhbytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2shaddressindex.rs b/crates/brk_types/src/p2shaddressindex.rs index 468b52ca0..2fd10ec04 100644 --- a/crates/brk_types/src/p2shaddressindex.rs +++ b/crates/brk_types/src/p2shaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2shbytes.rs b/crates/brk_types/src/p2shbytes.rs index 3dfa89cfa..d2807e1b4 100644 --- a/crates/brk_types/src/p2shbytes.rs +++ b/crates/brk_types/src/p2shbytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2traddressindex.rs b/crates/brk_types/src/p2traddressindex.rs index 5849311c6..c79e16426 100644 --- a/crates/brk_types/src/p2traddressindex.rs +++ b/crates/brk_types/src/p2traddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2trbytes.rs b/crates/brk_types/src/p2trbytes.rs index ed1f8086a..f8de72f4e 100644 --- a/crates/brk_types/src/p2trbytes.rs +++ b/crates/brk_types/src/p2trbytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2wpkhaddressindex.rs b/crates/brk_types/src/p2wpkhaddressindex.rs index 3bcb5ceb6..dbe68787b 100644 --- a/crates/brk_types/src/p2wpkhaddressindex.rs +++ b/crates/brk_types/src/p2wpkhaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2wpkhbytes.rs b/crates/brk_types/src/p2wpkhbytes.rs index f086595a3..e102f1729 100644 --- a/crates/brk_types/src/p2wpkhbytes.rs +++ b/crates/brk_types/src/p2wpkhbytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/p2wshaddressindex.rs b/crates/brk_types/src/p2wshaddressindex.rs index 79a2f0d84..f898e8e07 100644 --- a/crates/brk_types/src/p2wshaddressindex.rs +++ b/crates/brk_types/src/p2wshaddressindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/p2wshbytes.rs b/crates/brk_types/src/p2wshbytes.rs index 5f56ba752..0422d2f0a 100644 --- a/crates/brk_types/src/p2wshbytes.rs +++ b/crates/brk_types/src/p2wshbytes.rs @@ -1,6 +1,6 @@ use std::fmt; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/sats.rs b/crates/brk_types/src/sats.rs index c81755c97..d19435dab 100644 --- a/crates/brk_types/src/sats.rs +++ b/crates/brk_types/src/sats.rs @@ -4,7 +4,7 @@ use std::{ }; use bitcoin::Amount; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, SaturatingAdd}; diff --git a/crates/brk_types/src/stored_bool.rs b/crates/brk_types/src/stored_bool.rs index 7d9efec3a..30670ae6e 100644 --- a/crates/brk_types/src/stored_bool.rs +++ b/crates/brk_types/src/stored_bool.rs @@ -1,4 +1,4 @@ -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_f32.rs b/crates/brk_types/src/stored_f32.rs index 7002864e6..e03aa330e 100644 --- a/crates/brk_types/src/stored_f32.rs +++ b/crates/brk_types/src/stored_f32.rs @@ -6,7 +6,7 @@ use std::{ ops::{Add, AddAssign, Div, Mul, Neg, Sub}, }; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_f64.rs b/crates/brk_types/src/stored_f64.rs index 2011c7085..b35c0c50d 100644 --- a/crates/brk_types/src/stored_f64.rs +++ b/crates/brk_types/src/stored_f64.rs @@ -5,7 +5,7 @@ use std::{ ops::{Add, AddAssign, Div, Mul, Sub}, }; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_i16.rs b/crates/brk_types/src/stored_i16.rs index f7cf80816..0fa7aca6a 100644 --- a/crates/brk_types/src/stored_i16.rs +++ b/crates/brk_types/src/stored_i16.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_string.rs b/crates/brk_types/src/stored_string.rs index 8d80a0a69..c522dda9b 100644 --- a/crates/brk_types/src/stored_string.rs +++ b/crates/brk_types/src/stored_string.rs @@ -1,7 +1,7 @@ use std::{borrow::Cow, str}; use byteview::ByteView; -use derive_deref::Deref; +use derive_more::Deref; use serde::Serialize; use vecdb::PrintableIndex; diff --git a/crates/brk_types/src/stored_u16.rs b/crates/brk_types/src/stored_u16.rs index 852dc5deb..5cdcd95e1 100644 --- a/crates/brk_types/src/stored_u16.rs +++ b/crates/brk_types/src/stored_u16.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_u32.rs b/crates/brk_types/src/stored_u32.rs index 5dc38f6ed..69eb2e0d5 100644 --- a/crates/brk_types/src/stored_u32.rs +++ b/crates/brk_types/src/stored_u32.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div, Mul}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_u64.rs b/crates/brk_types/src/stored_u64.rs index d263e004f..b114d2a2d 100644 --- a/crates/brk_types/src/stored_u64.rs +++ b/crates/brk_types/src/stored_u64.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/stored_u8.rs b/crates/brk_types/src/stored_u8.rs index ab25af748..d5525c559 100644 --- a/crates/brk_types/src/stored_u8.rs +++ b/crates/brk_types/src/stored_u8.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div}; -use derive_deref::Deref; +use derive_more::Deref; use serde::Serialize; use vecdb::{CheckedSub, Formattable, PrintableIndex}; diff --git a/crates/brk_types/src/timestamp.rs b/crates/brk_types/src/timestamp.rs index a8d19b8e4..51a1d9fec 100644 --- a/crates/brk_types/src/timestamp.rs +++ b/crates/brk_types/src/timestamp.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div}; -use derive_deref::Deref; +use derive_more::Deref; use jiff::{civil::date, tz::TimeZone}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/crates/brk_types/src/treenode.rs b/crates/brk_types/src/treenode.rs index 0fa97e3ec..e302c3b49 100644 --- a/crates/brk_types/src/treenode.rs +++ b/crates/brk_types/src/treenode.rs @@ -121,81 +121,104 @@ impl TreeNode { } } - /// Merges all first-level branches into a single flattened structure. - /// Root-level leaves are placed under BASE key. + /// Wraps a node in a Branch with the given key. + /// Used by #[traversable(wrap = "...")] to produce Branch { key: inner }. + pub fn wrap(key: &str, inner: Self) -> Self { + let mut map = BTreeMap::new(); + map.insert(key.to_string(), inner); + Self::Branch(map) + } + + /// Merges all first-level branches into a single flattened structure (consuming version). + /// Direct leaves use their key (use #[traversable(rename = "...")] to control). + /// Branch children are lifted with their keys. + /// If all resulting children are leaves with the same metric name, collapses to a single leaf. /// Returns None if conflicts are found (same key with incompatible values). - pub fn merge_branches(&self) -> Option { + pub fn merge_branches(self) -> Option { let Self::Branch(tree) = self else { - return Some(self.clone()); + return Some(self); }; let mut merged: BTreeMap = BTreeMap::new(); - for node in tree.values() { + for (key, node) in tree { match node { Self::Leaf(leaf) => { - Self::merge_node(&mut merged, BASE, &Self::Leaf(leaf.clone()))?; + // Direct leaves use their key (which may be renamed via attribute) + Self::merge_node(&mut merged, key, Self::Leaf(leaf))?; } Self::Branch(inner) => { - for (key, inner_node) in inner { - Self::merge_node(&mut merged, key, inner_node)?; + // Lift children from branches with their keys + for (inner_key, inner_node) in inner { + Self::merge_node(&mut merged, inner_key, inner_node)?; } } } } - let result = Self::Branch(merged); - - // Check if all leaves have the same name (can be collapsed) - if let Some(common_leaf) = result.all_leaves_same() { - Some(Self::Leaf(common_leaf)) - } else { - Some(result) - } + // If all children are leaves with the same metric name, collapse into single leaf + Some(Self::try_collapse_same_name_leaves(merged)) } - /// Checks if all leaves in the tree have the same metric name. - /// Returns Some(merged_leaf) if all leaves have the same name, None otherwise. - /// When merging, indexes are unioned together. - fn all_leaves_same(&self) -> Option { - match self { - Self::Leaf(leaf) => Some(leaf.clone()), - Self::Branch(map) => { - let mut common_leaf: Option = None; + /// If all entries in the map are leaves with the same metric name, + /// collapse them into a single leaf with merged indexes. + fn try_collapse_same_name_leaves(map: BTreeMap) -> Self { + if map.is_empty() { + return Self::Branch(map); + } - for node in map.values() { - let node_leaf = node.all_leaves_same()?; + // Check if all entries are leaves with the same name + let mut first_leaf: Option<&MetricLeafWithSchema> = None; + let mut merged_indexes = BTreeSet::new(); - match &mut common_leaf { - None => common_leaf = Some(node_leaf), - Some(existing) if existing.is_same_metric(&node_leaf) => { - existing.merge_indexes(&node_leaf); + for node in map.values() { + match node { + Self::Leaf(leaf) => { + if let Some(first) = &first_leaf { + if leaf.name() != first.name() { + // Different names - can't collapse + return Self::Branch(map); } - Some(_) => return None, + } else { + first_leaf = Some(leaf); } + merged_indexes.extend(leaf.indexes().iter().copied()); + } + Self::Branch(_) => { + // Has non-leaf entries - can't collapse + return Self::Branch(map); } - - common_leaf } } + + // All entries were leaves with the same name + let first = first_leaf.unwrap(); + Self::Leaf(MetricLeafWithSchema::new( + MetricLeaf::new( + first.name().to_string(), + first.value_type().to_string(), + merged_indexes, + ), + first.schema.clone(), + )) } - /// Merges a node into the target map at the given key. + /// Merges a node into the target map at the given key (consuming version). /// Returns None if there's a conflict. fn merge_node( target: &mut BTreeMap, - key: &str, - node: &TreeNode, + key: String, + node: TreeNode, ) -> Option<()> { - match target.get_mut(key) { + match target.get_mut(&key) { None => { - target.insert(key.to_string(), node.clone()); + target.insert(key, node); Some(()) } Some(existing) => { - match (&mut *existing, node) { - (Self::Leaf(a), Self::Leaf(b)) if a.is_same_metric(b) => { - a.merge_indexes(b); + match (existing, node) { + (Self::Leaf(a), Self::Leaf(b)) if a.is_same_metric(&b) => { + a.merge_indexes(&b); Some(()) } (Self::Leaf(a), Self::Leaf(b)) => { @@ -204,19 +227,24 @@ impl TreeNode { eprintln!(" New: {b:?}"); None } - (Self::Leaf(leaf), Self::Branch(branch)) => { - let mut new_branch = BTreeMap::new(); - new_branch.insert(BASE.to_string(), Self::Leaf(leaf.clone())); + (existing @ Self::Leaf(_), Self::Branch(branch)) => { + let Self::Leaf(leaf) = + std::mem::replace(existing, Self::Branch(BTreeMap::new())) + else { + unreachable!() + }; + let Self::Branch(new_branch) = existing else { + unreachable!() + }; + new_branch.insert(BASE.to_string(), Self::Leaf(leaf)); for (k, v) in branch { - Self::merge_node(&mut new_branch, k, v)?; + Self::merge_node(new_branch, k, v)?; } - - *existing = Self::Branch(new_branch); Some(()) } (Self::Branch(existing_branch), Self::Leaf(leaf)) => { - Self::merge_node(existing_branch, BASE, &Self::Leaf(leaf.clone()))?; + Self::merge_node(existing_branch, BASE.to_string(), Self::Leaf(leaf))?; Some(()) } // Both branches: merge recursively @@ -231,12 +259,12 @@ impl TreeNode { } } - /// Recursively simplifies the tree by removing known prefixes from keys. + /// Recursively simplifies the tree by removing known prefixes from keys (consuming version). /// If multiple keys map to the same simplified name, checks for conflicts. /// Returns None if there are conflicts (same simplified key, different values). - pub fn simplify(&self) -> Option { + pub fn simplify(self) -> Option { match self { - Self::Leaf(value) => Some(Self::Leaf(value.clone())), + Self::Leaf(_) => Some(self), Self::Branch(map) => { let mut simplified: BTreeMap = BTreeMap::new(); @@ -249,10 +277,10 @@ impl TreeNode { .iter() .find_map(|prefix| key.strip_prefix(prefix)) .map(String::from) - .unwrap_or_else(|| key.clone()); + .unwrap_or(key); // Try to merge into the result - Self::merge_node(&mut simplified, &simplified_key, &simplified_node)?; + Self::merge_node(&mut simplified, simplified_key, simplified_node)?; } Some(Self::Branch(simplified)) @@ -260,3 +288,972 @@ impl TreeNode { } } } + +#[cfg(test)] +mod tests { + use super::*; + + fn leaf(name: &str, index: Index) -> TreeNode { + TreeNode::Leaf(MetricLeafWithSchema { + leaf: MetricLeaf { + name: name.to_string(), + value_type: "TestType".to_string(), + indexes: BTreeSet::from([index]), + }, + schema: serde_json::Value::Null, + }) + } + + fn branch(children: Vec<(&str, TreeNode)>) -> TreeNode { + TreeNode::Branch( + children + .into_iter() + .map(|(k, v)| (k.to_string(), v)) + .collect(), + ) + } + + fn get_leaf_indexes(node: &TreeNode) -> Option<&BTreeSet> { + match node { + TreeNode::Leaf(l) => Some(&l.leaf.indexes), + _ => None, + } + } + + // ========== Leaf passthrough ========== + + #[test] + fn merge_leaf_passthrough() { + let tree = leaf("metric", Index::Height); + let merged = tree.merge_branches().unwrap(); + assert!(matches!(merged, TreeNode::Leaf(_))); + } + + #[test] + fn merge_empty_branch() { + let tree = branch(vec![]); + let merged = tree.merge_branches().unwrap(); + match merged { + TreeNode::Branch(map) => assert!(map.is_empty()), + _ => panic!("Expected empty branch"), + } + } + + // ========== Direct leaves keep their keys ========== + + #[test] + fn merge_direct_leaves_keep_keys() { + // Direct leaves with different keys stay separate + let tree = branch(vec![ + ("sum", leaf("metric_sum", Index::Height)), + ("cumulative", leaf("metric_cumulative", Index::Height)), + ]); + let merged = tree.merge_branches().unwrap(); + + match merged { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2); + assert!(map.contains_key("sum")); + assert!(map.contains_key("cumulative")); + } + _ => panic!("Expected branch"), + } + } + + // ========== Branch lifting ========== + + #[test] + fn merge_lifts_branch_children() { + // Branch children are lifted to top level with their keys + let tree = branch(vec![( + "weekindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::WeekIndex)), + ("cumulative", leaf("metric_cumulative", Index::WeekIndex)), + ]), + )]); + let merged = tree.merge_branches().unwrap(); + + match merged { + TreeNode::Branch(map) => { + assert!(map.contains_key("sum")); + assert!(map.contains_key("cumulative")); + assert!(!map.contains_key("weekindex")); // Parent key gone + } + _ => panic!("Expected branch"), + } + } + + #[test] + fn merge_multiple_branches_combines_indexes() { + // Multiple branches with same child keys → indexes are merged + let tree = branch(vec![ + ( + "weekindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::WeekIndex)), + ("cumulative", leaf("metric_cumulative", Index::WeekIndex)), + ]), + ), + ( + "monthindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::MonthIndex)), + ("cumulative", leaf("metric_cumulative", Index::MonthIndex)), + ]), + ), + ]); + let merged = tree.merge_branches().unwrap(); + + match merged { + TreeNode::Branch(map) => { + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(sum_indexes.contains(&Index::WeekIndex)); + assert!(sum_indexes.contains(&Index::MonthIndex)); + + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::WeekIndex)); + assert!(cum_indexes.contains(&Index::MonthIndex)); + } + _ => panic!("Expected branch"), + } + } + + // ========== Mixed leaves and branches ========== + + #[test] + fn merge_leaf_merges_with_lifted_branch_child() { + // Direct leaf with key "cumulative" merges with lifted "cumulative" from branch + // This simulates: height_cumulative (renamed) + dateindex branch + let tree = branch(vec![ + ("cumulative", leaf("metric_cumulative", Index::Height)), + ( + "dateindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::DateIndex)), + ("cumulative", leaf("metric_cumulative", Index::DateIndex)), + ]), + ), + ]); + let merged = tree.merge_branches().unwrap(); + + match merged { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2); + + // cumulative merged: Height + DateIndex + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::Height)); + assert!(cum_indexes.contains(&Index::DateIndex)); + + // sum only has DateIndex + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(sum_indexes.contains(&Index::DateIndex)); + assert!(!sum_indexes.contains(&Index::Height)); + } + _ => panic!("Expected branch"), + } + } + + #[test] + fn merge_derived_computed_block_sum_cum_pattern() { + // Simulates DerivedComputedBlockSumCum: + // - height_cumulative (renamed to "cumulative") → direct leaf at Height + // - dateindex → branch with sum/cumulative at DateIndex + // - weekindex (flattened from dates) → branch with sum/cumulative at WeekIndex + // - difficultyepoch → branch with sum/cumulative at DifficultyEpoch + let tree = branch(vec![ + ("cumulative", leaf("metric_cumulative", Index::Height)), + ( + "dateindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::DateIndex)), + ("cumulative", leaf("metric_cumulative", Index::DateIndex)), + ]), + ), + ( + "weekindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::WeekIndex)), + ("cumulative", leaf("metric_cumulative", Index::WeekIndex)), + ]), + ), + ( + "difficultyepoch", + branch(vec![ + ("sum", leaf("metric_sum", Index::DifficultyEpoch)), + ( + "cumulative", + leaf("metric_cumulative", Index::DifficultyEpoch), + ), + ]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + match merged { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2); + + // sum: DateIndex, WeekIndex, DifficultyEpoch (NOT Height) + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(!sum_indexes.contains(&Index::Height)); + assert!(sum_indexes.contains(&Index::DateIndex)); + assert!(sum_indexes.contains(&Index::WeekIndex)); + assert!(sum_indexes.contains(&Index::DifficultyEpoch)); + + // cumulative: Height, DateIndex, WeekIndex, DifficultyEpoch + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::Height)); + assert!(cum_indexes.contains(&Index::DateIndex)); + assert!(cum_indexes.contains(&Index::WeekIndex)); + assert!(cum_indexes.contains(&Index::DifficultyEpoch)); + } + _ => panic!("Expected branch"), + } + } + + // ========== Conflict detection ========== + + #[test] + fn merge_conflict_from_lifted_branches() { + // Two branches lifting children with same key but different metric names → conflict + let tree = branch(vec![ + ("a", branch(vec![("data", leaf("metric_a", Index::Height))])), + ( + "b", + branch(vec![("data", leaf("metric_b", Index::DateIndex))]), + ), + ]); + let result = tree.merge_branches(); + assert!(result.is_none(), "Should detect conflict"); + } + + #[test] + fn merge_no_conflict_same_metric_different_indexes() { + // Same key, same metric name, different indexes → merges indexes → collapses to Leaf + let tree = branch(vec![ + ( + "a", + branch(vec![("sum", leaf("metric_sum", Index::Height))]), + ), + ( + "b", + branch(vec![("sum", leaf("metric_sum", Index::DateIndex))]), + ), + ]); + let result = tree.merge_branches(); + assert!(result.is_some(), "Should merge successfully"); + + let merged = result.unwrap(); + match merged { + TreeNode::Leaf(leaf) => { + assert_eq!(leaf.name(), "metric_sum"); + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::Height)); + assert!(indexes.contains(&Index::DateIndex)); + } + _ => panic!("Expected collapsed Leaf"), + } + } + + // ========== Nested branches ========== + + #[test] + fn merge_nested_branches_flattens_one_level() { + // Merge only flattens one level - nested branches stay as branches + let tree = branch(vec![( + "outer", + branch(vec![( + "inner", + branch(vec![("leaf", leaf("metric", Index::Height))]), + )]), + )]); + let merged = tree.merge_branches().unwrap(); + + // "inner" is lifted to top level but stays as a branch + match merged { + TreeNode::Branch(map) => { + assert!(map.contains_key("inner")); + assert!(matches!(map.get("inner"), Some(TreeNode::Branch(_)))); + } + _ => panic!("Expected branch"), + } + } + + // ========== Collapse same-name leaves ========== + + #[test] + fn collapse_direct_leaf_with_lifted_branches_same_name() { + // ComputedVecsDateLast pattern: + // - dateindex: direct leaf (field name as key) + // - rest (flattened): DerivedDateLast → branches with "last" children + // All leaves have same metric name → collapse to single Leaf + let tree = branch(vec![ + // Direct leaf from dateindex field (no wrap attribute) + ("dateindex", leaf("1m_block_count", Index::DateIndex)), + // Flattened from rest: DerivedDateLast + ( + "weekindex", + branch(vec![("last", leaf("1m_block_count", Index::WeekIndex))]), + ), + ( + "monthindex", + branch(vec![("last", leaf("1m_block_count", Index::MonthIndex))]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // All leaves have same name "1m_block_count" → collapses to single Leaf + match &merged { + TreeNode::Leaf(leaf) => { + assert_eq!(leaf.name(), "1m_block_count"); + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::DateIndex)); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + } + TreeNode::Branch(map) => { + panic!( + "Expected collapsed leaf, got branch: {:?}", + map.keys().collect::>() + ); + } + } + } + + // ========== Case 1: DerivedDateLast (all same metric name) ========== + + #[test] + fn case1_derived_date_last() { + // All leaves have the same metric name, all wrapped as "last" + // All branches lift to same key → collapses to single Leaf + let tree = branch(vec![ + ( + "weekindex", + branch(vec![("last", leaf("1m_block_count", Index::WeekIndex))]), + ), + ( + "monthindex", + branch(vec![("last", leaf("1m_block_count", Index::MonthIndex))]), + ), + ( + "quarterindex", + branch(vec![("last", leaf("1m_block_count", Index::QuarterIndex))]), + ), + ( + "yearindex", + branch(vec![("last", leaf("1m_block_count", Index::YearIndex))]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + match &merged { + TreeNode::Leaf(leaf) => { + assert_eq!(leaf.name(), "1m_block_count"); + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::QuarterIndex)); + assert!(indexes.contains(&Index::YearIndex)); + } + _ => panic!("Expected collapsed Leaf"), + } + } + + // ========== Case 2: SumCum (different aggregations via wrap) ========== + + #[test] + fn case2_sum_cum() { + // SumVec/CumulativeVec use wrap to produce branches + // Multiple time periods, each producing { "sum": Leaf, "cumulative": Leaf } + // These should merge into { "sum": Leaf(all indexes), "cumulative": Leaf(all indexes) } + let tree = branch(vec![ + ( + "dateindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::DateIndex)), + ("cumulative", leaf("metric_cumulative", Index::DateIndex)), + ]), + ), + ( + "weekindex", + branch(vec![ + ("sum", leaf("metric_sum", Index::WeekIndex)), + ("cumulative", leaf("metric_cumulative", Index::WeekIndex)), + ]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // DESIRED: { "sum": Leaf, "cumulative": Leaf } with merged indexes + match merged { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 2); + + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(sum_indexes.contains(&Index::DateIndex)); + assert!(sum_indexes.contains(&Index::WeekIndex)); + + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::DateIndex)); + assert!(cum_indexes.contains(&Index::WeekIndex)); + } + _ => panic!("Expected branch with sum and cumulative"), + } + } + + // ========== Case 3: ComputedBlockSum (base + sum) ========== + + #[test] + fn case3_computed_block_sum() { + // ComputedBlockSum: + // - height: wrap="base" → Branch { "base": Leaf(height) } + // - rest (flatten): DerivedComputedBlockSum → branches with "sum" children + let tree = branch(vec![ + // height wrapped as "base" + ( + "height", + branch(vec![("base", leaf("metric", Index::Height))]), + ), + // rest (flattened) produces branches + ( + "dateindex", + branch(vec![("sum", leaf("metric_sum", Index::DateIndex))]), + ), + ( + "weekindex", + branch(vec![("sum", leaf("metric_sum", Index::WeekIndex))]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // DESIRED: { "base": Leaf(height), "sum": Leaf(dateindex, weekindex) } + match &merged { + TreeNode::Branch(map) => { + assert_eq!( + map.len(), + 2, + "Expected 2 keys 'base' and 'sum', got: {:?}", + map.keys().collect::>() + ); + + // base should have Height only + let base_indexes = get_leaf_indexes(map.get("base").unwrap()).unwrap(); + assert!(base_indexes.contains(&Index::Height)); + assert_eq!(base_indexes.len(), 1); + + // sum should have DateIndex and WeekIndex + let sum_indexes = get_leaf_indexes(map.get("sum").unwrap()).unwrap(); + assert!(!sum_indexes.contains(&Index::Height)); + assert!(sum_indexes.contains(&Index::DateIndex)); + assert!(sum_indexes.contains(&Index::WeekIndex)); + } + _ => panic!("Expected branch"), + } + } + + // ========== Case 4: ComputedBlockLast (base + last) ========== + + #[test] + fn case4_computed_block_last() { + // ComputedBlockLast: + // - height: wrap="base" → Branch { "base": Leaf(height) } + // - rest (flatten): DerivedComputedBlockLast → branches with "last" children + let tree = branch(vec![ + // height wrapped as "base" + ( + "height", + branch(vec![("base", leaf("metric", Index::Height))]), + ), + // rest (flattened) produces branches with "last" key + ( + "dateindex", + branch(vec![("last", leaf("metric_last", Index::DateIndex))]), + ), + ( + "weekindex", + branch(vec![("last", leaf("metric_last", Index::WeekIndex))]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // DESIRED: { "base": Leaf(height), "last": Leaf(dateindex, weekindex) } + match &merged { + TreeNode::Branch(map) => { + assert_eq!( + map.len(), + 2, + "Expected 2 keys 'base' and 'last', got: {:?}", + map.keys().collect::>() + ); + + // base should have Height only + let base_indexes = get_leaf_indexes(map.get("base").unwrap()).unwrap(); + assert!(base_indexes.contains(&Index::Height)); + assert_eq!(base_indexes.len(), 1); + + // last should have DateIndex and WeekIndex + let last_indexes = get_leaf_indexes(map.get("last").unwrap()).unwrap(); + assert!(!last_indexes.contains(&Index::Height)); + assert!(last_indexes.contains(&Index::DateIndex)); + assert!(last_indexes.contains(&Index::WeekIndex)); + } + _ => panic!("Expected branch"), + } + } + + // ========== Case 5: ComputedBlockFull (most complex) ========== + + #[test] + fn case5_computed_block_full() { + // ComputedBlockFull has: + // - height: wrapped as "base" (raw values, not aggregated) + // - rest (flatten): DerivedComputedBlockFull { + // height_cumulative: CumulativeVec → Branch{"cumulative": Leaf} + // dateindex: Full → Branch{avg, min, max, sum, cumulative} + // dates (flatten): more aggregation branches + // } + let tree = branch(vec![ + // height wrapped as "base" (raw values at height granularity) + ( + "height", + branch(vec![("base", leaf("metric", Index::Height))]), + ), + // height_cumulative wrapped as cumulative + ( + "height_cumulative", + branch(vec![( + "cumulative", + leaf("metric_cumulative", Index::Height), + )]), + ), + // dateindex Full + ( + "dateindex", + branch(vec![ + ("average", leaf("metric_average", Index::DateIndex)), + ("min", leaf("metric_min", Index::DateIndex)), + ("max", leaf("metric_max", Index::DateIndex)), + ("sum", leaf("metric_sum", Index::DateIndex)), + ("cumulative", leaf("metric_cumulative", Index::DateIndex)), + ]), + ), + // weekindex (from flattened dates) + ( + "weekindex", + branch(vec![ + ("average", leaf("metric_average", Index::WeekIndex)), + ("min", leaf("metric_min", Index::WeekIndex)), + ("max", leaf("metric_max", Index::WeekIndex)), + ("sum", leaf("metric_sum", Index::WeekIndex)), + ("cumulative", leaf("metric_cumulative", Index::WeekIndex)), + ]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // DESIRED: { base, average, min, max, sum, cumulative } each with merged indexes + match &merged { + TreeNode::Branch(map) => { + assert_eq!( + map.len(), + 6, + "Expected 6 keys, got: {:?}", + map.keys().collect::>() + ); + + // base should have Height only + let base_indexes = get_leaf_indexes(map.get("base").unwrap()).unwrap(); + assert!(base_indexes.contains(&Index::Height)); + assert_eq!(base_indexes.len(), 1); + + // cumulative should include Height (from height_cumulative) + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!( + cum_indexes.contains(&Index::Height), + "cumulative should include Height" + ); + assert!(cum_indexes.contains(&Index::DateIndex)); + assert!(cum_indexes.contains(&Index::WeekIndex)); + + // average, min, max, sum should have DateIndex and WeekIndex only + for key in ["average", "min", "max", "sum"] { + let indexes = get_leaf_indexes(map.get(key).unwrap()).unwrap(); + assert!(!indexes.contains(&Index::Height)); + assert!(indexes.contains(&Index::DateIndex)); + assert!(indexes.contains(&Index::WeekIndex)); + } + } + _ => panic!("Expected branch"), + } + } + + // ========== Case 6: LazyDateLast (all branches with same inner key) ========== + + #[test] + fn case6_lazy_date_last_all_branches_same_key_collapses() { + // LazyDateLast pattern: All fields are branches with same inner key "last" + // All leaves have the same metric name → should collapse to single Leaf + let tree = branch(vec![ + ( + "dateindex", + branch(vec![("last", leaf("price_200d_sma", Index::DateIndex))]), + ), + ( + "weekindex", + branch(vec![("last", leaf("price_200d_sma", Index::WeekIndex))]), + ), + ( + "monthindex", + branch(vec![("last", leaf("price_200d_sma", Index::MonthIndex))]), + ), + ( + "quarterindex", + branch(vec![("last", leaf("price_200d_sma", Index::QuarterIndex))]), + ), + ( + "yearindex", + branch(vec![("last", leaf("price_200d_sma", Index::YearIndex))]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // All branches lifted to same "last" key, all same metric name → collapse to Leaf + match &merged { + TreeNode::Leaf(leaf) => { + assert_eq!(leaf.name(), "price_200d_sma"); + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::DateIndex)); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::QuarterIndex)); + assert!(indexes.contains(&Index::YearIndex)); + } + TreeNode::Branch(map) => { + panic!( + "Expected collapsed Leaf, got Branch with keys: {:?}", + map.keys().collect::>() + ); + } + } + } + + // ========== Case 7: LazyBlockValue ========== + // LazyBlockValue (no merge): + // - sats: LazyVecFrom1 with wrap="sats" + // - rest: LazyDerivedBlockValue with flatten + // - bitcoin: LazyVecFrom1 (plain field) + // - dollars: Option (plain field) + + #[test] + fn case7_lazy_block_value() { + // Simulates the tree produced by LazyBlockValue + // sats wrapped, rest flattened with bitcoin/dollars as plain leaves + let tree = branch(vec![ + // sats with wrap="sats" produces Branch { sats: Leaf } + ("sats", branch(vec![("sats", leaf("metric", Index::Height))])), + // rest with flatten: LazyDerivedBlockValue fields lifted + ( + "rest", + branch(vec![ + ("bitcoin", leaf("metric_btc", Index::Height)), + ("dollars", leaf("metric_usd", Index::Height)), + ]), + ), + ]); + + // After merge_branches: lifts children, flattens rest + let merged = tree.merge_branches().unwrap(); + + match &merged { + TreeNode::Branch(map) => { + assert_eq!( + map.len(), + 3, + "Expected sats, bitcoin, dollars. Got: {:?}", + map.keys().collect::>() + ); + assert!(matches!(map.get("sats"), Some(TreeNode::Leaf(_)))); + assert!(matches!(map.get("bitcoin"), Some(TreeNode::Leaf(_)))); + assert!(matches!(map.get("dollars"), Some(TreeNode::Leaf(_)))); + } + _ => panic!("Expected branch"), + } + } + + // ========== Case 8: BinaryBlockSumCum ========== + // After derive applies all inner merges and flatten, before parent merge: + // - height wrapped as "base" → { base: Leaf(Height) } + // - height_cumulative wrapped as "cumulative" → { cumulative: Leaf(Height) } + // - rest (flatten): children from already-merged inner struct inserted directly + // + // The key insight: inner types have merge applied BEFORE flatten lifts them. + // So rest.to_tree_node() returns merged { sum, cumulative } directly. + + #[test] + fn case8_binary_block_sum_cum() { + // Tree AFTER derive applies inner merges, flatten lifts rest's children: + let tree = branch(vec![ + // height with wrap="base" + ( + "height", + branch(vec![("base", leaf("metric", Index::Height))]), + ), + // height_cumulative with wrap="cumulative" + ( + "height_cumulative", + branch(vec![( + "cumulative", + leaf("metric_cumulative", Index::Height), + )]), + ), + // From rest (flatten) - inner struct already merged to { sum, cumulative } + // Each leaf has merged indexes from all time periods + ( + "sum", + leaf("metric_sum", Index::DateIndex), // Would have all time indexes + ), + ( + "cumulative", + leaf("metric_cumulative", Index::DateIndex), // Would have all time indexes + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // Expected: { base, sum, cumulative } + match &merged { + TreeNode::Branch(map) => { + assert_eq!( + map.len(), + 3, + "Expected base, sum, cumulative. Got: {:?}", + map.keys().collect::>() + ); + + // base: only Height + let base_indexes = get_leaf_indexes(map.get("base").unwrap()).unwrap(); + assert_eq!(base_indexes.len(), 1); + assert!(base_indexes.contains(&Index::Height)); + + // sum: from flattened rest + assert!(matches!(map.get("sum"), Some(TreeNode::Leaf(_)))); + + // cumulative: Height merged with rest's cumulative + let cum_indexes = get_leaf_indexes(map.get("cumulative").unwrap()).unwrap(); + assert!(cum_indexes.contains(&Index::Height)); + assert!(cum_indexes.contains(&Index::DateIndex)); + } + _ => panic!("Expected branch"), + } + } + + // ========== Case 9: ValueBlockSumCum (outer no merge, inner has merge) ========== + // ValueBlockSumCum (no merge): + // - sats: ComputedBlockSumCum (merge) → { base, sum, cumulative } + // - bitcoin: LazyBlockSumCum (merge) → { base, sum, cumulative } + // - dollars: Option> (merge) → { base, sum, cumulative } + + #[test] + fn case9_value_block_sum_cum() { + // Each denomination has already been merged internally + // Simulating the output after inner merge + let sats_merged = branch(vec![ + ("base", leaf("metric", Index::Height)), + ("sum", leaf("metric_sum", Index::DateIndex)), + ("cumulative", leaf("metric_cumulative", Index::Height)), + ]); + + let bitcoin_merged = branch(vec![ + ("base", leaf("metric_btc", Index::Height)), + ("sum", leaf("metric_btc_sum", Index::DateIndex)), + ("cumulative", leaf("metric_btc_cumulative", Index::Height)), + ]); + + let dollars_merged = branch(vec![ + ("base", leaf("metric_usd", Index::Height)), + ("sum", leaf("metric_usd_sum", Index::DateIndex)), + ("cumulative", leaf("metric_usd_cumulative", Index::Height)), + ]); + + // Outer struct has no merge, so denominations stay as branches + let tree = branch(vec![ + ("sats", sats_merged), + ("bitcoin", bitcoin_merged), + ("dollars", dollars_merged), + ]); + + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3); + + for denom in ["sats", "bitcoin", "dollars"] { + match map.get(denom) { + Some(TreeNode::Branch(inner)) => { + assert_eq!(inner.len(), 3); + assert!(inner.contains_key("base")); + assert!(inner.contains_key("sum")); + assert!(inner.contains_key("cumulative")); + } + _ => panic!("Expected branch for {}", denom), + } + } + } + _ => panic!("Expected branch"), + } + } + + // ========== Case 10: ValueDateLast structure ========== + // Testing individual components of ValueDateLast + + #[test] + fn case10_derived_date_last_collapses_to_leaf() { + // DerivedDateLast with merge: all fields have wrap="last" + // weekindex: { last: Leaf }, monthindex: { last: Leaf }, etc. + // After merge: all "last" keys merge, same metric name → collapses to Leaf + let tree = branch(vec![ + ( + "weekindex", + branch(vec![("last", leaf("metric", Index::WeekIndex))]), + ), + ( + "monthindex", + branch(vec![("last", leaf("metric", Index::MonthIndex))]), + ), + ( + "yearindex", + branch(vec![("last", leaf("metric", Index::YearIndex))]), + ), + ]); + + let merged = tree.merge_branches().unwrap(); + + // Should collapse to single Leaf with all indexes + match &merged { + TreeNode::Leaf(leaf) => { + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::WeekIndex)); + assert!(indexes.contains(&Index::MonthIndex)); + assert!(indexes.contains(&Index::YearIndex)); + } + TreeNode::Branch(map) => { + panic!("Expected Leaf, got Branch: {:?}", map.keys().collect::>()); + } + } + } + + #[test] + fn case10_computed_date_last_collapses_to_leaf() { + // ComputedDateLast with merge: + // - dateindex with wrap="base" → { base: Leaf } + // - rest (flatten): DerivedDateLast already merged to Leaf + // → flatten inserts with field name "rest" as key + // + // Both have same metric name → collapses to single Leaf + let tree = branch(vec![ + // dateindex with wrap="base" + ( + "dateindex", + branch(vec![("base", leaf("metric", Index::DateIndex))]), + ), + // rest (flatten): DerivedDateLast merged to Leaf + // Same metric name as base + ("rest", leaf("metric", Index::WeekIndex)), + ]); + + let merged = tree.merge_branches().unwrap(); + + // Same metric name → collapses to single Leaf with all indexes + match &merged { + TreeNode::Leaf(leaf) => { + let indexes = leaf.indexes(); + assert!(indexes.contains(&Index::DateIndex)); + assert!(indexes.contains(&Index::WeekIndex)); + } + TreeNode::Branch(map) => { + panic!("Expected Leaf, got Branch: {:?}", map.keys().collect::>()); + } + } + } + + // ========== Case 11: ValueDateLast conflict detection ========== + + #[test] + fn case11_value_date_last_sats_key_conflict() { + // ValueDateLast has a structural issue: + // - sats_dateindex with wrap="sats" produces key "sats" + // - rest (flatten) has field "sats" (DerivedDateLast) + // Both try to use the same "sats" key! + + // Simulating the pre-merge structure + let tree = branch(vec![ + // From sats_dateindex with wrap="sats" + ( + "sats_dateindex", + branch(vec![("sats", leaf("metric", Index::DateIndex))]), + ), + // From rest (flatten): ValueDerivedDateLast + ( + "rest", + branch(vec![ + // sats field: DerivedDateLast merged to Leaf + ("sats", leaf("metric", Index::WeekIndex)), // Same metric name! + ("bitcoin", leaf("metric_btc", Index::DateIndex)), + ("dollars", leaf("metric_usd", Index::DateIndex)), + ]), + ), + ]); + + let merged = tree.merge_branches(); + + // Should succeed because both "sats" have the same metric name + // Indexes should be merged + match merged { + Some(TreeNode::Branch(map)) => { + let sats_indexes = get_leaf_indexes(map.get("sats").unwrap()).unwrap(); + assert!(sats_indexes.contains(&Index::DateIndex)); + assert!(sats_indexes.contains(&Index::WeekIndex)); + } + Some(_) => panic!("Expected branch"), + None => panic!("Unexpected conflict"), + } + } + + // ========== Case 12: ValueDateLast ideal output ========== + + #[test] + fn case12_value_date_last_ideal_output() { + // The IDEAL output for ValueDateLast: + // { sats: Leaf(all indexes), bitcoin: Leaf(all indexes), dollars: Leaf(all indexes) } + // + // This requires: + // 1. Each denomination collapses its time indexes into one Leaf + // 2. Denominations stay as separate siblings + + // Simulating final merged output + let tree = branch(vec![ + ("sats", leaf("metric", Index::DateIndex)), // placeholder, would have all indexes + ("bitcoin", leaf("metric_btc", Index::DateIndex)), + ("dollars", leaf("metric_usd", Index::DateIndex)), + ]); + + match &tree { + TreeNode::Branch(map) => { + assert_eq!(map.len(), 3); + assert!(matches!(map.get("sats"), Some(TreeNode::Leaf(_)))); + assert!(matches!(map.get("bitcoin"), Some(TreeNode::Leaf(_)))); + assert!(matches!(map.get("dollars"), Some(TreeNode::Leaf(_)))); + } + _ => panic!("Expected branch with 3 denomination leaves"), + } + } +} diff --git a/crates/brk_types/src/txid.rs b/crates/brk_types/src/txid.rs index e31c7914a..f55ec32c5 100644 --- a/crates/brk_types/src/txid.rs +++ b/crates/brk_types/src/txid.rs @@ -1,7 +1,7 @@ use std::{fmt, mem, str::FromStr}; use bitcoin::hashes::Hash; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/txidprefix.rs b/crates/brk_types/src/txidprefix.rs index d47892448..7f0d0b801 100644 --- a/crates/brk_types/src/txidprefix.rs +++ b/crates/brk_types/src/txidprefix.rs @@ -1,5 +1,5 @@ use byteview::ByteView; -use derive_deref::Deref; +use derive_more::Deref; use super::Txid; diff --git a/crates/brk_types/src/txindex.rs b/crates/brk_types/src/txindex.rs index b46920d84..5bebf1b14 100644 --- a/crates/brk_types/src/txindex.rs +++ b/crates/brk_types/src/txindex.rs @@ -1,7 +1,7 @@ use std::ops::{Add, AddAssign}; use byteview::ByteView; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/txinindex.rs b/crates/brk_types/src/txinindex.rs index c2d9144b9..aed24f9f2 100644 --- a/crates/brk_types/src/txinindex.rs +++ b/crates/brk_types/src/txinindex.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/txoutindex.rs b/crates/brk_types/src/txoutindex.rs index ed3134e47..90cbe60fb 100644 --- a/crates/brk_types/src/txoutindex.rs +++ b/crates/brk_types/src/txoutindex.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign}; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/txversion.rs b/crates/brk_types/src/txversion.rs index 7e482b34c..aa8719345 100644 --- a/crates/brk_types/src/txversion.rs +++ b/crates/brk_types/src/txversion.rs @@ -1,4 +1,4 @@ -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Formattable, Pco}; diff --git a/crates/brk_types/src/unknownoutputindex.rs b/crates/brk_types/src/unknownoutputindex.rs index e2ed8eefe..5fd17704e 100644 --- a/crates/brk_types/src/unknownoutputindex.rs +++ b/crates/brk_types/src/unknownoutputindex.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use derive_deref::{Deref, DerefMut}; +use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; diff --git a/crates/brk_types/src/vin.rs b/crates/brk_types/src/vin.rs index 56f0bd4ba..b5fce8bc1 100644 --- a/crates/brk_types/src/vin.rs +++ b/crates/brk_types/src/vin.rs @@ -1,4 +1,4 @@ -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/crates/brk_types/src/vout.rs b/crates/brk_types/src/vout.rs index 3da35f9f1..a24429694 100644 --- a/crates/brk_types/src/vout.rs +++ b/crates/brk_types/src/vout.rs @@ -1,4 +1,4 @@ -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; diff --git a/crates/brk_types/src/vsize.rs b/crates/brk_types/src/vsize.rs index a4cd4c794..cbf5190ed 100644 --- a/crates/brk_types/src/vsize.rs +++ b/crates/brk_types/src/vsize.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div, Sub, SubAssign}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Formattable, Pco}; diff --git a/crates/brk_types/src/weight.rs b/crates/brk_types/src/weight.rs index 6b1eb6ef9..7754219e5 100644 --- a/crates/brk_types/src/weight.rs +++ b/crates/brk_types/src/weight.rs @@ -1,6 +1,6 @@ use std::ops::{Add, AddAssign, Div}; -use derive_deref::Deref; +use derive_more::Deref; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Formattable, Pco}; diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 2aa0db3f3..bf4163652 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -240,13 +240,6 @@ * @property {number} lazyEndpoints * @property {number} storedEndpoints */ -/** - * @typedef {Object} MetricData - * @property {number} total - * @property {number} from - * @property {number} to - * @property {*[]} data - */ /** * @typedef {Object} MetricLeafWithSchema * @property {string} name @@ -548,19 +541,30 @@ class BrkError extends Error { /** * @template T - * @typedef {Object} Endpoint - * @property {(onUpdate?: (value: T[]) => void) => Promise} get - Fetch all data points - * @property {(from?: number, to?: number, onUpdate?: (value: T[]) => void) => Promise} range - Fetch data in range + * @typedef {Object} MetricData + * @property {number} total - Total number of data points + * @property {number} from - Start index (inclusive) + * @property {number} to - End index (exclusive) + * @property {T[]} data - The metric data + */ +/** @typedef {MetricData} AnyMetricData */ + +/** + * @template T + * @typedef {Object} MetricEndpoint + * @property {(onUpdate?: (value: MetricData) => void) => Promise>} get - Fetch all data points + * @property {(from?: number, to?: number, onUpdate?: (value: MetricData) => void) => Promise>} range - Fetch data in range * @property {string} path - The endpoint path */ +/** @typedef {MetricEndpoint} AnyMetricEndpoint */ /** * @template T * @typedef {Object} MetricPattern * @property {string} name - The metric name - * @property {Partial>>} by - Index endpoints (lazy getters) + * @property {Partial>>} by - Index endpoints (lazy getters) * @property {() => Index[]} indexes - Get the list of available indexes - * @property {(index: Index) => Endpoint|undefined} get - Get an endpoint for a specific index + * @property {(index: Index) => MetricEndpoint|undefined} get - Get an endpoint for a specific index */ /** @typedef {MetricPattern} AnyMetricPattern */ @@ -571,7 +575,7 @@ class BrkError extends Error { * @param {BrkClientBase} client * @param {string} name - The metric vec name * @param {Index} index - The index name - * @returns {Endpoint} + * @returns {MetricEndpoint} */ function _endpoint(client, name, index) { const p = `/api/metric/${name}/${index}`; @@ -651,7 +655,7 @@ const _m = (acc, s) => acc ? `${acc}_${s}` : s; /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, decadeindex: Endpoint, difficultyepoch: Endpoint, height: Endpoint, monthindex: Endpoint, quarterindex: Endpoint, semesterindex: Endpoint, weekindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern1 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, decadeindex: MetricEndpoint, difficultyepoch: MetricEndpoint, height: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern1 */ /** @@ -688,7 +692,7 @@ function createMetricPattern1(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, decadeindex: Endpoint, difficultyepoch: Endpoint, monthindex: Endpoint, quarterindex: Endpoint, semesterindex: Endpoint, weekindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern2 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, decadeindex: MetricEndpoint, difficultyepoch: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern2 */ /** @@ -724,7 +728,7 @@ function createMetricPattern2(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, decadeindex: Endpoint, height: Endpoint, monthindex: Endpoint, quarterindex: Endpoint, semesterindex: Endpoint, weekindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern3 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, decadeindex: MetricEndpoint, height: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern3 */ /** @@ -760,7 +764,7 @@ function createMetricPattern3(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, decadeindex: Endpoint, monthindex: Endpoint, quarterindex: Endpoint, semesterindex: Endpoint, weekindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern4 + * @typedef {{ name: string, by: { decadeindex: MetricEndpoint, difficultyepoch: MetricEndpoint, height: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern4 */ /** @@ -771,6 +775,42 @@ function createMetricPattern3(client, name) { * @returns {MetricPattern4} */ function createMetricPattern4(client, name) { + return { + name, + by: { + get decadeindex() { return _endpoint(client, name, 'decadeindex'); }, + get difficultyepoch() { return _endpoint(client, name, 'difficultyepoch'); }, + get height() { return _endpoint(client, name, 'height'); }, + get monthindex() { return _endpoint(client, name, 'monthindex'); }, + get quarterindex() { return _endpoint(client, name, 'quarterindex'); }, + get semesterindex() { return _endpoint(client, name, 'semesterindex'); }, + get weekindex() { return _endpoint(client, name, 'weekindex'); }, + get yearindex() { return _endpoint(client, name, 'yearindex'); } + }, + indexes() { + return ['decadeindex', 'difficultyepoch', 'height', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex']; + }, + get(index) { + if (this.indexes().includes(index)) { + return _endpoint(client, name, index); + } + } + }; +} + +/** + * @template T + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, decadeindex: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern5 + */ + +/** + * Create a MetricPattern5 accessor + * @template T + * @param {BrkClientBase} client + * @param {string} name - The metric vec name + * @returns {MetricPattern5} + */ +function createMetricPattern5(client, name) { return { name, by: { @@ -795,22 +835,22 @@ function createMetricPattern4(client, name) { /** * @template T - * @typedef {{ name: string, by: { decadeindex: Endpoint, height: Endpoint, monthindex: Endpoint, quarterindex: Endpoint, semesterindex: Endpoint, weekindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern5 + * @typedef {{ name: string, by: { decadeindex: MetricEndpoint, difficultyepoch: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern6 */ /** - * Create a MetricPattern5 accessor + * Create a MetricPattern6 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern5} + * @returns {MetricPattern6} */ -function createMetricPattern5(client, name) { +function createMetricPattern6(client, name) { return { name, by: { get decadeindex() { return _endpoint(client, name, 'decadeindex'); }, - get height() { return _endpoint(client, name, 'height'); }, + get difficultyepoch() { return _endpoint(client, name, 'difficultyepoch'); }, get monthindex() { return _endpoint(client, name, 'monthindex'); }, get quarterindex() { return _endpoint(client, name, 'quarterindex'); }, get semesterindex() { return _endpoint(client, name, 'semesterindex'); }, @@ -818,7 +858,7 @@ function createMetricPattern5(client, name) { get yearindex() { return _endpoint(client, name, 'yearindex'); } }, indexes() { - return ['decadeindex', 'height', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex']; + return ['decadeindex', 'difficultyepoch', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex']; }, get(index) { if (this.indexes().includes(index)) { @@ -830,17 +870,17 @@ function createMetricPattern5(client, name) { /** * @template T - * @typedef {{ name: string, by: { decadeindex: Endpoint, monthindex: Endpoint, quarterindex: Endpoint, semesterindex: Endpoint, weekindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern6 + * @typedef {{ name: string, by: { decadeindex: MetricEndpoint, monthindex: MetricEndpoint, quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, weekindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern7 */ /** - * Create a MetricPattern6 accessor + * Create a MetricPattern7 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern6} + * @returns {MetricPattern7} */ -function createMetricPattern6(client, name) { +function createMetricPattern7(client, name) { return { name, by: { @@ -864,17 +904,17 @@ function createMetricPattern6(client, name) { /** * @template T - * @typedef {{ name: string, by: { emptyoutputindex: Endpoint, opreturnindex: Endpoint, p2msoutputindex: Endpoint, unknownoutputindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern7 + * @typedef {{ name: string, by: { emptyoutputindex: MetricEndpoint, opreturnindex: MetricEndpoint, p2msoutputindex: MetricEndpoint, unknownoutputindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern8 */ /** - * Create a MetricPattern7 accessor + * Create a MetricPattern8 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern7} + * @returns {MetricPattern8} */ -function createMetricPattern7(client, name) { +function createMetricPattern8(client, name) { return { name, by: { @@ -896,17 +936,17 @@ function createMetricPattern7(client, name) { /** * @template T - * @typedef {{ name: string, by: { quarterindex: Endpoint, semesterindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern8 + * @typedef {{ name: string, by: { quarterindex: MetricEndpoint, semesterindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern9 */ /** - * Create a MetricPattern8 accessor + * Create a MetricPattern9 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern8} + * @returns {MetricPattern9} */ -function createMetricPattern8(client, name) { +function createMetricPattern9(client, name) { return { name, by: { @@ -927,17 +967,17 @@ function createMetricPattern8(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, height: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern9 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, height: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern10 */ /** - * Create a MetricPattern9 accessor + * Create a MetricPattern10 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern9} + * @returns {MetricPattern10} */ -function createMetricPattern9(client, name) { +function createMetricPattern10(client, name) { return { name, by: { @@ -957,17 +997,17 @@ function createMetricPattern9(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, monthindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern10 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, monthindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern11 */ /** - * Create a MetricPattern10 accessor + * Create a MetricPattern11 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern10} + * @returns {MetricPattern11} */ -function createMetricPattern10(client, name) { +function createMetricPattern11(client, name) { return { name, by: { @@ -987,17 +1027,17 @@ function createMetricPattern10(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint, weekindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern11 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint, weekindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern12 */ /** - * Create a MetricPattern11 accessor + * Create a MetricPattern12 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern11} + * @returns {MetricPattern12} */ -function createMetricPattern11(client, name) { +function createMetricPattern12(client, name) { return { name, by: { @@ -1017,17 +1057,17 @@ function createMetricPattern11(client, name) { /** * @template T - * @typedef {{ name: string, by: { decadeindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern12 + * @typedef {{ name: string, by: { decadeindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern13 */ /** - * Create a MetricPattern12 accessor + * Create a MetricPattern13 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern12} + * @returns {MetricPattern13} */ -function createMetricPattern12(client, name) { +function createMetricPattern13(client, name) { return { name, by: { @@ -1047,17 +1087,17 @@ function createMetricPattern12(client, name) { /** * @template T - * @typedef {{ name: string, by: { difficultyepoch: Endpoint, halvingepoch: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern13 + * @typedef {{ name: string, by: { difficultyepoch: MetricEndpoint, halvingepoch: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern14 */ /** - * Create a MetricPattern13 accessor + * Create a MetricPattern14 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern13} + * @returns {MetricPattern14} */ -function createMetricPattern13(client, name) { +function createMetricPattern14(client, name) { return { name, by: { @@ -1077,17 +1117,17 @@ function createMetricPattern13(client, name) { /** * @template T - * @typedef {{ name: string, by: { difficultyepoch: Endpoint, height: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern14 + * @typedef {{ name: string, by: { difficultyepoch: MetricEndpoint, height: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern15 */ /** - * Create a MetricPattern14 accessor + * Create a MetricPattern15 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern14} + * @returns {MetricPattern15} */ -function createMetricPattern14(client, name) { +function createMetricPattern15(client, name) { return { name, by: { @@ -1107,17 +1147,17 @@ function createMetricPattern14(client, name) { /** * @template T - * @typedef {{ name: string, by: { halvingepoch: Endpoint, height: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern15 + * @typedef {{ name: string, by: { halvingepoch: MetricEndpoint, height: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern16 */ /** - * Create a MetricPattern15 accessor + * Create a MetricPattern16 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern15} + * @returns {MetricPattern16} */ -function createMetricPattern15(client, name) { +function createMetricPattern16(client, name) { return { name, by: { @@ -1137,17 +1177,17 @@ function createMetricPattern15(client, name) { /** * @template T - * @typedef {{ name: string, by: { height: Endpoint, txindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern16 + * @typedef {{ name: string, by: { height: MetricEndpoint, txindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern17 */ /** - * Create a MetricPattern16 accessor + * Create a MetricPattern17 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern16} + * @returns {MetricPattern17} */ -function createMetricPattern16(client, name) { +function createMetricPattern17(client, name) { return { name, by: { @@ -1167,17 +1207,17 @@ function createMetricPattern16(client, name) { /** * @template T - * @typedef {{ name: string, by: { monthindex: Endpoint, quarterindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern17 + * @typedef {{ name: string, by: { monthindex: MetricEndpoint, quarterindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern18 */ /** - * Create a MetricPattern17 accessor + * Create a MetricPattern18 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern17} + * @returns {MetricPattern18} */ -function createMetricPattern17(client, name) { +function createMetricPattern18(client, name) { return { name, by: { @@ -1197,17 +1237,17 @@ function createMetricPattern17(client, name) { /** * @template T - * @typedef {{ name: string, by: { monthindex: Endpoint, semesterindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern18 + * @typedef {{ name: string, by: { monthindex: MetricEndpoint, semesterindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern19 */ /** - * Create a MetricPattern18 accessor + * Create a MetricPattern19 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern18} + * @returns {MetricPattern19} */ -function createMetricPattern18(client, name) { +function createMetricPattern19(client, name) { return { name, by: { @@ -1227,17 +1267,17 @@ function createMetricPattern18(client, name) { /** * @template T - * @typedef {{ name: string, by: { monthindex: Endpoint, weekindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern19 + * @typedef {{ name: string, by: { monthindex: MetricEndpoint, weekindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern20 */ /** - * Create a MetricPattern19 accessor + * Create a MetricPattern20 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern19} + * @returns {MetricPattern20} */ -function createMetricPattern19(client, name) { +function createMetricPattern20(client, name) { return { name, by: { @@ -1257,17 +1297,17 @@ function createMetricPattern19(client, name) { /** * @template T - * @typedef {{ name: string, by: { monthindex: Endpoint, yearindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern20 + * @typedef {{ name: string, by: { monthindex: MetricEndpoint, yearindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern21 */ /** - * Create a MetricPattern20 accessor + * Create a MetricPattern21 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern20} + * @returns {MetricPattern21} */ -function createMetricPattern20(client, name) { +function createMetricPattern21(client, name) { return { name, by: { @@ -1287,17 +1327,17 @@ function createMetricPattern20(client, name) { /** * @template T - * @typedef {{ name: string, by: { dateindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern21 + * @typedef {{ name: string, by: { dateindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern22 */ /** - * Create a MetricPattern21 accessor + * Create a MetricPattern22 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern21} + * @returns {MetricPattern22} */ -function createMetricPattern21(client, name) { +function createMetricPattern22(client, name) { return { name, by: { @@ -1316,17 +1356,17 @@ function createMetricPattern21(client, name) { /** * @template T - * @typedef {{ name: string, by: { decadeindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern22 + * @typedef {{ name: string, by: { decadeindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern23 */ /** - * Create a MetricPattern22 accessor + * Create a MetricPattern23 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern22} + * @returns {MetricPattern23} */ -function createMetricPattern22(client, name) { +function createMetricPattern23(client, name) { return { name, by: { @@ -1345,17 +1385,17 @@ function createMetricPattern22(client, name) { /** * @template T - * @typedef {{ name: string, by: { difficultyepoch: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern23 + * @typedef {{ name: string, by: { difficultyepoch: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern24 */ /** - * Create a MetricPattern23 accessor + * Create a MetricPattern24 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern23} + * @returns {MetricPattern24} */ -function createMetricPattern23(client, name) { +function createMetricPattern24(client, name) { return { name, by: { @@ -1374,17 +1414,17 @@ function createMetricPattern23(client, name) { /** * @template T - * @typedef {{ name: string, by: { emptyoutputindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern24 + * @typedef {{ name: string, by: { emptyoutputindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern25 */ /** - * Create a MetricPattern24 accessor + * Create a MetricPattern25 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern24} + * @returns {MetricPattern25} */ -function createMetricPattern24(client, name) { +function createMetricPattern25(client, name) { return { name, by: { @@ -1403,17 +1443,17 @@ function createMetricPattern24(client, name) { /** * @template T - * @typedef {{ name: string, by: { height: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern25 + * @typedef {{ name: string, by: { height: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern26 */ /** - * Create a MetricPattern25 accessor + * Create a MetricPattern26 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern25} + * @returns {MetricPattern26} */ -function createMetricPattern25(client, name) { +function createMetricPattern26(client, name) { return { name, by: { @@ -1432,17 +1472,17 @@ function createMetricPattern25(client, name) { /** * @template T - * @typedef {{ name: string, by: { txinindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern26 + * @typedef {{ name: string, by: { txinindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern27 */ /** - * Create a MetricPattern26 accessor + * Create a MetricPattern27 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern26} + * @returns {MetricPattern27} */ -function createMetricPattern26(client, name) { +function createMetricPattern27(client, name) { return { name, by: { @@ -1461,17 +1501,17 @@ function createMetricPattern26(client, name) { /** * @template T - * @typedef {{ name: string, by: { opreturnindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern27 + * @typedef {{ name: string, by: { opreturnindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern28 */ /** - * Create a MetricPattern27 accessor + * Create a MetricPattern28 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern27} + * @returns {MetricPattern28} */ -function createMetricPattern27(client, name) { +function createMetricPattern28(client, name) { return { name, by: { @@ -1490,17 +1530,17 @@ function createMetricPattern27(client, name) { /** * @template T - * @typedef {{ name: string, by: { txoutindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern28 + * @typedef {{ name: string, by: { txoutindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern29 */ /** - * Create a MetricPattern28 accessor + * Create a MetricPattern29 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern28} + * @returns {MetricPattern29} */ -function createMetricPattern28(client, name) { +function createMetricPattern29(client, name) { return { name, by: { @@ -1519,17 +1559,17 @@ function createMetricPattern28(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2aaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern29 + * @typedef {{ name: string, by: { p2aaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern30 */ /** - * Create a MetricPattern29 accessor + * Create a MetricPattern30 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern29} + * @returns {MetricPattern30} */ -function createMetricPattern29(client, name) { +function createMetricPattern30(client, name) { return { name, by: { @@ -1548,17 +1588,17 @@ function createMetricPattern29(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2msoutputindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern30 + * @typedef {{ name: string, by: { p2msoutputindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern31 */ /** - * Create a MetricPattern30 accessor + * Create a MetricPattern31 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern30} + * @returns {MetricPattern31} */ -function createMetricPattern30(client, name) { +function createMetricPattern31(client, name) { return { name, by: { @@ -1577,17 +1617,17 @@ function createMetricPattern30(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2pk33addressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern31 + * @typedef {{ name: string, by: { p2pk33addressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern32 */ /** - * Create a MetricPattern31 accessor + * Create a MetricPattern32 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern31} + * @returns {MetricPattern32} */ -function createMetricPattern31(client, name) { +function createMetricPattern32(client, name) { return { name, by: { @@ -1606,17 +1646,17 @@ function createMetricPattern31(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2pk65addressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern32 + * @typedef {{ name: string, by: { p2pk65addressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern33 */ /** - * Create a MetricPattern32 accessor + * Create a MetricPattern33 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern32} + * @returns {MetricPattern33} */ -function createMetricPattern32(client, name) { +function createMetricPattern33(client, name) { return { name, by: { @@ -1635,17 +1675,17 @@ function createMetricPattern32(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2pkhaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern33 + * @typedef {{ name: string, by: { p2pkhaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern34 */ /** - * Create a MetricPattern33 accessor + * Create a MetricPattern34 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern33} + * @returns {MetricPattern34} */ -function createMetricPattern33(client, name) { +function createMetricPattern34(client, name) { return { name, by: { @@ -1664,17 +1704,17 @@ function createMetricPattern33(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2shaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern34 + * @typedef {{ name: string, by: { p2shaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern35 */ /** - * Create a MetricPattern34 accessor + * Create a MetricPattern35 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern34} + * @returns {MetricPattern35} */ -function createMetricPattern34(client, name) { +function createMetricPattern35(client, name) { return { name, by: { @@ -1693,17 +1733,17 @@ function createMetricPattern34(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2traddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern35 + * @typedef {{ name: string, by: { p2traddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern36 */ /** - * Create a MetricPattern35 accessor + * Create a MetricPattern36 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern35} + * @returns {MetricPattern36} */ -function createMetricPattern35(client, name) { +function createMetricPattern36(client, name) { return { name, by: { @@ -1722,17 +1762,17 @@ function createMetricPattern35(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2wpkhaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern36 + * @typedef {{ name: string, by: { p2wpkhaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern37 */ /** - * Create a MetricPattern36 accessor + * Create a MetricPattern37 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern36} + * @returns {MetricPattern37} */ -function createMetricPattern36(client, name) { +function createMetricPattern37(client, name) { return { name, by: { @@ -1751,17 +1791,17 @@ function createMetricPattern36(client, name) { /** * @template T - * @typedef {{ name: string, by: { p2wshaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern37 + * @typedef {{ name: string, by: { p2wshaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern38 */ /** - * Create a MetricPattern37 accessor + * Create a MetricPattern38 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern37} + * @returns {MetricPattern38} */ -function createMetricPattern37(client, name) { +function createMetricPattern38(client, name) { return { name, by: { @@ -1780,17 +1820,17 @@ function createMetricPattern37(client, name) { /** * @template T - * @typedef {{ name: string, by: { txindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern38 + * @typedef {{ name: string, by: { txindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern39 */ /** - * Create a MetricPattern38 accessor + * Create a MetricPattern39 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern38} + * @returns {MetricPattern39} */ -function createMetricPattern38(client, name) { +function createMetricPattern39(client, name) { return { name, by: { @@ -1809,17 +1849,17 @@ function createMetricPattern38(client, name) { /** * @template T - * @typedef {{ name: string, by: { unknownoutputindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern39 + * @typedef {{ name: string, by: { unknownoutputindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern40 */ /** - * Create a MetricPattern39 accessor + * Create a MetricPattern40 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern39} + * @returns {MetricPattern40} */ -function createMetricPattern39(client, name) { +function createMetricPattern40(client, name) { return { name, by: { @@ -1838,17 +1878,17 @@ function createMetricPattern39(client, name) { /** * @template T - * @typedef {{ name: string, by: { loadedaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern40 + * @typedef {{ name: string, by: { loadedaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern41 */ /** - * Create a MetricPattern40 accessor + * Create a MetricPattern41 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern40} + * @returns {MetricPattern41} */ -function createMetricPattern40(client, name) { +function createMetricPattern41(client, name) { return { name, by: { @@ -1867,17 +1907,17 @@ function createMetricPattern40(client, name) { /** * @template T - * @typedef {{ name: string, by: { emptyaddressindex: Endpoint }, indexes: () => Index[], get: (index: Index) => Endpoint|undefined }} MetricPattern41 + * @typedef {{ name: string, by: { emptyaddressindex: MetricEndpoint }, indexes: () => Index[], get: (index: Index) => MetricEndpoint|undefined }} MetricPattern42 */ /** - * Create a MetricPattern41 accessor + * Create a MetricPattern42 accessor * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @returns {MetricPattern41} + * @returns {MetricPattern42} */ -function createMetricPattern41(client, name) { +function createMetricPattern42(client, name) { return { name, by: { @@ -1898,38 +1938,40 @@ function createMetricPattern41(client, name) { /** * @typedef {Object} RealizedPattern3 - * @property {MetricPattern21} adjustedSopr - * @property {MetricPattern21} adjustedSopr30dEma - * @property {MetricPattern21} adjustedSopr7dEma - * @property {TotalRealizedPnlPattern} adjustedValueCreated - * @property {TotalRealizedPnlPattern} adjustedValueDestroyed - * @property {MetricPattern4} mvrv + * @property {MetricPattern22} adjustedSopr + * @property {MetricPattern22} adjustedSopr30dEma + * @property {MetricPattern22} adjustedSopr7dEma + * @property {MetricPattern1} adjustedValueCreated + * @property {MetricPattern1} adjustedValueDestroyed + * @property {MetricPattern5} mvrv * @property {BlockCountPattern} negRealizedLoss * @property {BlockCountPattern} netRealizedPnl - * @property {MetricPattern4} netRealizedPnlCumulative30dDelta - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap - * @property {MetricPattern25} netRealizedPnlRelToRealizedCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDelta + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToMarketCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToRealizedCap + * @property {BlockCountPattern} netRealizedPnlRelToRealizedCap * @property {MetricPattern1} realizedCap - * @property {MetricPattern4} realizedCap30dDelta + * @property {MetricPattern5} realizedCap30dDelta * @property {MetricPattern1} realizedCapRelToOwnMarketCap * @property {BlockCountPattern} realizedLoss - * @property {MetricPattern25} realizedLossRelToRealizedCap + * @property {BlockCountPattern} realizedLossRelToRealizedCap * @property {MetricPattern1} realizedPrice * @property {ActivePriceRatioPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit - * @property {MetricPattern25} realizedProfitRelToRealizedCap - * @property {MetricPattern21} realizedProfitToLossRatio - * @property {MetricPattern1} realizedValue - * @property {MetricPattern21} sellSideRiskRatio - * @property {MetricPattern21} sellSideRiskRatio30dEma - * @property {MetricPattern21} sellSideRiskRatio7dEma - * @property {MetricPattern21} sopr - * @property {MetricPattern21} sopr30dEma - * @property {MetricPattern21} sopr7dEma - * @property {TotalRealizedPnlPattern} totalRealizedPnl - * @property {MetricPattern1} valueCreated - * @property {MetricPattern1} valueDestroyed + * @property {BlockCountPattern} realizedProfitRelToRealizedCap + * @property {MetricPattern22} realizedProfitToLossRatio + * @property {DifficultyAdjustmentPattern} realizedValue + * @property {MetricPattern22} sellSideRiskRatio + * @property {MetricPattern22} sellSideRiskRatio30dEma + * @property {MetricPattern22} sellSideRiskRatio7dEma + * @property {MetricPattern22} sopr + * @property {MetricPattern22} sopr30dEma + * @property {MetricPattern22} sopr7dEma + * @property {MetricPattern1} totalRealizedPnl + * @property {MetricPattern26} valueCreated + * @property {MetricPattern2} valueCreatedSum + * @property {MetricPattern26} valueDestroyed + * @property {MetricPattern2} valueDestroyedSum */ /** @@ -1940,73 +1982,77 @@ function createMetricPattern41(client, name) { */ function createRealizedPattern3(client, acc) { return { - adjustedSopr: createMetricPattern21(client, _m(acc, 'adjusted_sopr')), - adjustedSopr30dEma: createMetricPattern21(client, _m(acc, 'adjusted_sopr_30d_ema')), - adjustedSopr7dEma: createMetricPattern21(client, _m(acc, 'adjusted_sopr_7d_ema')), - adjustedValueCreated: createTotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_created')), - adjustedValueDestroyed: createTotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_destroyed')), - mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), + adjustedSopr: createMetricPattern22(client, _m(acc, 'adjusted_sopr')), + adjustedSopr30dEma: createMetricPattern22(client, _m(acc, 'adjusted_sopr_30d_ema')), + adjustedSopr7dEma: createMetricPattern22(client, _m(acc, 'adjusted_sopr_7d_ema')), + adjustedValueCreated: createMetricPattern1(client, _m(acc, 'adjusted_value_created')), + adjustedValueDestroyed: createMetricPattern1(client, _m(acc, 'adjusted_value_destroyed')), + mvrv: createMetricPattern5(client, _m(acc, 'mvrv')), negRealizedLoss: createBlockCountPattern(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createBlockCountPattern(client, _m(acc, 'net_realized_pnl')), - netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), - netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), - netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), - netRealizedPnlRelToRealizedCap: createMetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + netRealizedPnlCumulative30dDelta: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), + netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), + netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), + netRealizedPnlRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), realizedCap: createMetricPattern1(client, _m(acc, 'realized_cap')), - realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), + realizedCap30dDelta: createMetricPattern5(client, _m(acc, 'realized_cap_30d_delta')), realizedCapRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), - realizedLossRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')), + realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), realizedPriceExtra: createActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), - realizedProfitRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')), - realizedProfitToLossRatio: createMetricPattern21(client, _m(acc, 'realized_profit_to_loss_ratio')), - realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), - sellSideRiskRatio: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio')), - sellSideRiskRatio30dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), - sellSideRiskRatio7dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), - sopr: createMetricPattern21(client, _m(acc, 'sopr')), - sopr30dEma: createMetricPattern21(client, _m(acc, 'sopr_30d_ema')), - sopr7dEma: createMetricPattern21(client, _m(acc, 'sopr_7d_ema')), - totalRealizedPnl: createTotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')), - valueCreated: createMetricPattern1(client, _m(acc, 'value_created')), - valueDestroyed: createMetricPattern1(client, _m(acc, 'value_destroyed')), + realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), + realizedProfitToLossRatio: createMetricPattern22(client, _m(acc, 'realized_profit_to_loss_ratio')), + realizedValue: createDifficultyAdjustmentPattern(client, _m(acc, 'realized_value')), + sellSideRiskRatio: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio')), + sellSideRiskRatio30dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), + sellSideRiskRatio7dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sopr: createMetricPattern22(client, _m(acc, 'sopr')), + sopr30dEma: createMetricPattern22(client, _m(acc, 'sopr_30d_ema')), + sopr7dEma: createMetricPattern22(client, _m(acc, 'sopr_7d_ema')), + totalRealizedPnl: createMetricPattern1(client, _m(acc, 'total_realized_pnl')), + valueCreated: createMetricPattern26(client, _m(acc, 'value_created')), + valueCreatedSum: createMetricPattern2(client, _m(acc, 'value_created_sum')), + valueDestroyed: createMetricPattern26(client, _m(acc, 'value_destroyed')), + valueDestroyedSum: createMetricPattern2(client, _m(acc, 'value_destroyed_sum')), }; } /** * @typedef {Object} RealizedPattern4 - * @property {MetricPattern21} adjustedSopr - * @property {MetricPattern21} adjustedSopr30dEma - * @property {MetricPattern21} adjustedSopr7dEma - * @property {TotalRealizedPnlPattern} adjustedValueCreated - * @property {TotalRealizedPnlPattern} adjustedValueDestroyed - * @property {MetricPattern4} mvrv + * @property {MetricPattern22} adjustedSopr + * @property {MetricPattern22} adjustedSopr30dEma + * @property {MetricPattern22} adjustedSopr7dEma + * @property {MetricPattern1} adjustedValueCreated + * @property {MetricPattern1} adjustedValueDestroyed + * @property {MetricPattern5} mvrv * @property {BlockCountPattern} negRealizedLoss * @property {BlockCountPattern} netRealizedPnl - * @property {MetricPattern4} netRealizedPnlCumulative30dDelta - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap - * @property {MetricPattern25} netRealizedPnlRelToRealizedCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDelta + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToMarketCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToRealizedCap + * @property {BlockCountPattern} netRealizedPnlRelToRealizedCap * @property {MetricPattern1} realizedCap - * @property {MetricPattern4} realizedCap30dDelta + * @property {MetricPattern5} realizedCap30dDelta * @property {BlockCountPattern} realizedLoss - * @property {MetricPattern25} realizedLossRelToRealizedCap + * @property {BlockCountPattern} realizedLossRelToRealizedCap * @property {MetricPattern1} realizedPrice * @property {RealizedPriceExtraPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit - * @property {MetricPattern25} realizedProfitRelToRealizedCap - * @property {MetricPattern1} realizedValue - * @property {MetricPattern21} sellSideRiskRatio - * @property {MetricPattern21} sellSideRiskRatio30dEma - * @property {MetricPattern21} sellSideRiskRatio7dEma - * @property {MetricPattern21} sopr - * @property {MetricPattern21} sopr30dEma - * @property {MetricPattern21} sopr7dEma - * @property {TotalRealizedPnlPattern} totalRealizedPnl - * @property {MetricPattern1} valueCreated - * @property {MetricPattern1} valueDestroyed + * @property {BlockCountPattern} realizedProfitRelToRealizedCap + * @property {DifficultyAdjustmentPattern} realizedValue + * @property {MetricPattern22} sellSideRiskRatio + * @property {MetricPattern22} sellSideRiskRatio30dEma + * @property {MetricPattern22} sellSideRiskRatio7dEma + * @property {MetricPattern22} sopr + * @property {MetricPattern22} sopr30dEma + * @property {MetricPattern22} sopr7dEma + * @property {MetricPattern1} totalRealizedPnl + * @property {MetricPattern26} valueCreated + * @property {MetricPattern2} valueCreatedSum + * @property {MetricPattern26} valueDestroyed + * @property {MetricPattern2} valueDestroyedSum */ /** @@ -2017,139 +2063,72 @@ function createRealizedPattern3(client, acc) { */ function createRealizedPattern4(client, acc) { return { - adjustedSopr: createMetricPattern21(client, _m(acc, 'adjusted_sopr')), - adjustedSopr30dEma: createMetricPattern21(client, _m(acc, 'adjusted_sopr_30d_ema')), - adjustedSopr7dEma: createMetricPattern21(client, _m(acc, 'adjusted_sopr_7d_ema')), - adjustedValueCreated: createTotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_created')), - adjustedValueDestroyed: createTotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_destroyed')), - mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), + adjustedSopr: createMetricPattern22(client, _m(acc, 'adjusted_sopr')), + adjustedSopr30dEma: createMetricPattern22(client, _m(acc, 'adjusted_sopr_30d_ema')), + adjustedSopr7dEma: createMetricPattern22(client, _m(acc, 'adjusted_sopr_7d_ema')), + adjustedValueCreated: createMetricPattern1(client, _m(acc, 'adjusted_value_created')), + adjustedValueDestroyed: createMetricPattern1(client, _m(acc, 'adjusted_value_destroyed')), + mvrv: createMetricPattern5(client, _m(acc, 'mvrv')), negRealizedLoss: createBlockCountPattern(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createBlockCountPattern(client, _m(acc, 'net_realized_pnl')), - netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), - netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), - netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), - netRealizedPnlRelToRealizedCap: createMetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + netRealizedPnlCumulative30dDelta: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), + netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), + netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), + netRealizedPnlRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), realizedCap: createMetricPattern1(client, _m(acc, 'realized_cap')), - realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), + realizedCap30dDelta: createMetricPattern5(client, _m(acc, 'realized_cap_30d_delta')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), - realizedLossRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')), + realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), realizedPriceExtra: createRealizedPriceExtraPattern(client, _m(acc, 'realized_price')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), - realizedProfitRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')), - realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), - sellSideRiskRatio: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio')), - sellSideRiskRatio30dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), - sellSideRiskRatio7dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), - sopr: createMetricPattern21(client, _m(acc, 'sopr')), - sopr30dEma: createMetricPattern21(client, _m(acc, 'sopr_30d_ema')), - sopr7dEma: createMetricPattern21(client, _m(acc, 'sopr_7d_ema')), - totalRealizedPnl: createTotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')), - valueCreated: createMetricPattern1(client, _m(acc, 'value_created')), - valueDestroyed: createMetricPattern1(client, _m(acc, 'value_destroyed')), - }; -} - -/** - * @typedef {Object} Ratio1ySdPattern - * @property {MetricPattern4} _0sdUsd - * @property {MetricPattern4} m05sd - * @property {MetricPattern4} m05sdUsd - * @property {MetricPattern4} m15sd - * @property {MetricPattern4} m15sdUsd - * @property {MetricPattern4} m1sd - * @property {MetricPattern4} m1sdUsd - * @property {MetricPattern4} m25sd - * @property {MetricPattern4} m25sdUsd - * @property {MetricPattern4} m2sd - * @property {MetricPattern4} m2sdUsd - * @property {MetricPattern4} m3sd - * @property {MetricPattern4} m3sdUsd - * @property {MetricPattern4} p05sd - * @property {MetricPattern4} p05sdUsd - * @property {MetricPattern4} p15sd - * @property {MetricPattern4} p15sdUsd - * @property {MetricPattern4} p1sd - * @property {MetricPattern4} p1sdUsd - * @property {MetricPattern4} p25sd - * @property {MetricPattern4} p25sdUsd - * @property {MetricPattern4} p2sd - * @property {MetricPattern4} p2sdUsd - * @property {MetricPattern4} p3sd - * @property {MetricPattern4} p3sdUsd - * @property {MetricPattern4} sd - * @property {MetricPattern4} sma - * @property {MetricPattern4} zscore - */ - -/** - * Create a Ratio1ySdPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {Ratio1ySdPattern} - */ -function createRatio1ySdPattern(client, acc) { - return { - _0sdUsd: createMetricPattern4(client, _m(acc, '0sd_usd')), - m05sd: createMetricPattern4(client, _m(acc, 'm0_5sd')), - m05sdUsd: createMetricPattern4(client, _m(acc, 'm0_5sd_usd')), - m15sd: createMetricPattern4(client, _m(acc, 'm1_5sd')), - m15sdUsd: createMetricPattern4(client, _m(acc, 'm1_5sd_usd')), - m1sd: createMetricPattern4(client, _m(acc, 'm1sd')), - m1sdUsd: createMetricPattern4(client, _m(acc, 'm1sd_usd')), - m25sd: createMetricPattern4(client, _m(acc, 'm2_5sd')), - m25sdUsd: createMetricPattern4(client, _m(acc, 'm2_5sd_usd')), - m2sd: createMetricPattern4(client, _m(acc, 'm2sd')), - m2sdUsd: createMetricPattern4(client, _m(acc, 'm2sd_usd')), - m3sd: createMetricPattern4(client, _m(acc, 'm3sd')), - m3sdUsd: createMetricPattern4(client, _m(acc, 'm3sd_usd')), - p05sd: createMetricPattern4(client, _m(acc, 'p0_5sd')), - p05sdUsd: createMetricPattern4(client, _m(acc, 'p0_5sd_usd')), - p15sd: createMetricPattern4(client, _m(acc, 'p1_5sd')), - p15sdUsd: createMetricPattern4(client, _m(acc, 'p1_5sd_usd')), - p1sd: createMetricPattern4(client, _m(acc, 'p1sd')), - p1sdUsd: createMetricPattern4(client, _m(acc, 'p1sd_usd')), - p25sd: createMetricPattern4(client, _m(acc, 'p2_5sd')), - p25sdUsd: createMetricPattern4(client, _m(acc, 'p2_5sd_usd')), - p2sd: createMetricPattern4(client, _m(acc, 'p2sd')), - p2sdUsd: createMetricPattern4(client, _m(acc, 'p2sd_usd')), - p3sd: createMetricPattern4(client, _m(acc, 'p3sd')), - p3sdUsd: createMetricPattern4(client, _m(acc, 'p3sd_usd')), - sd: createMetricPattern4(client, _m(acc, 'sd')), - sma: createMetricPattern4(client, _m(acc, 'sma')), - zscore: createMetricPattern4(client, _m(acc, 'zscore')), + realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), + realizedValue: createDifficultyAdjustmentPattern(client, _m(acc, 'realized_value')), + sellSideRiskRatio: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio')), + sellSideRiskRatio30dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), + sellSideRiskRatio7dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sopr: createMetricPattern22(client, _m(acc, 'sopr')), + sopr30dEma: createMetricPattern22(client, _m(acc, 'sopr_30d_ema')), + sopr7dEma: createMetricPattern22(client, _m(acc, 'sopr_7d_ema')), + totalRealizedPnl: createMetricPattern1(client, _m(acc, 'total_realized_pnl')), + valueCreated: createMetricPattern26(client, _m(acc, 'value_created')), + valueCreatedSum: createMetricPattern2(client, _m(acc, 'value_created_sum')), + valueDestroyed: createMetricPattern26(client, _m(acc, 'value_destroyed')), + valueDestroyedSum: createMetricPattern2(client, _m(acc, 'value_destroyed_sum')), }; } /** * @typedef {Object} RealizedPattern2 - * @property {MetricPattern4} mvrv + * @property {MetricPattern5} mvrv * @property {BlockCountPattern} negRealizedLoss * @property {BlockCountPattern} netRealizedPnl - * @property {MetricPattern4} netRealizedPnlCumulative30dDelta - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap - * @property {MetricPattern25} netRealizedPnlRelToRealizedCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDelta + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToMarketCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToRealizedCap + * @property {BlockCountPattern} netRealizedPnlRelToRealizedCap * @property {MetricPattern1} realizedCap - * @property {MetricPattern4} realizedCap30dDelta + * @property {MetricPattern5} realizedCap30dDelta * @property {MetricPattern1} realizedCapRelToOwnMarketCap * @property {BlockCountPattern} realizedLoss - * @property {MetricPattern25} realizedLossRelToRealizedCap + * @property {BlockCountPattern} realizedLossRelToRealizedCap * @property {MetricPattern1} realizedPrice * @property {ActivePriceRatioPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit - * @property {MetricPattern25} realizedProfitRelToRealizedCap - * @property {MetricPattern21} realizedProfitToLossRatio - * @property {MetricPattern1} realizedValue - * @property {MetricPattern21} sellSideRiskRatio - * @property {MetricPattern21} sellSideRiskRatio30dEma - * @property {MetricPattern21} sellSideRiskRatio7dEma - * @property {MetricPattern21} sopr - * @property {MetricPattern21} sopr30dEma - * @property {MetricPattern21} sopr7dEma - * @property {TotalRealizedPnlPattern} totalRealizedPnl - * @property {MetricPattern1} valueCreated - * @property {MetricPattern1} valueDestroyed + * @property {BlockCountPattern} realizedProfitRelToRealizedCap + * @property {MetricPattern22} realizedProfitToLossRatio + * @property {DifficultyAdjustmentPattern} realizedValue + * @property {MetricPattern22} sellSideRiskRatio + * @property {MetricPattern22} sellSideRiskRatio30dEma + * @property {MetricPattern22} sellSideRiskRatio7dEma + * @property {MetricPattern22} sopr + * @property {MetricPattern22} sopr30dEma + * @property {MetricPattern22} sopr7dEma + * @property {MetricPattern1} totalRealizedPnl + * @property {MetricPattern26} valueCreated + * @property {MetricPattern2} valueCreatedSum + * @property {MetricPattern26} valueDestroyed + * @property {MetricPattern2} valueDestroyedSum */ /** @@ -2160,63 +2139,138 @@ function createRatio1ySdPattern(client, acc) { */ function createRealizedPattern2(client, acc) { return { - mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), + mvrv: createMetricPattern5(client, _m(acc, 'mvrv')), negRealizedLoss: createBlockCountPattern(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createBlockCountPattern(client, _m(acc, 'net_realized_pnl')), - netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), - netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), - netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), - netRealizedPnlRelToRealizedCap: createMetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + netRealizedPnlCumulative30dDelta: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), + netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), + netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), + netRealizedPnlRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), realizedCap: createMetricPattern1(client, _m(acc, 'realized_cap')), - realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), + realizedCap30dDelta: createMetricPattern5(client, _m(acc, 'realized_cap_30d_delta')), realizedCapRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), - realizedLossRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')), + realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), realizedPriceExtra: createActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), - realizedProfitRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')), - realizedProfitToLossRatio: createMetricPattern21(client, _m(acc, 'realized_profit_to_loss_ratio')), - realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), - sellSideRiskRatio: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio')), - sellSideRiskRatio30dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), - sellSideRiskRatio7dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), - sopr: createMetricPattern21(client, _m(acc, 'sopr')), - sopr30dEma: createMetricPattern21(client, _m(acc, 'sopr_30d_ema')), - sopr7dEma: createMetricPattern21(client, _m(acc, 'sopr_7d_ema')), - totalRealizedPnl: createTotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')), - valueCreated: createMetricPattern1(client, _m(acc, 'value_created')), - valueDestroyed: createMetricPattern1(client, _m(acc, 'value_destroyed')), + realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), + realizedProfitToLossRatio: createMetricPattern22(client, _m(acc, 'realized_profit_to_loss_ratio')), + realizedValue: createDifficultyAdjustmentPattern(client, _m(acc, 'realized_value')), + sellSideRiskRatio: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio')), + sellSideRiskRatio30dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), + sellSideRiskRatio7dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sopr: createMetricPattern22(client, _m(acc, 'sopr')), + sopr30dEma: createMetricPattern22(client, _m(acc, 'sopr_30d_ema')), + sopr7dEma: createMetricPattern22(client, _m(acc, 'sopr_7d_ema')), + totalRealizedPnl: createMetricPattern1(client, _m(acc, 'total_realized_pnl')), + valueCreated: createMetricPattern26(client, _m(acc, 'value_created')), + valueCreatedSum: createMetricPattern2(client, _m(acc, 'value_created_sum')), + valueDestroyed: createMetricPattern26(client, _m(acc, 'value_destroyed')), + valueDestroyedSum: createMetricPattern2(client, _m(acc, 'value_destroyed_sum')), + }; +} + +/** + * @typedef {Object} Ratio1ySdPattern + * @property {MetricPattern5} _0sdUsd + * @property {MetricPattern5} m05sd + * @property {MetricPattern5} m05sdUsd + * @property {MetricPattern5} m15sd + * @property {MetricPattern5} m15sdUsd + * @property {MetricPattern5} m1sd + * @property {MetricPattern5} m1sdUsd + * @property {MetricPattern5} m25sd + * @property {MetricPattern5} m25sdUsd + * @property {MetricPattern5} m2sd + * @property {MetricPattern5} m2sdUsd + * @property {MetricPattern5} m3sd + * @property {MetricPattern5} m3sdUsd + * @property {MetricPattern5} p05sd + * @property {MetricPattern5} p05sdUsd + * @property {MetricPattern5} p15sd + * @property {MetricPattern5} p15sdUsd + * @property {MetricPattern5} p1sd + * @property {MetricPattern5} p1sdUsd + * @property {MetricPattern5} p25sd + * @property {MetricPattern5} p25sdUsd + * @property {MetricPattern5} p2sd + * @property {MetricPattern5} p2sdUsd + * @property {MetricPattern5} p3sd + * @property {MetricPattern5} p3sdUsd + * @property {MetricPattern5} sd + * @property {MetricPattern5} sma + * @property {MetricPattern5} zscore + */ + +/** + * Create a Ratio1ySdPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {Ratio1ySdPattern} + */ +function createRatio1ySdPattern(client, acc) { + return { + _0sdUsd: createMetricPattern5(client, _m(acc, '0sd_usd')), + m05sd: createMetricPattern5(client, _m(acc, 'm0_5sd')), + m05sdUsd: createMetricPattern5(client, _m(acc, 'm0_5sd_usd')), + m15sd: createMetricPattern5(client, _m(acc, 'm1_5sd')), + m15sdUsd: createMetricPattern5(client, _m(acc, 'm1_5sd_usd')), + m1sd: createMetricPattern5(client, _m(acc, 'm1sd')), + m1sdUsd: createMetricPattern5(client, _m(acc, 'm1sd_usd')), + m25sd: createMetricPattern5(client, _m(acc, 'm2_5sd')), + m25sdUsd: createMetricPattern5(client, _m(acc, 'm2_5sd_usd')), + m2sd: createMetricPattern5(client, _m(acc, 'm2sd')), + m2sdUsd: createMetricPattern5(client, _m(acc, 'm2sd_usd')), + m3sd: createMetricPattern5(client, _m(acc, 'm3sd')), + m3sdUsd: createMetricPattern5(client, _m(acc, 'm3sd_usd')), + p05sd: createMetricPattern5(client, _m(acc, 'p0_5sd')), + p05sdUsd: createMetricPattern5(client, _m(acc, 'p0_5sd_usd')), + p15sd: createMetricPattern5(client, _m(acc, 'p1_5sd')), + p15sdUsd: createMetricPattern5(client, _m(acc, 'p1_5sd_usd')), + p1sd: createMetricPattern5(client, _m(acc, 'p1sd')), + p1sdUsd: createMetricPattern5(client, _m(acc, 'p1sd_usd')), + p25sd: createMetricPattern5(client, _m(acc, 'p2_5sd')), + p25sdUsd: createMetricPattern5(client, _m(acc, 'p2_5sd_usd')), + p2sd: createMetricPattern5(client, _m(acc, 'p2sd')), + p2sdUsd: createMetricPattern5(client, _m(acc, 'p2sd_usd')), + p3sd: createMetricPattern5(client, _m(acc, 'p3sd')), + p3sdUsd: createMetricPattern5(client, _m(acc, 'p3sd_usd')), + sd: createMetricPattern5(client, _m(acc, 'sd')), + sma: createMetricPattern5(client, _m(acc, 'sma')), + zscore: createMetricPattern5(client, _m(acc, 'zscore')), }; } /** * @typedef {Object} RealizedPattern - * @property {MetricPattern4} mvrv + * @property {MetricPattern5} mvrv * @property {BlockCountPattern} negRealizedLoss * @property {BlockCountPattern} netRealizedPnl - * @property {MetricPattern4} netRealizedPnlCumulative30dDelta - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToMarketCap - * @property {MetricPattern4} netRealizedPnlCumulative30dDeltaRelToRealizedCap - * @property {MetricPattern25} netRealizedPnlRelToRealizedCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDelta + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToMarketCap + * @property {MetricPattern5} netRealizedPnlCumulative30dDeltaRelToRealizedCap + * @property {BlockCountPattern} netRealizedPnlRelToRealizedCap * @property {MetricPattern1} realizedCap - * @property {MetricPattern4} realizedCap30dDelta + * @property {MetricPattern5} realizedCap30dDelta * @property {BlockCountPattern} realizedLoss - * @property {MetricPattern25} realizedLossRelToRealizedCap + * @property {BlockCountPattern} realizedLossRelToRealizedCap * @property {MetricPattern1} realizedPrice * @property {RealizedPriceExtraPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit - * @property {MetricPattern25} realizedProfitRelToRealizedCap - * @property {MetricPattern1} realizedValue - * @property {MetricPattern21} sellSideRiskRatio - * @property {MetricPattern21} sellSideRiskRatio30dEma - * @property {MetricPattern21} sellSideRiskRatio7dEma - * @property {MetricPattern21} sopr - * @property {MetricPattern21} sopr30dEma - * @property {MetricPattern21} sopr7dEma - * @property {TotalRealizedPnlPattern} totalRealizedPnl - * @property {MetricPattern1} valueCreated - * @property {MetricPattern1} valueDestroyed + * @property {BlockCountPattern} realizedProfitRelToRealizedCap + * @property {DifficultyAdjustmentPattern} realizedValue + * @property {MetricPattern22} sellSideRiskRatio + * @property {MetricPattern22} sellSideRiskRatio30dEma + * @property {MetricPattern22} sellSideRiskRatio7dEma + * @property {MetricPattern22} sopr + * @property {MetricPattern22} sopr30dEma + * @property {MetricPattern22} sopr7dEma + * @property {MetricPattern1} totalRealizedPnl + * @property {MetricPattern26} valueCreated + * @property {MetricPattern2} valueCreatedSum + * @property {MetricPattern26} valueDestroyed + * @property {MetricPattern2} valueDestroyedSum */ /** @@ -2227,55 +2281,57 @@ function createRealizedPattern2(client, acc) { */ function createRealizedPattern(client, acc) { return { - mvrv: createMetricPattern4(client, _m(acc, 'mvrv')), + mvrv: createMetricPattern5(client, _m(acc, 'mvrv')), negRealizedLoss: createBlockCountPattern(client, _m(acc, 'neg_realized_loss')), netRealizedPnl: createBlockCountPattern(client, _m(acc, 'net_realized_pnl')), - netRealizedPnlCumulative30dDelta: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), - netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), - netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), - netRealizedPnlRelToRealizedCap: createMetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), + netRealizedPnlCumulative30dDelta: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')), + netRealizedPnlCumulative30dDeltaRelToMarketCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')), + netRealizedPnlCumulative30dDeltaRelToRealizedCap: createMetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')), + netRealizedPnlRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')), realizedCap: createMetricPattern1(client, _m(acc, 'realized_cap')), - realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), + realizedCap30dDelta: createMetricPattern5(client, _m(acc, 'realized_cap_30d_delta')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), - realizedLossRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')), + realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), realizedPriceExtra: createRealizedPriceExtraPattern(client, _m(acc, 'realized_price')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), - realizedProfitRelToRealizedCap: createMetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')), - realizedValue: createMetricPattern1(client, _m(acc, 'realized_value')), - sellSideRiskRatio: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio')), - sellSideRiskRatio30dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), - sellSideRiskRatio7dEma: createMetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), - sopr: createMetricPattern21(client, _m(acc, 'sopr')), - sopr30dEma: createMetricPattern21(client, _m(acc, 'sopr_30d_ema')), - sopr7dEma: createMetricPattern21(client, _m(acc, 'sopr_7d_ema')), - totalRealizedPnl: createTotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')), - valueCreated: createMetricPattern1(client, _m(acc, 'value_created')), - valueDestroyed: createMetricPattern1(client, _m(acc, 'value_destroyed')), + realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), + realizedValue: createDifficultyAdjustmentPattern(client, _m(acc, 'realized_value')), + sellSideRiskRatio: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio')), + sellSideRiskRatio30dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')), + sellSideRiskRatio7dEma: createMetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')), + sopr: createMetricPattern22(client, _m(acc, 'sopr')), + sopr30dEma: createMetricPattern22(client, _m(acc, 'sopr_30d_ema')), + sopr7dEma: createMetricPattern22(client, _m(acc, 'sopr_7d_ema')), + totalRealizedPnl: createMetricPattern1(client, _m(acc, 'total_realized_pnl')), + valueCreated: createMetricPattern26(client, _m(acc, 'value_created')), + valueCreatedSum: createMetricPattern2(client, _m(acc, 'value_created_sum')), + valueDestroyed: createMetricPattern26(client, _m(acc, 'value_destroyed')), + valueDestroyedSum: createMetricPattern2(client, _m(acc, 'value_destroyed_sum')), }; } /** * @typedef {Object} Price111dSmaPattern - * @property {MetricPattern4} price - * @property {MetricPattern4} ratio - * @property {MetricPattern4} ratio1mSma - * @property {MetricPattern4} ratio1wSma + * @property {MetricPattern5} price + * @property {MetricPattern5} ratio + * @property {MetricPattern5} ratio1mSma + * @property {MetricPattern5} ratio1wSma * @property {Ratio1ySdPattern} ratio1ySd * @property {Ratio1ySdPattern} ratio2ySd * @property {Ratio1ySdPattern} ratio4ySd - * @property {MetricPattern4} ratioPct1 - * @property {MetricPattern4} ratioPct1Usd - * @property {MetricPattern4} ratioPct2 - * @property {MetricPattern4} ratioPct2Usd - * @property {MetricPattern4} ratioPct5 - * @property {MetricPattern4} ratioPct5Usd - * @property {MetricPattern4} ratioPct95 - * @property {MetricPattern4} ratioPct95Usd - * @property {MetricPattern4} ratioPct98 - * @property {MetricPattern4} ratioPct98Usd - * @property {MetricPattern4} ratioPct99 - * @property {MetricPattern4} ratioPct99Usd + * @property {MetricPattern5} ratioPct1 + * @property {MetricPattern5} ratioPct1Usd + * @property {MetricPattern5} ratioPct2 + * @property {MetricPattern5} ratioPct2Usd + * @property {MetricPattern5} ratioPct5 + * @property {MetricPattern5} ratioPct5Usd + * @property {MetricPattern5} ratioPct95 + * @property {MetricPattern5} ratioPct95Usd + * @property {MetricPattern5} ratioPct98 + * @property {MetricPattern5} ratioPct98Usd + * @property {MetricPattern5} ratioPct99 + * @property {MetricPattern5} ratioPct99Usd * @property {Ratio1ySdPattern} ratioSd */ @@ -2287,49 +2343,102 @@ function createRealizedPattern(client, acc) { */ function createPrice111dSmaPattern(client, acc) { return { - price: createMetricPattern4(client, acc), - ratio: createMetricPattern4(client, _m(acc, 'ratio')), - ratio1mSma: createMetricPattern4(client, _m(acc, 'ratio_1m_sma')), - ratio1wSma: createMetricPattern4(client, _m(acc, 'ratio_1w_sma')), + price: createMetricPattern5(client, acc), + ratio: createMetricPattern5(client, _m(acc, 'ratio')), + ratio1mSma: createMetricPattern5(client, _m(acc, 'ratio_1m_sma')), + ratio1wSma: createMetricPattern5(client, _m(acc, 'ratio_1w_sma')), ratio1ySd: createRatio1ySdPattern(client, _m(acc, 'ratio_1y')), ratio2ySd: createRatio1ySdPattern(client, _m(acc, 'ratio_2y')), ratio4ySd: createRatio1ySdPattern(client, _m(acc, 'ratio_4y')), - ratioPct1: createMetricPattern4(client, _m(acc, 'ratio_pct1')), - ratioPct1Usd: createMetricPattern4(client, _m(acc, 'ratio_pct1_usd')), - ratioPct2: createMetricPattern4(client, _m(acc, 'ratio_pct2')), - ratioPct2Usd: createMetricPattern4(client, _m(acc, 'ratio_pct2_usd')), - ratioPct5: createMetricPattern4(client, _m(acc, 'ratio_pct5')), - ratioPct5Usd: createMetricPattern4(client, _m(acc, 'ratio_pct5_usd')), - ratioPct95: createMetricPattern4(client, _m(acc, 'ratio_pct95')), - ratioPct95Usd: createMetricPattern4(client, _m(acc, 'ratio_pct95_usd')), - ratioPct98: createMetricPattern4(client, _m(acc, 'ratio_pct98')), - ratioPct98Usd: createMetricPattern4(client, _m(acc, 'ratio_pct98_usd')), - ratioPct99: createMetricPattern4(client, _m(acc, 'ratio_pct99')), - ratioPct99Usd: createMetricPattern4(client, _m(acc, 'ratio_pct99_usd')), + ratioPct1: createMetricPattern5(client, _m(acc, 'ratio_pct1')), + ratioPct1Usd: createMetricPattern5(client, _m(acc, 'ratio_pct1_usd')), + ratioPct2: createMetricPattern5(client, _m(acc, 'ratio_pct2')), + ratioPct2Usd: createMetricPattern5(client, _m(acc, 'ratio_pct2_usd')), + ratioPct5: createMetricPattern5(client, _m(acc, 'ratio_pct5')), + ratioPct5Usd: createMetricPattern5(client, _m(acc, 'ratio_pct5_usd')), + ratioPct95: createMetricPattern5(client, _m(acc, 'ratio_pct95')), + ratioPct95Usd: createMetricPattern5(client, _m(acc, 'ratio_pct95_usd')), + ratioPct98: createMetricPattern5(client, _m(acc, 'ratio_pct98')), + ratioPct98Usd: createMetricPattern5(client, _m(acc, 'ratio_pct98_usd')), + ratioPct99: createMetricPattern5(client, _m(acc, 'ratio_pct99')), + ratioPct99Usd: createMetricPattern5(client, _m(acc, 'ratio_pct99_usd')), ratioSd: createRatio1ySdPattern(client, _m(acc, 'ratio')), }; } +/** + * @typedef {Object} PercentilesPattern2 + * @property {MetricPattern5} costBasisPct05 + * @property {MetricPattern5} costBasisPct10 + * @property {MetricPattern5} costBasisPct15 + * @property {MetricPattern5} costBasisPct20 + * @property {MetricPattern5} costBasisPct25 + * @property {MetricPattern5} costBasisPct30 + * @property {MetricPattern5} costBasisPct35 + * @property {MetricPattern5} costBasisPct40 + * @property {MetricPattern5} costBasisPct45 + * @property {MetricPattern5} costBasisPct50 + * @property {MetricPattern5} costBasisPct55 + * @property {MetricPattern5} costBasisPct60 + * @property {MetricPattern5} costBasisPct65 + * @property {MetricPattern5} costBasisPct70 + * @property {MetricPattern5} costBasisPct75 + * @property {MetricPattern5} costBasisPct80 + * @property {MetricPattern5} costBasisPct85 + * @property {MetricPattern5} costBasisPct90 + * @property {MetricPattern5} costBasisPct95 + */ + +/** + * Create a PercentilesPattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {PercentilesPattern2} + */ +function createPercentilesPattern2(client, acc) { + return { + costBasisPct05: createMetricPattern5(client, _m(acc, 'pct05')), + costBasisPct10: createMetricPattern5(client, _m(acc, 'pct10')), + costBasisPct15: createMetricPattern5(client, _m(acc, 'pct15')), + costBasisPct20: createMetricPattern5(client, _m(acc, 'pct20')), + costBasisPct25: createMetricPattern5(client, _m(acc, 'pct25')), + costBasisPct30: createMetricPattern5(client, _m(acc, 'pct30')), + costBasisPct35: createMetricPattern5(client, _m(acc, 'pct35')), + costBasisPct40: createMetricPattern5(client, _m(acc, 'pct40')), + costBasisPct45: createMetricPattern5(client, _m(acc, 'pct45')), + costBasisPct50: createMetricPattern5(client, _m(acc, 'pct50')), + costBasisPct55: createMetricPattern5(client, _m(acc, 'pct55')), + costBasisPct60: createMetricPattern5(client, _m(acc, 'pct60')), + costBasisPct65: createMetricPattern5(client, _m(acc, 'pct65')), + costBasisPct70: createMetricPattern5(client, _m(acc, 'pct70')), + costBasisPct75: createMetricPattern5(client, _m(acc, 'pct75')), + costBasisPct80: createMetricPattern5(client, _m(acc, 'pct80')), + costBasisPct85: createMetricPattern5(client, _m(acc, 'pct85')), + costBasisPct90: createMetricPattern5(client, _m(acc, 'pct90')), + costBasisPct95: createMetricPattern5(client, _m(acc, 'pct95')), + }; +} + /** * @typedef {Object} ActivePriceRatioPattern - * @property {MetricPattern4} ratio - * @property {MetricPattern4} ratio1mSma - * @property {MetricPattern4} ratio1wSma + * @property {MetricPattern5} ratio + * @property {MetricPattern5} ratio1mSma + * @property {MetricPattern5} ratio1wSma * @property {Ratio1ySdPattern} ratio1ySd * @property {Ratio1ySdPattern} ratio2ySd * @property {Ratio1ySdPattern} ratio4ySd - * @property {MetricPattern4} ratioPct1 - * @property {MetricPattern4} ratioPct1Usd - * @property {MetricPattern4} ratioPct2 - * @property {MetricPattern4} ratioPct2Usd - * @property {MetricPattern4} ratioPct5 - * @property {MetricPattern4} ratioPct5Usd - * @property {MetricPattern4} ratioPct95 - * @property {MetricPattern4} ratioPct95Usd - * @property {MetricPattern4} ratioPct98 - * @property {MetricPattern4} ratioPct98Usd - * @property {MetricPattern4} ratioPct99 - * @property {MetricPattern4} ratioPct99Usd + * @property {MetricPattern5} ratioPct1 + * @property {MetricPattern5} ratioPct1Usd + * @property {MetricPattern5} ratioPct2 + * @property {MetricPattern5} ratioPct2Usd + * @property {MetricPattern5} ratioPct5 + * @property {MetricPattern5} ratioPct5Usd + * @property {MetricPattern5} ratioPct95 + * @property {MetricPattern5} ratioPct95Usd + * @property {MetricPattern5} ratioPct98 + * @property {MetricPattern5} ratioPct98Usd + * @property {MetricPattern5} ratioPct99 + * @property {MetricPattern5} ratioPct99Usd * @property {Ratio1ySdPattern} ratioSd */ @@ -2341,101 +2450,48 @@ function createPrice111dSmaPattern(client, acc) { */ function createActivePriceRatioPattern(client, acc) { return { - ratio: createMetricPattern4(client, acc), - ratio1mSma: createMetricPattern4(client, _m(acc, '1m_sma')), - ratio1wSma: createMetricPattern4(client, _m(acc, '1w_sma')), + ratio: createMetricPattern5(client, acc), + ratio1mSma: createMetricPattern5(client, _m(acc, '1m_sma')), + ratio1wSma: createMetricPattern5(client, _m(acc, '1w_sma')), ratio1ySd: createRatio1ySdPattern(client, _m(acc, '1y')), ratio2ySd: createRatio1ySdPattern(client, _m(acc, '2y')), ratio4ySd: createRatio1ySdPattern(client, _m(acc, '4y')), - ratioPct1: createMetricPattern4(client, _m(acc, 'pct1')), - ratioPct1Usd: createMetricPattern4(client, _m(acc, 'pct1_usd')), - ratioPct2: createMetricPattern4(client, _m(acc, 'pct2')), - ratioPct2Usd: createMetricPattern4(client, _m(acc, 'pct2_usd')), - ratioPct5: createMetricPattern4(client, _m(acc, 'pct5')), - ratioPct5Usd: createMetricPattern4(client, _m(acc, 'pct5_usd')), - ratioPct95: createMetricPattern4(client, _m(acc, 'pct95')), - ratioPct95Usd: createMetricPattern4(client, _m(acc, 'pct95_usd')), - ratioPct98: createMetricPattern4(client, _m(acc, 'pct98')), - ratioPct98Usd: createMetricPattern4(client, _m(acc, 'pct98_usd')), - ratioPct99: createMetricPattern4(client, _m(acc, 'pct99')), - ratioPct99Usd: createMetricPattern4(client, _m(acc, 'pct99_usd')), + ratioPct1: createMetricPattern5(client, _m(acc, 'pct1')), + ratioPct1Usd: createMetricPattern5(client, _m(acc, 'pct1_usd')), + ratioPct2: createMetricPattern5(client, _m(acc, 'pct2')), + ratioPct2Usd: createMetricPattern5(client, _m(acc, 'pct2_usd')), + ratioPct5: createMetricPattern5(client, _m(acc, 'pct5')), + ratioPct5Usd: createMetricPattern5(client, _m(acc, 'pct5_usd')), + ratioPct95: createMetricPattern5(client, _m(acc, 'pct95')), + ratioPct95Usd: createMetricPattern5(client, _m(acc, 'pct95_usd')), + ratioPct98: createMetricPattern5(client, _m(acc, 'pct98')), + ratioPct98Usd: createMetricPattern5(client, _m(acc, 'pct98_usd')), + ratioPct99: createMetricPattern5(client, _m(acc, 'pct99')), + ratioPct99Usd: createMetricPattern5(client, _m(acc, 'pct99_usd')), ratioSd: createRatio1ySdPattern(client, acc), }; } -/** - * @typedef {Object} PercentilesPattern - * @property {MetricPattern4} costBasisPct05 - * @property {MetricPattern4} costBasisPct10 - * @property {MetricPattern4} costBasisPct15 - * @property {MetricPattern4} costBasisPct20 - * @property {MetricPattern4} costBasisPct25 - * @property {MetricPattern4} costBasisPct30 - * @property {MetricPattern4} costBasisPct35 - * @property {MetricPattern4} costBasisPct40 - * @property {MetricPattern4} costBasisPct45 - * @property {MetricPattern4} costBasisPct50 - * @property {MetricPattern4} costBasisPct55 - * @property {MetricPattern4} costBasisPct60 - * @property {MetricPattern4} costBasisPct65 - * @property {MetricPattern4} costBasisPct70 - * @property {MetricPattern4} costBasisPct75 - * @property {MetricPattern4} costBasisPct80 - * @property {MetricPattern4} costBasisPct85 - * @property {MetricPattern4} costBasisPct90 - * @property {MetricPattern4} costBasisPct95 - */ - -/** - * Create a PercentilesPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {PercentilesPattern} - */ -function createPercentilesPattern(client, acc) { - return { - costBasisPct05: createMetricPattern4(client, _m(acc, 'pct05')), - costBasisPct10: createMetricPattern4(client, _m(acc, 'pct10')), - costBasisPct15: createMetricPattern4(client, _m(acc, 'pct15')), - costBasisPct20: createMetricPattern4(client, _m(acc, 'pct20')), - costBasisPct25: createMetricPattern4(client, _m(acc, 'pct25')), - costBasisPct30: createMetricPattern4(client, _m(acc, 'pct30')), - costBasisPct35: createMetricPattern4(client, _m(acc, 'pct35')), - costBasisPct40: createMetricPattern4(client, _m(acc, 'pct40')), - costBasisPct45: createMetricPattern4(client, _m(acc, 'pct45')), - costBasisPct50: createMetricPattern4(client, _m(acc, 'pct50')), - costBasisPct55: createMetricPattern4(client, _m(acc, 'pct55')), - costBasisPct60: createMetricPattern4(client, _m(acc, 'pct60')), - costBasisPct65: createMetricPattern4(client, _m(acc, 'pct65')), - costBasisPct70: createMetricPattern4(client, _m(acc, 'pct70')), - costBasisPct75: createMetricPattern4(client, _m(acc, 'pct75')), - costBasisPct80: createMetricPattern4(client, _m(acc, 'pct80')), - costBasisPct85: createMetricPattern4(client, _m(acc, 'pct85')), - costBasisPct90: createMetricPattern4(client, _m(acc, 'pct90')), - costBasisPct95: createMetricPattern4(client, _m(acc, 'pct95')), - }; -} - /** * @typedef {Object} RelativePattern5 - * @property {MetricPattern5} negUnrealizedLossRelToMarketCap - * @property {MetricPattern5} negUnrealizedLossRelToOwnMarketCap - * @property {MetricPattern5} negUnrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} negUnrealizedLossRelToMarketCap + * @property {MetricPattern3} negUnrealizedLossRelToOwnMarketCap + * @property {MetricPattern3} negUnrealizedLossRelToOwnTotalUnrealizedPnl * @property {MetricPattern3} netUnrealizedPnlRelToMarketCap * @property {MetricPattern3} netUnrealizedPnlRelToOwnMarketCap * @property {MetricPattern3} netUnrealizedPnlRelToOwnTotalUnrealizedPnl - * @property {MetricPattern4} nupl - * @property {MetricPattern5} supplyInLossRelToCirculatingSupply - * @property {MetricPattern5} supplyInLossRelToOwnSupply - * @property {MetricPattern5} supplyInProfitRelToCirculatingSupply - * @property {MetricPattern5} supplyInProfitRelToOwnSupply - * @property {MetricPattern4} supplyRelToCirculatingSupply - * @property {MetricPattern5} unrealizedLossRelToMarketCap - * @property {MetricPattern5} unrealizedLossRelToOwnMarketCap - * @property {MetricPattern5} unrealizedLossRelToOwnTotalUnrealizedPnl - * @property {MetricPattern5} unrealizedProfitRelToMarketCap - * @property {MetricPattern5} unrealizedProfitRelToOwnMarketCap - * @property {MetricPattern5} unrealizedProfitRelToOwnTotalUnrealizedPnl + * @property {MetricPattern5} nupl + * @property {MetricPattern3} supplyInLossRelToCirculatingSupply + * @property {MetricPattern3} supplyInLossRelToOwnSupply + * @property {MetricPattern3} supplyInProfitRelToCirculatingSupply + * @property {MetricPattern3} supplyInProfitRelToOwnSupply + * @property {MetricPattern5} supplyRelToCirculatingSupply + * @property {MetricPattern3} unrealizedLossRelToMarketCap + * @property {MetricPattern3} unrealizedLossRelToOwnMarketCap + * @property {MetricPattern3} unrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} unrealizedProfitRelToMarketCap + * @property {MetricPattern3} unrealizedProfitRelToOwnMarketCap + * @property {MetricPattern3} unrealizedProfitRelToOwnTotalUnrealizedPnl */ /** @@ -2446,39 +2502,39 @@ function createPercentilesPattern(client, acc) { */ function createRelativePattern5(client, acc) { return { - negUnrealizedLossRelToMarketCap: createMetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')), - negUnrealizedLossRelToOwnMarketCap: createMetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')), - negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')), + negUnrealizedLossRelToMarketCap: createMetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')), + negUnrealizedLossRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')), + negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')), netUnrealizedPnlRelToMarketCap: createMetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')), netUnrealizedPnlRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')), netUnrealizedPnlRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')), - nupl: createMetricPattern4(client, _m(acc, 'nupl')), - supplyInLossRelToCirculatingSupply: createMetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')), - supplyInLossRelToOwnSupply: createMetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), - supplyInProfitRelToCirculatingSupply: createMetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), - supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')), - unrealizedLossRelToMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_market_cap')), - unrealizedLossRelToOwnMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), - unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), - unrealizedProfitRelToMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_market_cap')), - unrealizedProfitRelToOwnMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), - unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), + nupl: createMetricPattern5(client, _m(acc, 'nupl')), + supplyInLossRelToCirculatingSupply: createMetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')), + supplyInLossRelToOwnSupply: createMetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), + supplyInProfitRelToCirculatingSupply: createMetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), + supplyRelToCirculatingSupply: createMetricPattern5(client, _m(acc, 'supply_rel_to_circulating_supply')), + unrealizedLossRelToMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_market_cap')), + unrealizedLossRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), + unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), + unrealizedProfitRelToMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_market_cap')), + unrealizedProfitRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), + unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), }; } /** * @typedef {Object} AXbtPattern * @property {BlockCountPattern} _1dDominance - * @property {MetricPattern4} _1mBlocksMined - * @property {MetricPattern4} _1mDominance - * @property {MetricPattern4} _1wBlocksMined - * @property {MetricPattern4} _1wDominance - * @property {MetricPattern4} _1yBlocksMined - * @property {MetricPattern4} _1yDominance + * @property {MetricPattern5} _1mBlocksMined + * @property {MetricPattern5} _1mDominance + * @property {MetricPattern5} _1wBlocksMined + * @property {MetricPattern5} _1wDominance + * @property {MetricPattern5} _1yBlocksMined + * @property {MetricPattern5} _1yDominance * @property {BlockCountPattern} blocksMined * @property {UnclaimedRewardsPattern} coinbase - * @property {MetricPattern4} daysSinceBlock + * @property {MetricPattern5} daysSinceBlock * @property {BlockCountPattern} dominance * @property {SentPattern} fee * @property {SentPattern} subsidy @@ -2493,37 +2549,37 @@ function createRelativePattern5(client, acc) { function createAXbtPattern(client, acc) { return { _1dDominance: createBlockCountPattern(client, _m(acc, '1d_dominance')), - _1mBlocksMined: createMetricPattern4(client, _m(acc, '1m_blocks_mined')), - _1mDominance: createMetricPattern4(client, _m(acc, '1m_dominance')), - _1wBlocksMined: createMetricPattern4(client, _m(acc, '1w_blocks_mined')), - _1wDominance: createMetricPattern4(client, _m(acc, '1w_dominance')), - _1yBlocksMined: createMetricPattern4(client, _m(acc, '1y_blocks_mined')), - _1yDominance: createMetricPattern4(client, _m(acc, '1y_dominance')), + _1mBlocksMined: createMetricPattern5(client, _m(acc, '1m_blocks_mined')), + _1mDominance: createMetricPattern5(client, _m(acc, '1m_dominance')), + _1wBlocksMined: createMetricPattern5(client, _m(acc, '1w_blocks_mined')), + _1wDominance: createMetricPattern5(client, _m(acc, '1w_dominance')), + _1yBlocksMined: createMetricPattern5(client, _m(acc, '1y_blocks_mined')), + _1yDominance: createMetricPattern5(client, _m(acc, '1y_dominance')), blocksMined: createBlockCountPattern(client, _m(acc, 'blocks_mined')), coinbase: createUnclaimedRewardsPattern(client, _m(acc, 'coinbase')), - daysSinceBlock: createMetricPattern4(client, _m(acc, 'days_since_block')), + daysSinceBlock: createMetricPattern5(client, _m(acc, 'days_since_block')), dominance: createBlockCountPattern(client, _m(acc, 'dominance')), - fee: createSentPattern(client, _m(acc, 'fee')), - subsidy: createSentPattern(client, _m(acc, 'subsidy')), + fee: createSentPattern(client, acc), + subsidy: createSentPattern(client, acc), }; } /** * @template T * @typedef {Object} PriceAgoPattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _1d - * @property {MetricPattern4} _1m - * @property {MetricPattern4} _1w - * @property {MetricPattern4} _1y - * @property {MetricPattern4} _2y - * @property {MetricPattern4} _3m - * @property {MetricPattern4} _3y - * @property {MetricPattern4} _4y - * @property {MetricPattern4} _5y - * @property {MetricPattern4} _6m - * @property {MetricPattern4} _6y - * @property {MetricPattern4} _8y + * @property {MetricPattern5} _10y + * @property {MetricPattern5} _1d + * @property {MetricPattern5} _1m + * @property {MetricPattern5} _1w + * @property {MetricPattern5} _1y + * @property {MetricPattern5} _2y + * @property {MetricPattern5} _3m + * @property {MetricPattern5} _3y + * @property {MetricPattern5} _4y + * @property {MetricPattern5} _5y + * @property {MetricPattern5} _6m + * @property {MetricPattern5} _6y + * @property {MetricPattern5} _8y */ /** @@ -2535,19 +2591,19 @@ function createAXbtPattern(client, acc) { */ function createPriceAgoPattern(client, acc) { return { - _10y: createMetricPattern4(client, _m(acc, '10y_ago')), - _1d: createMetricPattern4(client, _m(acc, '1d_ago')), - _1m: createMetricPattern4(client, _m(acc, '1m_ago')), - _1w: createMetricPattern4(client, _m(acc, '1w_ago')), - _1y: createMetricPattern4(client, _m(acc, '1y_ago')), - _2y: createMetricPattern4(client, _m(acc, '2y_ago')), - _3m: createMetricPattern4(client, _m(acc, '3m_ago')), - _3y: createMetricPattern4(client, _m(acc, '3y_ago')), - _4y: createMetricPattern4(client, _m(acc, '4y_ago')), - _5y: createMetricPattern4(client, _m(acc, '5y_ago')), - _6m: createMetricPattern4(client, _m(acc, '6m_ago')), - _6y: createMetricPattern4(client, _m(acc, '6y_ago')), - _8y: createMetricPattern4(client, _m(acc, '8y_ago')), + _10y: createMetricPattern5(client, _m(acc, '10y_ago')), + _1d: createMetricPattern5(client, _m(acc, '1d_ago')), + _1m: createMetricPattern5(client, _m(acc, '1m_ago')), + _1w: createMetricPattern5(client, _m(acc, '1w_ago')), + _1y: createMetricPattern5(client, _m(acc, '1y_ago')), + _2y: createMetricPattern5(client, _m(acc, '2y_ago')), + _3m: createMetricPattern5(client, _m(acc, '3m_ago')), + _3y: createMetricPattern5(client, _m(acc, '3y_ago')), + _4y: createMetricPattern5(client, _m(acc, '4y_ago')), + _5y: createMetricPattern5(client, _m(acc, '5y_ago')), + _6m: createMetricPattern5(client, _m(acc, '6m_ago')), + _6y: createMetricPattern5(client, _m(acc, '6y_ago')), + _8y: createMetricPattern5(client, _m(acc, '8y_ago')), }; } @@ -2592,135 +2648,96 @@ function createPeriodLumpSumStackPattern(client, acc) { /** * @template T - * @typedef {Object} PeriodAvgPricePattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _1m - * @property {MetricPattern4} _1w - * @property {MetricPattern4} _1y - * @property {MetricPattern4} _2y - * @property {MetricPattern4} _3m - * @property {MetricPattern4} _3y - * @property {MetricPattern4} _4y - * @property {MetricPattern4} _5y - * @property {MetricPattern4} _6m - * @property {MetricPattern4} _6y - * @property {MetricPattern4} _8y + * @typedef {Object} PeriodAveragePricePattern + * @property {MetricPattern5} _10y + * @property {MetricPattern5} _1m + * @property {MetricPattern5} _1w + * @property {MetricPattern5} _1y + * @property {MetricPattern5} _2y + * @property {MetricPattern5} _3m + * @property {MetricPattern5} _3y + * @property {MetricPattern5} _4y + * @property {MetricPattern5} _5y + * @property {MetricPattern5} _6m + * @property {MetricPattern5} _6y + * @property {MetricPattern5} _8y */ /** - * Create a PeriodAvgPricePattern pattern node + * Create a PeriodAveragePricePattern pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {PeriodAvgPricePattern} + * @returns {PeriodAveragePricePattern} */ -function createPeriodAvgPricePattern(client, acc) { +function createPeriodAveragePricePattern(client, acc) { return { - _10y: createMetricPattern4(client, (acc ? `10y_${acc}` : '10y')), - _1m: createMetricPattern4(client, (acc ? `1m_${acc}` : '1m')), - _1w: createMetricPattern4(client, (acc ? `1w_${acc}` : '1w')), - _1y: createMetricPattern4(client, (acc ? `1y_${acc}` : '1y')), - _2y: createMetricPattern4(client, (acc ? `2y_${acc}` : '2y')), - _3m: createMetricPattern4(client, (acc ? `3m_${acc}` : '3m')), - _3y: createMetricPattern4(client, (acc ? `3y_${acc}` : '3y')), - _4y: createMetricPattern4(client, (acc ? `4y_${acc}` : '4y')), - _5y: createMetricPattern4(client, (acc ? `5y_${acc}` : '5y')), - _6m: createMetricPattern4(client, (acc ? `6m_${acc}` : '6m')), - _6y: createMetricPattern4(client, (acc ? `6y_${acc}` : '6y')), - _8y: createMetricPattern4(client, (acc ? `8y_${acc}` : '8y')), + _10y: createMetricPattern5(client, (acc ? `10y_${acc}` : '10y')), + _1m: createMetricPattern5(client, (acc ? `1m_${acc}` : '1m')), + _1w: createMetricPattern5(client, (acc ? `1w_${acc}` : '1w')), + _1y: createMetricPattern5(client, (acc ? `1y_${acc}` : '1y')), + _2y: createMetricPattern5(client, (acc ? `2y_${acc}` : '2y')), + _3m: createMetricPattern5(client, (acc ? `3m_${acc}` : '3m')), + _3y: createMetricPattern5(client, (acc ? `3y_${acc}` : '3y')), + _4y: createMetricPattern5(client, (acc ? `4y_${acc}` : '4y')), + _5y: createMetricPattern5(client, (acc ? `5y_${acc}` : '5y')), + _6m: createMetricPattern5(client, (acc ? `6m_${acc}` : '6m')), + _6y: createMetricPattern5(client, (acc ? `6y_${acc}` : '6y')), + _8y: createMetricPattern5(client, (acc ? `8y_${acc}` : '8y')), }; } /** * @template T - * @typedef {Object} BitcoinPattern - * @property {MetricPattern2} average - * @property {MetricPattern25} base - * @property {MetricPattern1} cumulative - * @property {MetricPattern2} max - * @property {MetricPattern21} median - * @property {MetricPattern2} min - * @property {MetricPattern21} pct10 - * @property {MetricPattern21} pct25 - * @property {MetricPattern21} pct75 - * @property {MetricPattern21} pct90 - * @property {MetricPattern2} sum + * @typedef {Object} ClassAveragePricePattern + * @property {MetricPattern5} _2015 + * @property {MetricPattern5} _2016 + * @property {MetricPattern5} _2017 + * @property {MetricPattern5} _2018 + * @property {MetricPattern5} _2019 + * @property {MetricPattern5} _2020 + * @property {MetricPattern5} _2021 + * @property {MetricPattern5} _2022 + * @property {MetricPattern5} _2023 + * @property {MetricPattern5} _2024 + * @property {MetricPattern5} _2025 */ /** - * Create a BitcoinPattern pattern node + * Create a ClassAveragePricePattern pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {BitcoinPattern} + * @returns {ClassAveragePricePattern} */ -function createBitcoinPattern(client, acc) { +function createClassAveragePricePattern(client, acc) { return { - average: createMetricPattern2(client, _m(acc, 'avg')), - base: createMetricPattern25(client, acc), - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), - max: createMetricPattern2(client, _m(acc, 'max')), - median: createMetricPattern21(client, _m(acc, 'median')), - min: createMetricPattern2(client, _m(acc, 'min')), - pct10: createMetricPattern21(client, _m(acc, 'pct10')), - pct25: createMetricPattern21(client, _m(acc, 'pct25')), - pct75: createMetricPattern21(client, _m(acc, 'pct75')), - pct90: createMetricPattern21(client, _m(acc, 'pct90')), - sum: createMetricPattern2(client, _m(acc, 'sum')), - }; -} - -/** - * @template T - * @typedef {Object} ClassAvgPricePattern - * @property {MetricPattern4} _2015 - * @property {MetricPattern4} _2016 - * @property {MetricPattern4} _2017 - * @property {MetricPattern4} _2018 - * @property {MetricPattern4} _2019 - * @property {MetricPattern4} _2020 - * @property {MetricPattern4} _2021 - * @property {MetricPattern4} _2022 - * @property {MetricPattern4} _2023 - * @property {MetricPattern4} _2024 - * @property {MetricPattern4} _2025 - */ - -/** - * Create a ClassAvgPricePattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {ClassAvgPricePattern} - */ -function createClassAvgPricePattern(client, acc) { - return { - _2015: createMetricPattern4(client, _m(acc, '2015_avg_price')), - _2016: createMetricPattern4(client, _m(acc, '2016_avg_price')), - _2017: createMetricPattern4(client, _m(acc, '2017_avg_price')), - _2018: createMetricPattern4(client, _m(acc, '2018_avg_price')), - _2019: createMetricPattern4(client, _m(acc, '2019_avg_price')), - _2020: createMetricPattern4(client, _m(acc, '2020_avg_price')), - _2021: createMetricPattern4(client, _m(acc, '2021_avg_price')), - _2022: createMetricPattern4(client, _m(acc, '2022_avg_price')), - _2023: createMetricPattern4(client, _m(acc, '2023_avg_price')), - _2024: createMetricPattern4(client, _m(acc, '2024_avg_price')), - _2025: createMetricPattern4(client, _m(acc, '2025_avg_price')), + _2015: createMetricPattern5(client, _m(acc, '2015_average_price')), + _2016: createMetricPattern5(client, _m(acc, '2016_average_price')), + _2017: createMetricPattern5(client, _m(acc, '2017_average_price')), + _2018: createMetricPattern5(client, _m(acc, '2018_average_price')), + _2019: createMetricPattern5(client, _m(acc, '2019_average_price')), + _2020: createMetricPattern5(client, _m(acc, '2020_average_price')), + _2021: createMetricPattern5(client, _m(acc, '2021_average_price')), + _2022: createMetricPattern5(client, _m(acc, '2022_average_price')), + _2023: createMetricPattern5(client, _m(acc, '2023_average_price')), + _2024: createMetricPattern5(client, _m(acc, '2024_average_price')), + _2025: createMetricPattern5(client, _m(acc, '2025_average_price')), }; } /** * @typedef {Object} RelativePattern2 - * @property {MetricPattern5} negUnrealizedLossRelToOwnMarketCap - * @property {MetricPattern5} negUnrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} negUnrealizedLossRelToOwnMarketCap + * @property {MetricPattern3} negUnrealizedLossRelToOwnTotalUnrealizedPnl * @property {MetricPattern3} netUnrealizedPnlRelToOwnMarketCap * @property {MetricPattern3} netUnrealizedPnlRelToOwnTotalUnrealizedPnl - * @property {MetricPattern5} supplyInLossRelToOwnSupply - * @property {MetricPattern5} supplyInProfitRelToOwnSupply - * @property {MetricPattern5} unrealizedLossRelToOwnMarketCap - * @property {MetricPattern5} unrealizedLossRelToOwnTotalUnrealizedPnl - * @property {MetricPattern5} unrealizedProfitRelToOwnMarketCap - * @property {MetricPattern5} unrealizedProfitRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} supplyInLossRelToOwnSupply + * @property {MetricPattern3} supplyInProfitRelToOwnSupply + * @property {MetricPattern3} unrealizedLossRelToOwnMarketCap + * @property {MetricPattern3} unrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} unrealizedProfitRelToOwnMarketCap + * @property {MetricPattern3} unrealizedProfitRelToOwnTotalUnrealizedPnl */ /** @@ -2731,31 +2748,31 @@ function createClassAvgPricePattern(client, acc) { */ function createRelativePattern2(client, acc) { return { - negUnrealizedLossRelToOwnMarketCap: createMetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')), - negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')), + negUnrealizedLossRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')), + negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')), netUnrealizedPnlRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')), netUnrealizedPnlRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')), - supplyInLossRelToOwnSupply: createMetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), - unrealizedLossRelToOwnMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), - unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), - unrealizedProfitRelToOwnMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), - unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), + supplyInLossRelToOwnSupply: createMetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), + unrealizedLossRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')), + unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')), + unrealizedProfitRelToOwnMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')), + unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')), }; } /** * @typedef {Object} RelativePattern - * @property {MetricPattern5} negUnrealizedLossRelToMarketCap + * @property {MetricPattern3} negUnrealizedLossRelToMarketCap * @property {MetricPattern3} netUnrealizedPnlRelToMarketCap - * @property {MetricPattern4} nupl - * @property {MetricPattern5} supplyInLossRelToCirculatingSupply - * @property {MetricPattern5} supplyInLossRelToOwnSupply - * @property {MetricPattern5} supplyInProfitRelToCirculatingSupply - * @property {MetricPattern5} supplyInProfitRelToOwnSupply - * @property {MetricPattern4} supplyRelToCirculatingSupply - * @property {MetricPattern5} unrealizedLossRelToMarketCap - * @property {MetricPattern5} unrealizedProfitRelToMarketCap + * @property {MetricPattern5} nupl + * @property {MetricPattern3} supplyInLossRelToCirculatingSupply + * @property {MetricPattern3} supplyInLossRelToOwnSupply + * @property {MetricPattern3} supplyInProfitRelToCirculatingSupply + * @property {MetricPattern3} supplyInProfitRelToOwnSupply + * @property {MetricPattern5} supplyRelToCirculatingSupply + * @property {MetricPattern3} unrealizedLossRelToMarketCap + * @property {MetricPattern3} unrealizedProfitRelToMarketCap */ /** @@ -2766,53 +2783,16 @@ function createRelativePattern2(client, acc) { */ function createRelativePattern(client, acc) { return { - negUnrealizedLossRelToMarketCap: createMetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')), + negUnrealizedLossRelToMarketCap: createMetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')), netUnrealizedPnlRelToMarketCap: createMetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')), - nupl: createMetricPattern4(client, _m(acc, 'nupl')), - supplyInLossRelToCirculatingSupply: createMetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')), - supplyInLossRelToOwnSupply: createMetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), - supplyInProfitRelToCirculatingSupply: createMetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), - supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')), - unrealizedLossRelToMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_market_cap')), - unrealizedProfitRelToMarketCap: createMetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_market_cap')), - }; -} - -/** - * @template T - * @typedef {Object} BlockSizePattern - * @property {MetricPattern2} average - * @property {MetricPattern1} cumulative - * @property {MetricPattern2} max - * @property {MetricPattern21} median - * @property {MetricPattern2} min - * @property {MetricPattern21} pct10 - * @property {MetricPattern21} pct25 - * @property {MetricPattern21} pct75 - * @property {MetricPattern21} pct90 - * @property {MetricPattern2} sum - */ - -/** - * Create a BlockSizePattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {BlockSizePattern} - */ -function createBlockSizePattern(client, acc) { - return { - average: createMetricPattern2(client, _m(acc, 'avg')), - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), - max: createMetricPattern2(client, _m(acc, 'max')), - median: createMetricPattern21(client, _m(acc, 'median')), - min: createMetricPattern2(client, _m(acc, 'min')), - pct10: createMetricPattern21(client, _m(acc, 'pct10')), - pct25: createMetricPattern21(client, _m(acc, 'pct25')), - pct75: createMetricPattern21(client, _m(acc, 'pct75')), - pct90: createMetricPattern21(client, _m(acc, 'pct90')), - sum: createMetricPattern2(client, _m(acc, 'sum')), + nupl: createMetricPattern5(client, _m(acc, 'nupl')), + supplyInLossRelToCirculatingSupply: createMetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')), + supplyInLossRelToOwnSupply: createMetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_own_supply')), + supplyInProfitRelToCirculatingSupply: createMetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_own_supply')), + supplyRelToCirculatingSupply: createMetricPattern5(client, _m(acc, 'supply_rel_to_circulating_supply')), + unrealizedLossRelToMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_market_cap')), + unrealizedProfitRelToMarketCap: createMetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_market_cap')), }; } @@ -2852,14 +2832,14 @@ function createUnrealizedPattern(client, acc) { /** * @template T * @typedef {Object} AddresstypeToHeightToAddrCountPattern - * @property {MetricPattern29} p2a - * @property {MetricPattern31} p2pk33 - * @property {MetricPattern32} p2pk65 - * @property {MetricPattern33} p2pkh - * @property {MetricPattern34} p2sh - * @property {MetricPattern35} p2tr - * @property {MetricPattern36} p2wpkh - * @property {MetricPattern37} p2wsh + * @property {MetricPattern26} p2a + * @property {MetricPattern26} p2pk33 + * @property {MetricPattern26} p2pk65 + * @property {MetricPattern26} p2pkh + * @property {MetricPattern26} p2sh + * @property {MetricPattern26} p2tr + * @property {MetricPattern26} p2wpkh + * @property {MetricPattern26} p2wsh */ /** @@ -2871,47 +2851,47 @@ function createUnrealizedPattern(client, acc) { */ function createAddresstypeToHeightToAddrCountPattern(client, acc) { return { - p2a: createMetricPattern29(client, (acc ? `p2a_${acc}` : 'p2a')), - p2pk33: createMetricPattern31(client, (acc ? `p2pk33_${acc}` : 'p2pk33')), - p2pk65: createMetricPattern32(client, (acc ? `p2pk65_${acc}` : 'p2pk65')), - p2pkh: createMetricPattern33(client, (acc ? `p2pkh_${acc}` : 'p2pkh')), - p2sh: createMetricPattern34(client, (acc ? `p2sh_${acc}` : 'p2sh')), - p2tr: createMetricPattern35(client, (acc ? `p2tr_${acc}` : 'p2tr')), - p2wpkh: createMetricPattern36(client, (acc ? `p2wpkh_${acc}` : 'p2wpkh')), - p2wsh: createMetricPattern37(client, (acc ? `p2wsh_${acc}` : 'p2wsh')), + p2a: createMetricPattern26(client, (acc ? `p2a_${acc}` : 'p2a')), + p2pk33: createMetricPattern26(client, (acc ? `p2pk33_${acc}` : 'p2pk33')), + p2pk65: createMetricPattern26(client, (acc ? `p2pk65_${acc}` : 'p2pk65')), + p2pkh: createMetricPattern26(client, (acc ? `p2pkh_${acc}` : 'p2pkh')), + p2sh: createMetricPattern26(client, (acc ? `p2sh_${acc}` : 'p2sh')), + p2tr: createMetricPattern26(client, (acc ? `p2tr_${acc}` : 'p2tr')), + p2wpkh: createMetricPattern26(client, (acc ? `p2wpkh_${acc}` : 'p2wpkh')), + p2wsh: createMetricPattern26(client, (acc ? `p2wsh_${acc}` : 'p2wsh')), }; } /** * @template T - * @typedef {Object} BlockIntervalPattern - * @property {MetricPattern1} average - * @property {MetricPattern1} max - * @property {MetricPattern25} median - * @property {MetricPattern1} min - * @property {MetricPattern25} pct10 - * @property {MetricPattern25} pct25 - * @property {MetricPattern25} pct75 - * @property {MetricPattern25} pct90 + * @typedef {Object} CountPattern2 + * @property {MetricPattern2} average + * @property {MetricPattern6} cumulative + * @property {BlockIntervalPattern} distribution + * @property {MetricPattern6} max + * @property {MetricPattern6} min + * @property {MinmaxPattern} minmax + * @property {MetricPattern6} sum + * @property {SumCumPattern} sumCum */ /** - * Create a BlockIntervalPattern pattern node + * Create a CountPattern2 pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {BlockIntervalPattern} + * @returns {CountPattern2} */ -function createBlockIntervalPattern(client, acc) { +function createCountPattern2(client, acc) { return { - average: createMetricPattern1(client, _m(acc, 'avg')), - max: createMetricPattern1(client, _m(acc, 'max')), - median: createMetricPattern25(client, _m(acc, 'median')), - min: createMetricPattern1(client, _m(acc, 'min')), - pct10: createMetricPattern25(client, _m(acc, 'pct10')), - pct25: createMetricPattern25(client, _m(acc, 'pct25')), - pct75: createMetricPattern25(client, _m(acc, 'pct75')), - pct90: createMetricPattern25(client, _m(acc, 'pct90')), + average: createMetricPattern2(client, _m(acc, 'average')), + cumulative: createMetricPattern6(client, _m(acc, 'cumulative')), + distribution: createBlockIntervalPattern(client, acc), + max: createMetricPattern6(client, _m(acc, 'max')), + min: createMetricPattern6(client, _m(acc, 'min')), + minmax: createMinmaxPattern(client, acc), + sum: createMetricPattern6(client, _m(acc, 'sum')), + sumCum: createSumCumPattern(client, acc), }; } @@ -2946,13 +2926,13 @@ function create_0satsPattern(client, acc) { /** * @typedef {Object} PeriodCagrPattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _2y - * @property {MetricPattern4} _3y - * @property {MetricPattern4} _4y - * @property {MetricPattern4} _5y - * @property {MetricPattern4} _6y - * @property {MetricPattern4} _8y + * @property {MetricPattern5} _10y + * @property {MetricPattern5} _2y + * @property {MetricPattern5} _3y + * @property {MetricPattern5} _4y + * @property {MetricPattern5} _5y + * @property {MetricPattern5} _6y + * @property {MetricPattern5} _8y */ /** @@ -2963,40 +2943,75 @@ function create_0satsPattern(client, acc) { */ function createPeriodCagrPattern(client, acc) { return { - _10y: createMetricPattern4(client, (acc ? `10y_${acc}` : '10y')), - _2y: createMetricPattern4(client, (acc ? `2y_${acc}` : '2y')), - _3y: createMetricPattern4(client, (acc ? `3y_${acc}` : '3y')), - _4y: createMetricPattern4(client, (acc ? `4y_${acc}` : '4y')), - _5y: createMetricPattern4(client, (acc ? `5y_${acc}` : '5y')), - _6y: createMetricPattern4(client, (acc ? `6y_${acc}` : '6y')), - _8y: createMetricPattern4(client, (acc ? `8y_${acc}` : '8y')), + _10y: createMetricPattern5(client, (acc ? `10y_${acc}` : '10y')), + _2y: createMetricPattern5(client, (acc ? `2y_${acc}` : '2y')), + _3y: createMetricPattern5(client, (acc ? `3y_${acc}` : '3y')), + _4y: createMetricPattern5(client, (acc ? `4y_${acc}` : '4y')), + _5y: createMetricPattern5(client, (acc ? `5y_${acc}` : '5y')), + _6y: createMetricPattern5(client, (acc ? `6y_${acc}` : '6y')), + _8y: createMetricPattern5(client, (acc ? `8y_${acc}` : '8y')), }; } /** - * @typedef {Object} _0satsPattern2 - * @property {ActivityPattern2} activity - * @property {CostBasisPattern} costBasis - * @property {RealizedPattern} realized - * @property {RelativePattern4} relative - * @property {SupplyPattern3} supply - * @property {UnrealizedPattern} unrealized + * @template T + * @typedef {Object} BlockSizePattern + * @property {MetricPattern6} average + * @property {MetricPattern4} cumulative + * @property {BlockIntervalPattern} distribution + * @property {MetricPattern6} max + * @property {MetricPattern6} min + * @property {MetricPattern6} sum + * @property {SumCumPattern} sumCum */ /** - * Create a _0satsPattern2 pattern node + * Create a BlockSizePattern pattern node + * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_0satsPattern2} + * @returns {BlockSizePattern} */ -function create_0satsPattern2(client, acc) { +function createBlockSizePattern(client, acc) { return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern(client, acc), - realized: createRealizedPattern(client, acc), - relative: createRelativePattern4(client, _m(acc, 'supply_in')), - supply: createSupplyPattern3(client, acc), - unrealized: createUnrealizedPattern(client, acc), + average: createMetricPattern6(client, _m(acc, 'average')), + cumulative: createMetricPattern4(client, _m(acc, 'cumulative')), + distribution: createBlockIntervalPattern(client, acc), + max: createMetricPattern6(client, _m(acc, 'max')), + min: createMetricPattern6(client, _m(acc, 'min')), + sum: createMetricPattern6(client, _m(acc, 'sum')), + sumCum: createSumCumPattern(client, acc), + }; +} + +/** + * @template T + * @typedef {Object} DollarsPattern + * @property {MetricPattern2} average + * @property {MetricPattern26} base + * @property {MetricPattern1} cumulative + * @property {MetricPattern2} max + * @property {MetricPattern2} min + * @property {PercentilesPattern} percentiles + * @property {MetricPattern2} sum + */ + +/** + * Create a DollarsPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {DollarsPattern} + */ +function createDollarsPattern(client, acc) { + return { + average: createMetricPattern2(client, _m(acc, 'average')), + base: createMetricPattern26(client, acc), + cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), + max: createMetricPattern2(client, _m(acc, 'max')), + min: createMetricPattern2(client, _m(acc, 'min')), + percentiles: createPercentilesPattern(client, acc), + sum: createMetricPattern2(client, _m(acc, 'sum')), }; } @@ -3027,33 +3042,6 @@ function create_10yPattern(client, acc) { }; } -/** - * @typedef {Object} _100btcPattern - * @property {ActivityPattern2} activity - * @property {CostBasisPattern} costBasis - * @property {RealizedPattern} realized - * @property {RelativePattern} relative - * @property {SupplyPattern3} supply - * @property {UnrealizedPattern} unrealized - */ - -/** - * Create a _100btcPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_100btcPattern} - */ -function create_100btcPattern(client, acc) { - return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern(client, acc), - realized: createRealizedPattern(client, acc), - relative: createRelativePattern(client, acc), - supply: createSupplyPattern3(client, acc), - unrealized: createUnrealizedPattern(client, acc), - }; -} - /** * @typedef {Object} _10yTo12yPattern * @property {ActivityPattern2} activity @@ -3081,29 +3069,83 @@ function create_10yTo12yPattern(client, acc) { }; } +/** + * @typedef {Object} _100btcPattern + * @property {ActivityPattern2} activity + * @property {CostBasisPattern} costBasis + * @property {RealizedPattern} realized + * @property {RelativePattern} relative + * @property {SupplyPattern3} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _100btcPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_100btcPattern} + */ +function create_100btcPattern(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern(client, acc), + realized: createRealizedPattern(client, acc), + relative: createRelativePattern(client, acc), + supply: createSupplyPattern3(client, acc), + unrealized: createUnrealizedPattern(client, acc), + }; +} + +/** + * @typedef {Object} _0satsPattern2 + * @property {ActivityPattern2} activity + * @property {CostBasisPattern} costBasis + * @property {RealizedPattern} realized + * @property {RelativePattern4} relative + * @property {SupplyPattern3} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _0satsPattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_0satsPattern2} + */ +function create_0satsPattern2(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern(client, acc), + realized: createRealizedPattern(client, acc), + relative: createRelativePattern4(client, _m(acc, 'supply_in')), + supply: createSupplyPattern3(client, acc), + unrealized: createUnrealizedPattern(client, acc), + }; +} + /** * @template T - * @typedef {Object} SegwitAdoptionPattern + * @typedef {Object} BitcoinPattern * @property {MetricPattern2} average - * @property {MetricPattern25} base - * @property {MetricPattern1} cumulative + * @property {MetricPattern26} base + * @property {MetricPattern2} cumulative * @property {MetricPattern2} max * @property {MetricPattern2} min * @property {MetricPattern2} sum */ /** - * Create a SegwitAdoptionPattern pattern node + * Create a BitcoinPattern pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {SegwitAdoptionPattern} + * @returns {BitcoinPattern} */ -function createSegwitAdoptionPattern(client, acc) { +function createBitcoinPattern(client, acc) { return { - average: createMetricPattern2(client, _m(acc, 'avg')), - base: createMetricPattern25(client, acc), - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), + average: createMetricPattern2(client, _m(acc, 'average')), + base: createMetricPattern26(client, acc), + cumulative: createMetricPattern2(client, _m(acc, 'cum')), max: createMetricPattern2(client, _m(acc, 'max')), min: createMetricPattern2(client, _m(acc, 'min')), sum: createMetricPattern2(client, _m(acc, 'sum')), @@ -3114,8 +3156,8 @@ function createSegwitAdoptionPattern(client, acc) { * @typedef {Object} ActivityPattern2 * @property {BlockCountPattern} coinblocksDestroyed * @property {BlockCountPattern} coindaysDestroyed - * @property {MetricPattern25} satblocksDestroyed - * @property {MetricPattern25} satdaysDestroyed + * @property {MetricPattern26} satblocksDestroyed + * @property {MetricPattern26} satdaysDestroyed * @property {SentPattern} sent */ @@ -3129,12 +3171,37 @@ function createActivityPattern2(client, acc) { return { coinblocksDestroyed: createBlockCountPattern(client, _m(acc, 'coinblocks_destroyed')), coindaysDestroyed: createBlockCountPattern(client, _m(acc, 'coindays_destroyed')), - satblocksDestroyed: createMetricPattern25(client, _m(acc, 'satblocks_destroyed')), - satdaysDestroyed: createMetricPattern25(client, _m(acc, 'satdays_destroyed')), + satblocksDestroyed: createMetricPattern26(client, _m(acc, 'satblocks_destroyed')), + satdaysDestroyed: createMetricPattern26(client, _m(acc, 'satdays_destroyed')), sent: createSentPattern(client, _m(acc, 'sent')), }; } +/** + * @typedef {Object} SentPattern + * @property {MetricPattern26} base + * @property {BlockCountPattern} bitcoin + * @property {SumCumPattern} dollars + * @property {MetricPattern26} dollarsSource + * @property {SumCumPattern} sats + */ + +/** + * Create a SentPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {SentPattern} + */ +function createSentPattern(client, acc) { + return { + base: createMetricPattern26(client, _m(acc, 'height_fee')), + bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), + dollars: createSumCumPattern(client, _m(acc, 'usd')), + dollarsSource: createMetricPattern26(client, _m(acc, 'usd')), + sats: createSumCumPattern(client, _m(acc, 'fee')), + }; +} + /** * @typedef {Object} SupplyPattern3 * @property {SupplyPattern2} supply @@ -3160,12 +3227,39 @@ function createSupplyPattern3(client, acc) { }; } +/** + * @template T + * @typedef {Object} PercentilesPattern + * @property {MetricPattern22} median + * @property {MetricPattern22} pct10 + * @property {MetricPattern22} pct25 + * @property {MetricPattern22} pct75 + * @property {MetricPattern22} pct90 + */ + +/** + * Create a PercentilesPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {PercentilesPattern} + */ +function createPercentilesPattern(client, acc) { + return { + median: createMetricPattern22(client, _m(acc, 'median')), + pct10: createMetricPattern22(client, _m(acc, 'pct10')), + pct25: createMetricPattern22(client, _m(acc, 'pct25')), + pct75: createMetricPattern22(client, _m(acc, 'pct75')), + pct90: createMetricPattern22(client, _m(acc, 'pct90')), + }; +} + /** * @typedef {Object} SupplyPattern2 - * @property {MetricPattern25} base - * @property {MetricPattern4} bitcoin - * @property {MetricPattern4} dollars - * @property {MetricPattern4} sats + * @property {MetricPattern26} base + * @property {MetricPattern5} bitcoin + * @property {MetricPattern5} dollars + * @property {MetricPattern7} sats */ /** @@ -3176,98 +3270,85 @@ function createSupplyPattern3(client, acc) { */ function createSupplyPattern2(client, acc) { return { - base: createMetricPattern25(client, acc), - bitcoin: createMetricPattern4(client, _m(acc, 'btc')), - dollars: createMetricPattern4(client, _m(acc, 'usd')), - sats: createMetricPattern4(client, acc), + base: createMetricPattern26(client, acc), + bitcoin: createMetricPattern5(client, _m(acc, 'btc')), + dollars: createMetricPattern5(client, _m(acc, 'usd')), + sats: createMetricPattern7(client, acc), }; } /** - * @typedef {Object} OpreturnPattern - * @property {MetricPattern25} base - * @property {BitcoinPattern2} bitcoin - * @property {BitcoinPattern2} dollars - * @property {SatsPattern4} sats + * @template T + * @typedef {Object} PriceHighInSatsPattern + * @property {MetricPattern22} dateindex + * @property {MetricPattern26} height + * @property {MetricPattern24} max + * @property {MetricPattern7} rest */ /** - * Create a OpreturnPattern pattern node + * Create a PriceHighInSatsPattern pattern node + * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {OpreturnPattern} + * @returns {PriceHighInSatsPattern} */ -function createOpreturnPattern(client, acc) { +function createPriceHighInSatsPattern(client, acc) { return { - base: createMetricPattern25(client, acc), - bitcoin: createBitcoinPattern2(client, _m(acc, 'btc')), - dollars: createBitcoinPattern2(client, _m(acc, 'usd')), - sats: createSatsPattern4(client, acc), + dateindex: createMetricPattern22(client, acc), + height: createMetricPattern26(client, acc), + max: createMetricPattern24(client, _m(acc, 'max')), + rest: createMetricPattern7(client, _m(acc, 'max')), }; } /** - * @typedef {Object} SentPattern - * @property {MetricPattern25} base - * @property {BlockCountPattern} bitcoin - * @property {BlockCountPattern} dollars - * @property {SatsPattern} sats + * @template T + * @typedef {Object} PriceLowInSatsPattern + * @property {MetricPattern22} dateindex + * @property {MetricPattern26} height + * @property {MetricPattern24} min + * @property {MetricPattern7} rest */ /** - * Create a SentPattern pattern node + * Create a PriceLowInSatsPattern pattern node + * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {SentPattern} + * @returns {PriceLowInSatsPattern} */ -function createSentPattern(client, acc) { +function createPriceLowInSatsPattern(client, acc) { return { - base: createMetricPattern25(client, acc), - bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), - dollars: createBlockCountPattern(client, _m(acc, 'usd')), - sats: createSatsPattern(client, acc), + dateindex: createMetricPattern22(client, acc), + height: createMetricPattern26(client, acc), + min: createMetricPattern24(client, _m(acc, 'min')), + rest: createMetricPattern7(client, _m(acc, 'min')), }; } /** - * @typedef {Object} CoinbasePattern - * @property {BitcoinPattern} bitcoin - * @property {BitcoinPattern} dollars - * @property {BitcoinPattern} sats + * @template T + * @typedef {Object} BlockIntervalPattern + * @property {MetricPattern22} average + * @property {MetricPattern22} max + * @property {MetricPattern22} min + * @property {PercentilesPattern} percentiles */ /** - * Create a CoinbasePattern pattern node + * Create a BlockIntervalPattern pattern node + * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {CoinbasePattern} + * @returns {BlockIntervalPattern} */ -function createCoinbasePattern(client, acc) { +function createBlockIntervalPattern(client, acc) { return { - bitcoin: createBitcoinPattern(client, _m(acc, 'btc')), - dollars: createBitcoinPattern(client, _m(acc, 'usd')), - sats: createBitcoinPattern(client, acc), - }; -} - -/** - * @typedef {Object} UnclaimedRewardsPattern - * @property {BlockCountPattern} bitcoin - * @property {BlockCountPattern} dollars - * @property {BlockCountPattern} sats - */ - -/** - * Create a UnclaimedRewardsPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {UnclaimedRewardsPattern} - */ -function createUnclaimedRewardsPattern(client, acc) { - return { - bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), - dollars: createBlockCountPattern(client, _m(acc, 'usd')), - sats: createBlockCountPattern(client, acc), + average: createMetricPattern22(client, _m(acc, 'average')), + max: createMetricPattern22(client, _m(acc, 'max')), + min: createMetricPattern22(client, _m(acc, 'min')), + percentiles: createPercentilesPattern(client, acc), }; } @@ -3296,7 +3377,7 @@ function createActiveSupplyPattern(client, acc) { * @typedef {Object} CostBasisPattern2 * @property {MetricPattern1} maxCostBasis * @property {MetricPattern1} minCostBasis - * @property {PercentilesPattern} percentiles + * @property {PercentilesPattern2} percentiles */ /** @@ -3309,15 +3390,57 @@ function createCostBasisPattern2(client, acc) { return { maxCostBasis: createMetricPattern1(client, _m(acc, 'max_cost_basis')), minCostBasis: createMetricPattern1(client, _m(acc, 'min_cost_basis')), - percentiles: createPercentilesPattern(client, _m(acc, 'cost_basis')), + percentiles: createPercentilesPattern2(client, _m(acc, 'cost_basis')), + }; +} + +/** + * @typedef {Object} CoinbasePattern + * @property {BitcoinPattern} bitcoin + * @property {DollarsPattern} dollars + * @property {DollarsPattern} sats + */ + +/** + * Create a CoinbasePattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CoinbasePattern} + */ +function createCoinbasePattern(client, acc) { + return { + bitcoin: createBitcoinPattern(client, _m(acc, 'btc')), + dollars: createDollarsPattern(client, _m(acc, 'usd')), + sats: createDollarsPattern(client, acc), + }; +} + +/** + * @typedef {Object} UnclaimedRewardsPattern + * @property {BlockCountPattern} bitcoin + * @property {BlockCountPattern} dollars + * @property {BlockCountPattern} sats + */ + +/** + * Create a UnclaimedRewardsPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {UnclaimedRewardsPattern} + */ +function createUnclaimedRewardsPattern(client, acc) { + return { + bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), + dollars: createBlockCountPattern(client, _m(acc, 'usd')), + sats: createBlockCountPattern(client, acc), }; } /** * @template T * @typedef {Object} BlockCountPattern - * @property {MetricPattern25} base - * @property {MetricPattern1} cumulative + * @property {MetricPattern26} base + * @property {MetricPattern2} cumulative * @property {MetricPattern2} sum */ @@ -3330,58 +3453,35 @@ function createCostBasisPattern2(client, acc) { */ function createBlockCountPattern(client, acc) { return { - base: createMetricPattern25(client, acc), - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), + base: createMetricPattern26(client, acc), + cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), sum: createMetricPattern2(client, _m(acc, 'sum')), }; } /** - * @template T - * @typedef {Object} BitcoinPattern2 - * @property {MetricPattern25} base - * @property {MetricPattern1} cumulative - * @property {MetricPattern2} last + * @typedef {Object} SupplyValuePattern + * @property {MetricPattern26} bitcoin + * @property {MetricPattern26} dollars */ /** - * Create a BitcoinPattern2 pattern node - * @template T + * Create a SupplyValuePattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {BitcoinPattern2} + * @returns {SupplyValuePattern} */ -function createBitcoinPattern2(client, acc) { +function createSupplyValuePattern(client, acc) { return { - base: createMetricPattern25(client, acc), - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), - last: createMetricPattern2(client, acc), - }; -} - -/** - * @typedef {Object} SatsPattern4 - * @property {MetricPattern1} cumulative - * @property {MetricPattern2} last - */ - -/** - * Create a SatsPattern4 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SatsPattern4} - */ -function createSatsPattern4(client, acc) { - return { - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), - last: createMetricPattern2(client, acc), + bitcoin: createMetricPattern26(client, _m(acc, 'btc')), + dollars: createMetricPattern26(client, _m(acc, 'usd')), }; } /** * @typedef {Object} RelativePattern4 - * @property {MetricPattern5} supplyInLossRelToOwnSupply - * @property {MetricPattern5} supplyInProfitRelToOwnSupply + * @property {MetricPattern3} supplyInLossRelToOwnSupply + * @property {MetricPattern3} supplyInProfitRelToOwnSupply */ /** @@ -3392,27 +3492,8 @@ function createSatsPattern4(client, acc) { */ function createRelativePattern4(client, acc) { return { - supplyInLossRelToOwnSupply: createMetricPattern5(client, _m(acc, 'loss_rel_to_own_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern5(client, _m(acc, 'profit_rel_to_own_supply')), - }; -} - -/** - * @typedef {Object} SatsPattern - * @property {MetricPattern1} cumulative - * @property {MetricPattern2} sum - */ - -/** - * Create a SatsPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SatsPattern} - */ -function createSatsPattern(client, acc) { - return { - cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), - sum: createMetricPattern2(client, acc), + supplyInLossRelToOwnSupply: createMetricPattern3(client, _m(acc, 'loss_rel_to_own_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern3(client, _m(acc, 'profit_rel_to_own_supply')), }; } @@ -3435,29 +3516,10 @@ function createCostBasisPattern(client, acc) { }; } -/** - * @typedef {Object} SupplyValuePattern - * @property {MetricPattern25} bitcoin - * @property {MetricPattern25} dollars - */ - -/** - * Create a SupplyValuePattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SupplyValuePattern} - */ -function createSupplyValuePattern(client, acc) { - return { - bitcoin: createMetricPattern25(client, _m(acc, 'btc')), - dollars: createMetricPattern25(client, _m(acc, 'usd')), - }; -} - /** * @typedef {Object} _1dReturns1mSdPattern - * @property {MetricPattern4} sd - * @property {MetricPattern4} sma + * @property {MetricPattern5} sd + * @property {MetricPattern5} sma */ /** @@ -3468,35 +3530,98 @@ function createSupplyValuePattern(client, acc) { */ function create_1dReturns1mSdPattern(client, acc) { return { - sd: createMetricPattern4(client, _m(acc, 'sd')), - sma: createMetricPattern4(client, _m(acc, 'sma')), + sd: createMetricPattern5(client, _m(acc, 'sd')), + sma: createMetricPattern5(client, _m(acc, 'sma')), }; } /** * @template T - * @typedef {Object} TotalRealizedPnlPattern - * @property {MetricPattern25} base + * @typedef {Object} MinmaxPattern + * @property {MetricPattern22} max + * @property {MetricPattern22} min + */ + +/** + * Create a MinmaxPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {MinmaxPattern} + */ +function createMinmaxPattern(client, acc) { + return { + max: createMetricPattern22(client, _m(acc, 'max')), + min: createMetricPattern22(client, _m(acc, 'min')), + }; +} + +/** + * @template T + * @typedef {Object} SumCumPattern + * @property {MetricPattern1} cumulative * @property {MetricPattern2} sum */ /** - * Create a TotalRealizedPnlPattern pattern node + * Create a SumCumPattern pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {TotalRealizedPnlPattern} + * @returns {SumCumPattern} */ -function createTotalRealizedPnlPattern(client, acc) { +function createSumCumPattern(client, acc) { return { - base: createMetricPattern25(client, acc), + cumulative: createMetricPattern1(client, _m(acc, 'cumulative')), sum: createMetricPattern2(client, _m(acc, 'sum')), }; } +/** + * @template T + * @typedef {Object} IndexesPattern2 + * @property {MetricPattern22} dateindex + * @property {MetricPattern7} rest + */ + +/** + * Create a IndexesPattern2 pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {IndexesPattern2} + */ +function createIndexesPattern2(client, acc) { + return { + dateindex: createMetricPattern22(client, acc), + rest: createMetricPattern7(client, _m(acc, 'average')), + }; +} + +/** + * @template T + * @typedef {Object} DifficultyAdjustmentPattern + * @property {MetricPattern26} base + * @property {MetricPattern2} rest + */ + +/** + * Create a DifficultyAdjustmentPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {DifficultyAdjustmentPattern} + */ +function createDifficultyAdjustmentPattern(client, acc) { + return { + base: createMetricPattern26(client, acc), + rest: createMetricPattern2(client, _m(acc, 'sum')), + }; +} + /** * @typedef {Object} RealizedPriceExtraPattern - * @property {MetricPattern4} ratio + * @property {MetricPattern5} ratio */ /** @@ -3507,7 +3632,7 @@ function createTotalRealizedPnlPattern(client, acc) { */ function createRealizedPriceExtraPattern(client, acc) { return { - ratio: createMetricPattern4(client, _m(acc, 'ratio')), + ratio: createMetricPattern5(client, _m(acc, 'ratio')), }; } @@ -3552,38 +3677,38 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Blocks_Count - * @property {MetricPattern4} _1mBlockCount - * @property {MetricPattern4} _1wBlockCount - * @property {MetricPattern4} _1yBlockCount - * @property {MetricPattern25} _24hBlockCount + * @property {MetricPattern5} _1mBlockCount + * @property {MetricPattern5} _1wBlockCount + * @property {MetricPattern5} _1yBlockCount + * @property {MetricPattern26} _24hBlockCount * @property {BlockCountPattern} blockCount - * @property {MetricPattern4} blockCountTarget + * @property {MetricPattern5} blockCountTarget */ /** * @typedef {Object} CatalogTree_Computed_Blocks_Difficulty * @property {MetricPattern1} blocksBeforeNextDifficultyAdjustment * @property {MetricPattern1} daysBeforeNextDifficultyAdjustment - * @property {MetricPattern4} difficultyepoch + * @property {MetricPattern5} difficultyepoch */ /** * @typedef {Object} CatalogTree_Computed_Blocks_Halving * @property {MetricPattern1} blocksBeforeNextHalving * @property {MetricPattern1} daysBeforeNextHalving - * @property {MetricPattern4} halvingepoch + * @property {MetricPattern5} halvingepoch */ /** * @typedef {Object} CatalogTree_Computed_Blocks_Interval * @property {BlockIntervalPattern} blockInterval - * @property {MetricPattern25} interval + * @property {MetricPattern26} interval */ /** * @typedef {Object} CatalogTree_Computed_Blocks_Mining * @property {MetricPattern2} difficulty - * @property {MetricPattern1} difficultyAdjustment + * @property {DifficultyAdjustmentPattern} difficultyAdjustment * @property {MetricPattern1} difficultyAsHash * @property {MetricPattern1} hashPricePhs * @property {MetricPattern1} hashPricePhsMin @@ -3591,10 +3716,10 @@ function createRealizedPriceExtraPattern(client, acc) { * @property {MetricPattern1} hashPriceThs * @property {MetricPattern1} hashPriceThsMin * @property {MetricPattern1} hashRate - * @property {MetricPattern4} hashRate1mSma - * @property {MetricPattern4} hashRate1wSma - * @property {MetricPattern4} hashRate1ySma - * @property {MetricPattern4} hashRate2mSma + * @property {MetricPattern5} hashRate1mSma + * @property {MetricPattern5} hashRate1wSma + * @property {MetricPattern5} hashRate1ySma + * @property {MetricPattern5} hashRate2mSma * @property {MetricPattern1} hashValuePhs * @property {MetricPattern1} hashValuePhsMin * @property {MetricPattern1} hashValueRebound @@ -3604,13 +3729,13 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Blocks_Rewards - * @property {MetricPattern25} _24hCoinbaseSum - * @property {MetricPattern25} _24hCoinbaseUsdSum + * @property {MetricPattern26} _24hCoinbaseSum + * @property {MetricPattern26} _24hCoinbaseUsdSum * @property {CoinbasePattern} coinbase - * @property {MetricPattern21} feeDominance + * @property {MetricPattern22} feeDominance * @property {CoinbasePattern} subsidy - * @property {MetricPattern21} subsidyDominance - * @property {MetricPattern4} subsidyUsd1ySma + * @property {MetricPattern22} subsidyDominance + * @property {MetricPattern5} subsidyUsd1ySma * @property {UnclaimedRewardsPattern} unclaimedRewards */ @@ -3618,15 +3743,15 @@ function createRealizedPriceExtraPattern(client, acc) { * @typedef {Object} CatalogTree_Computed_Blocks_Size * @property {BlockSizePattern} blockSize * @property {BlockSizePattern} blockVbytes - * @property {MetricPattern25} vbytes + * @property {MetricPattern26} vbytes */ /** * @typedef {Object} CatalogTree_Computed_Blocks_Time - * @property {MetricPattern25} date - * @property {MetricPattern25} dateFixed + * @property {MetricPattern26} date + * @property {MetricPattern26} dateFixed * @property {MetricPattern2} timestamp - * @property {MetricPattern25} timestampFixed + * @property {MetricPattern26} timestampFixed */ /** @@ -3656,9 +3781,9 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Cointime_Adjusted - * @property {MetricPattern4} cointimeAdjInflationRate - * @property {MetricPattern4} cointimeAdjTxBtcVelocity - * @property {MetricPattern4} cointimeAdjTxUsdVelocity + * @property {MetricPattern5} cointimeAdjInflationRate + * @property {MetricPattern5} cointimeAdjTxBtcVelocity + * @property {MetricPattern5} cointimeAdjTxUsdVelocity */ /** @@ -3727,10 +3852,10 @@ function createRealizedPriceExtraPattern(client, acc) { * @property {AddresstypeToHeightToAddrCountPattern} addresstypeToIndexesToAddrCount * @property {AddresstypeToHeightToAddrCountPattern} addresstypeToIndexesToEmptyAddrCount * @property {AddresstypeToHeightToAddrCountPattern} anyAddressIndexes - * @property {MetricPattern25} chainState + * @property {MetricPattern26} chainState * @property {MetricPattern1} emptyAddrCount - * @property {MetricPattern41} emptyaddressindex - * @property {MetricPattern40} loadedaddressindex + * @property {MetricPattern42} emptyaddressindex + * @property {MetricPattern41} loadedaddressindex * @property {CatalogTree_Computed_Distribution_UtxoCohorts} utxoCohorts */ @@ -3796,8 +3921,8 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Distribution_AddressesData - * @property {MetricPattern41} empty - * @property {MetricPattern40} loaded + * @property {MetricPattern42} empty + * @property {MetricPattern41} loaded */ /** @@ -3852,12 +3977,12 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Distribution_UtxoCohorts_All_Relative - * @property {MetricPattern5} negUnrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} negUnrealizedLossRelToOwnTotalUnrealizedPnl * @property {MetricPattern3} netUnrealizedPnlRelToOwnTotalUnrealizedPnl - * @property {MetricPattern5} supplyInLossRelToOwnSupply - * @property {MetricPattern5} supplyInProfitRelToOwnSupply - * @property {MetricPattern5} unrealizedLossRelToOwnTotalUnrealizedPnl - * @property {MetricPattern5} unrealizedProfitRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} supplyInLossRelToOwnSupply + * @property {MetricPattern3} supplyInProfitRelToOwnSupply + * @property {MetricPattern3} unrealizedLossRelToOwnTotalUnrealizedPnl + * @property {MetricPattern3} unrealizedProfitRelToOwnTotalUnrealizedPnl */ /** @@ -4039,58 +4164,58 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Indexes_Address - * @property {MetricPattern24} emptyoutputindex - * @property {MetricPattern27} opreturnindex - * @property {MetricPattern29} p2aaddressindex - * @property {MetricPattern30} p2msoutputindex - * @property {MetricPattern31} p2pk33addressindex - * @property {MetricPattern32} p2pk65addressindex - * @property {MetricPattern33} p2pkhaddressindex - * @property {MetricPattern34} p2shaddressindex - * @property {MetricPattern35} p2traddressindex - * @property {MetricPattern36} p2wpkhaddressindex - * @property {MetricPattern37} p2wshaddressindex - * @property {MetricPattern39} unknownoutputindex + * @property {MetricPattern25} emptyoutputindex + * @property {MetricPattern28} opreturnindex + * @property {MetricPattern30} p2aaddressindex + * @property {MetricPattern31} p2msoutputindex + * @property {MetricPattern32} p2pk33addressindex + * @property {MetricPattern33} p2pk65addressindex + * @property {MetricPattern34} p2pkhaddressindex + * @property {MetricPattern35} p2shaddressindex + * @property {MetricPattern36} p2traddressindex + * @property {MetricPattern37} p2wpkhaddressindex + * @property {MetricPattern38} p2wshaddressindex + * @property {MetricPattern40} unknownoutputindex */ /** * @typedef {Object} CatalogTree_Computed_Indexes_Block - * @property {MetricPattern25} dateindex - * @property {MetricPattern14} difficultyepoch - * @property {MetricPattern13} firstHeight - * @property {MetricPattern15} halvingepoch - * @property {MetricPattern25} height - * @property {MetricPattern23} heightCount - * @property {MetricPattern25} txindexCount + * @property {MetricPattern26} dateindex + * @property {MetricPattern15} difficultyepoch + * @property {MetricPattern14} firstHeight + * @property {MetricPattern16} halvingepoch + * @property {MetricPattern26} height + * @property {MetricPattern24} heightCount + * @property {MetricPattern26} txindexCount */ /** * @typedef {Object} CatalogTree_Computed_Indexes_Time - * @property {MetricPattern21} date - * @property {MetricPattern21} dateindex - * @property {MetricPattern19} dateindexCount - * @property {MetricPattern12} decadeindex - * @property {MetricPattern19} firstDateindex - * @property {MetricPattern21} firstHeight - * @property {MetricPattern8} firstMonthindex - * @property {MetricPattern22} firstYearindex - * @property {MetricPattern21} heightCount - * @property {MetricPattern10} monthindex - * @property {MetricPattern8} monthindexCount - * @property {MetricPattern17} quarterindex - * @property {MetricPattern18} semesterindex - * @property {MetricPattern11} weekindex - * @property {MetricPattern20} yearindex - * @property {MetricPattern22} yearindexCount + * @property {MetricPattern22} date + * @property {MetricPattern22} dateindex + * @property {MetricPattern20} dateindexCount + * @property {MetricPattern13} decadeindex + * @property {MetricPattern20} firstDateindex + * @property {MetricPattern22} firstHeight + * @property {MetricPattern9} firstMonthindex + * @property {MetricPattern23} firstYearindex + * @property {MetricPattern22} heightCount + * @property {MetricPattern11} monthindex + * @property {MetricPattern9} monthindexCount + * @property {MetricPattern18} quarterindex + * @property {MetricPattern19} semesterindex + * @property {MetricPattern12} weekindex + * @property {MetricPattern21} yearindex + * @property {MetricPattern23} yearindexCount */ /** * @typedef {Object} CatalogTree_Computed_Indexes_Transaction - * @property {MetricPattern38} inputCount - * @property {MetricPattern38} outputCount - * @property {MetricPattern38} txindex - * @property {MetricPattern26} txinindex - * @property {MetricPattern28} txoutindex + * @property {MetricPattern39} inputCount + * @property {MetricPattern39} outputCount + * @property {MetricPattern39} txindex + * @property {MetricPattern27} txinindex + * @property {MetricPattern29} txoutindex */ /** @@ -4101,13 +4226,13 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Inputs_Count - * @property {BlockSizePattern} count + * @property {CountPattern2} count */ /** * @typedef {Object} CatalogTree_Computed_Inputs_Spent - * @property {MetricPattern26} txoutindex - * @property {MetricPattern26} value + * @property {MetricPattern27} txoutindex + * @property {MetricPattern27} value */ /** @@ -4124,22 +4249,23 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Market_Ath - * @property {MetricPattern4} daysSincePriceAth - * @property {MetricPattern4} maxDaysBetweenPriceAths - * @property {MetricPattern4} maxYearsBetweenPriceAths + * @property {MetricPattern5} daysSincePriceAth + * @property {MetricPattern5} maxDaysBetweenPriceAths + * @property {MetricPattern5} maxYearsBetweenPriceAths * @property {MetricPattern3} priceAth * @property {MetricPattern3} priceDrawdown + * @property {MetricPattern5} yearsSincePriceAth */ /** * @typedef {Object} CatalogTree_Computed_Market_Dca - * @property {ClassAvgPricePattern} classAvgPrice - * @property {ClassAvgPricePattern} classReturns + * @property {ClassAveragePricePattern} classAveragePrice + * @property {ClassAveragePricePattern} classReturns * @property {CatalogTree_Computed_Market_Dca_ClassStack} classStack - * @property {PeriodAvgPricePattern} periodAvgPrice + * @property {PeriodAveragePricePattern} periodAveragePrice * @property {PeriodCagrPattern} periodCagr * @property {PeriodLumpSumStackPattern} periodLumpSumStack - * @property {PeriodAvgPricePattern} periodReturns + * @property {PeriodAveragePricePattern} periodReturns * @property {PeriodLumpSumStackPattern} periodStack */ @@ -4160,25 +4286,25 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Market_Indicators - * @property {MetricPattern21} gini - * @property {MetricPattern21} macdHistogram - * @property {MetricPattern21} macdLine - * @property {MetricPattern21} macdSignal - * @property {MetricPattern21} nvt - * @property {MetricPattern21} piCycle - * @property {MetricPattern4} puellMultiple - * @property {MetricPattern21} rsi14d - * @property {MetricPattern21} rsi14dMax - * @property {MetricPattern21} rsi14dMin - * @property {MetricPattern21} rsiAvgGain14d - * @property {MetricPattern21} rsiAvgLoss14d - * @property {MetricPattern21} rsiGains - * @property {MetricPattern21} rsiLosses - * @property {MetricPattern21} stochD - * @property {MetricPattern21} stochK - * @property {MetricPattern21} stochRsi - * @property {MetricPattern21} stochRsiD - * @property {MetricPattern21} stochRsiK + * @property {MetricPattern22} gini + * @property {MetricPattern22} macdHistogram + * @property {MetricPattern22} macdLine + * @property {MetricPattern22} macdSignal + * @property {MetricPattern5} nvt + * @property {MetricPattern22} piCycle + * @property {MetricPattern5} puellMultiple + * @property {MetricPattern22} rsi14d + * @property {MetricPattern22} rsi14dMax + * @property {MetricPattern22} rsi14dMin + * @property {MetricPattern22} rsiAverageGain14d + * @property {MetricPattern22} rsiAverageLoss14d + * @property {MetricPattern22} rsiGains + * @property {MetricPattern22} rsiLosses + * @property {MetricPattern22} stochD + * @property {MetricPattern22} stochK + * @property {MetricPattern22} stochRsi + * @property {MetricPattern22} stochRsiD + * @property {MetricPattern22} stochRsiK */ /** @@ -4202,8 +4328,8 @@ function createRealizedPriceExtraPattern(client, acc) { * @property {Price111dSmaPattern} price1ySma * @property {Price111dSmaPattern} price200dEma * @property {Price111dSmaPattern} price200dSma - * @property {MetricPattern4} price200dSmaX08 - * @property {MetricPattern4} price200dSmaX24 + * @property {MetricPattern5} price200dSmaX08 + * @property {MetricPattern5} price200dSmaX24 * @property {Price111dSmaPattern} price200wEma * @property {Price111dSmaPattern} price200wSma * @property {Price111dSmaPattern} price21dEma @@ -4214,7 +4340,7 @@ function createRealizedPriceExtraPattern(client, acc) { * @property {Price111dSmaPattern} price34dEma * @property {Price111dSmaPattern} price34dSma * @property {Price111dSmaPattern} price350dSma - * @property {MetricPattern4} price350dSmaX2 + * @property {MetricPattern5} price350dSmaX2 * @property {Price111dSmaPattern} price4yEma * @property {Price111dSmaPattern} price4ySma * @property {Price111dSmaPattern} price55dEma @@ -4227,17 +4353,17 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Market_Range - * @property {MetricPattern4} price1mMax - * @property {MetricPattern4} price1mMin - * @property {MetricPattern4} price1wMax - * @property {MetricPattern4} price1wMin - * @property {MetricPattern4} price1yMax - * @property {MetricPattern4} price1yMin - * @property {MetricPattern4} price2wChoppinessIndex - * @property {MetricPattern4} price2wMax - * @property {MetricPattern4} price2wMin - * @property {MetricPattern21} priceTrueRange - * @property {MetricPattern21} priceTrueRange2wSum + * @property {MetricPattern5} price1mMax + * @property {MetricPattern5} price1mMin + * @property {MetricPattern5} price1wMax + * @property {MetricPattern5} price1wMin + * @property {MetricPattern5} price1yMax + * @property {MetricPattern5} price1yMin + * @property {MetricPattern5} price2wChoppinessIndex + * @property {MetricPattern5} price2wMax + * @property {MetricPattern5} price2wMin + * @property {MetricPattern22} priceTrueRange + * @property {MetricPattern22} priceTrueRange2wSum */ /** @@ -4249,21 +4375,21 @@ function createRealizedPriceExtraPattern(client, acc) { * @property {_1dReturns1mSdPattern} downside1mSd * @property {_1dReturns1mSdPattern} downside1wSd * @property {_1dReturns1mSdPattern} downside1ySd - * @property {MetricPattern21} downsideReturns + * @property {MetricPattern22} downsideReturns * @property {PriceAgoPattern} priceReturns */ /** * @typedef {Object} CatalogTree_Computed_Market_Volatility - * @property {MetricPattern4} price1mVolatility - * @property {MetricPattern4} price1wVolatility - * @property {MetricPattern4} price1yVolatility - * @property {MetricPattern21} sharpe1m - * @property {MetricPattern21} sharpe1w - * @property {MetricPattern21} sharpe1y - * @property {MetricPattern21} sortino1m - * @property {MetricPattern21} sortino1w - * @property {MetricPattern21} sortino1y + * @property {MetricPattern5} price1mVolatility + * @property {MetricPattern5} price1wVolatility + * @property {MetricPattern5} price1yVolatility + * @property {MetricPattern22} sharpe1m + * @property {MetricPattern22} sharpe1w + * @property {MetricPattern22} sharpe1y + * @property {MetricPattern22} sortino1m + * @property {MetricPattern22} sortino1w + * @property {MetricPattern22} sortino1y */ /** @@ -4274,18 +4400,18 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Outputs_Count - * @property {BlockSizePattern} count - * @property {BitcoinPattern} utxoCount + * @property {CountPattern2} count + * @property {DollarsPattern} utxoCount */ /** * @typedef {Object} CatalogTree_Computed_Outputs_Spent - * @property {MetricPattern28} txinindex + * @property {MetricPattern29} txinindex */ /** * @typedef {Object} CatalogTree_Computed_Pools - * @property {MetricPattern25} pool + * @property {MetricPattern26} pool * @property {CatalogTree_Computed_Pools_Vecs} vecs */ @@ -4453,7 +4579,7 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Positions - * @property {MetricPattern16} position + * @property {MetricPattern17} position */ /** @@ -4465,14 +4591,14 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Price_Ohlc - * @property {MetricPattern9} ohlcInCents + * @property {MetricPattern10} ohlcInCents */ /** * @typedef {Object} CatalogTree_Computed_Price_Sats * @property {MetricPattern1} priceCloseInSats - * @property {MetricPattern1} priceHighInSats - * @property {MetricPattern1} priceLowInSats + * @property {PriceHighInSatsPattern} priceHighInSats + * @property {PriceLowInSatsPattern} priceLowInSats * @property {MetricPattern1} priceOhlcInSats * @property {MetricPattern1} priceOpenInSats */ @@ -4480,14 +4606,14 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Price_Usd * @property {MetricPattern1} priceClose - * @property {MetricPattern9} priceCloseInCents - * @property {MetricPattern1} priceHigh - * @property {MetricPattern9} priceHighInCents - * @property {MetricPattern1} priceLow - * @property {MetricPattern9} priceLowInCents + * @property {MetricPattern10} priceCloseInCents + * @property {PriceHighInSatsPattern} priceHigh + * @property {MetricPattern10} priceHighInCents + * @property {PriceLowInSatsPattern} priceLow + * @property {MetricPattern10} priceLowInCents * @property {MetricPattern1} priceOhlc * @property {MetricPattern1} priceOpen - * @property {MetricPattern9} priceOpenInCents + * @property {MetricPattern10} priceOpenInCents */ /** @@ -4498,43 +4624,26 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Scripts_Count - * @property {BitcoinPattern} emptyoutputCount - * @property {BitcoinPattern} opreturnCount - * @property {BitcoinPattern} p2aCount - * @property {BitcoinPattern} p2msCount - * @property {BitcoinPattern} p2pk33Count - * @property {BitcoinPattern} p2pk65Count - * @property {BitcoinPattern} p2pkhCount - * @property {BitcoinPattern} p2shCount - * @property {BitcoinPattern} p2trCount - * @property {BitcoinPattern} p2wpkhCount - * @property {BitcoinPattern} p2wshCount - * @property {SegwitAdoptionPattern} segwitAdoption - * @property {BitcoinPattern} segwitCount - * @property {SegwitAdoptionPattern} taprootAdoption - * @property {BitcoinPattern} unknownoutputCount + * @property {DollarsPattern} emptyoutputCount + * @property {DollarsPattern} opreturnCount + * @property {DollarsPattern} p2aCount + * @property {DollarsPattern} p2msCount + * @property {DollarsPattern} p2pk33Count + * @property {DollarsPattern} p2pk65Count + * @property {DollarsPattern} p2pkhCount + * @property {DollarsPattern} p2shCount + * @property {DollarsPattern} p2trCount + * @property {DollarsPattern} p2wpkhCount + * @property {DollarsPattern} p2wshCount + * @property {BlockCountPattern} segwitAdoption + * @property {DollarsPattern} segwitCount + * @property {BlockCountPattern} taprootAdoption + * @property {DollarsPattern} unknownoutputCount */ /** * @typedef {Object} CatalogTree_Computed_Scripts_Value - * @property {CatalogTree_Computed_Scripts_Value_OpreturnValue} opreturnValue - */ - -/** - * @typedef {Object} CatalogTree_Computed_Scripts_Value_OpreturnValue - * @property {MetricPattern25} base - * @property {SegwitAdoptionPattern} bitcoin - * @property {SegwitAdoptionPattern} dollars - * @property {CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats} sats - */ - -/** - * @typedef {Object} CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats - * @property {MetricPattern2} average - * @property {MetricPattern1} cumulative - * @property {MetricPattern2} max - * @property {MetricPattern2} min - * @property {MetricPattern2} sum + * @property {CoinbasePattern} opreturnValue */ /** @@ -4548,33 +4657,33 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Supply_Burned - * @property {OpreturnPattern} opreturn - * @property {OpreturnPattern} unspendable + * @property {UnclaimedRewardsPattern} opreturn + * @property {UnclaimedRewardsPattern} unspendable */ /** * @typedef {Object} CatalogTree_Computed_Supply_Circulating - * @property {MetricPattern25} btc + * @property {MetricPattern26} btc * @property {ActiveSupplyPattern} indexes - * @property {MetricPattern25} sats - * @property {MetricPattern25} usd + * @property {MetricPattern26} sats + * @property {MetricPattern26} usd */ /** * @typedef {Object} CatalogTree_Computed_Supply_Inflation - * @property {MetricPattern4} indexes + * @property {IndexesPattern2} indexes */ /** * @typedef {Object} CatalogTree_Computed_Supply_MarketCap - * @property {MetricPattern25} height - * @property {MetricPattern4} indexes + * @property {MetricPattern26} height + * @property {MetricPattern5} indexes */ /** * @typedef {Object} CatalogTree_Computed_Supply_Velocity - * @property {MetricPattern4} btc - * @property {MetricPattern4} usd + * @property {IndexesPattern2} btc + * @property {IndexesPattern2} usd */ /** @@ -4588,47 +4697,50 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Transactions_Count - * @property {MetricPattern38} isCoinbase - * @property {BitcoinPattern} txCount + * @property {MetricPattern39} isCoinbase + * @property {DollarsPattern} txCount */ /** * @typedef {Object} CatalogTree_Computed_Transactions_Fees * @property {CatalogTree_Computed_Transactions_Fees_Fee} fee * @property {CatalogTree_Computed_Transactions_Fees_FeeRate} feeRate - * @property {MetricPattern38} inputValue - * @property {MetricPattern38} outputValue + * @property {MetricPattern39} inputValue + * @property {MetricPattern39} outputValue */ /** * @typedef {Object} CatalogTree_Computed_Transactions_Fees_Fee - * @property {MetricPattern38} base - * @property {BlockSizePattern} bitcoin - * @property {MetricPattern38} bitcoinTxindex - * @property {BlockSizePattern} dollars - * @property {MetricPattern38} dollarsTxindex - * @property {BlockSizePattern} sats + * @property {MetricPattern39} base + * @property {CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin} bitcoin + * @property {CountPattern2} dollars + * @property {CountPattern2} sats + */ + +/** + * @typedef {Object} CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin + * @property {MetricPattern1} average + * @property {MetricPattern1} cumulative + * @property {MetricPattern1} max + * @property {MetricPattern1} min + * @property {MetricPattern1} sum */ /** * @typedef {Object} CatalogTree_Computed_Transactions_Fees_FeeRate * @property {MetricPattern1} average - * @property {MetricPattern38} base + * @property {MetricPattern39} base * @property {MetricPattern1} max - * @property {MetricPattern25} median * @property {MetricPattern1} min - * @property {MetricPattern25} pct10 - * @property {MetricPattern25} pct25 - * @property {MetricPattern25} pct75 - * @property {MetricPattern25} pct90 + * @property {PercentilesPattern} percentiles */ /** * @typedef {Object} CatalogTree_Computed_Transactions_Size * @property {BlockIntervalPattern} txVsize * @property {BlockIntervalPattern} txWeight - * @property {MetricPattern38} vsize - * @property {MetricPattern38} weight + * @property {MetricPattern39} vsize + * @property {MetricPattern39} weight */ /** @@ -4640,20 +4752,20 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Computed_Transactions_Volume - * @property {MetricPattern4} annualizedVolume - * @property {MetricPattern4} annualizedVolumeBtc - * @property {MetricPattern4} annualizedVolumeUsd - * @property {MetricPattern4} inputsPerSec - * @property {MetricPattern4} outputsPerSec + * @property {MetricPattern5} annualizedVolume + * @property {MetricPattern5} annualizedVolumeBtc + * @property {MetricPattern5} annualizedVolumeUsd + * @property {MetricPattern5} inputsPerSec + * @property {MetricPattern5} outputsPerSec * @property {CatalogTree_Computed_Transactions_Volume_SentSum} sentSum - * @property {MetricPattern4} txPerSec + * @property {MetricPattern5} txPerSec */ /** * @typedef {Object} CatalogTree_Computed_Transactions_Volume_SentSum - * @property {TotalRealizedPnlPattern} bitcoin - * @property {MetricPattern1} dollars - * @property {MetricPattern1} sats + * @property {MetricPattern1} bitcoin + * @property {DifficultyAdjustmentPattern} dollars + * @property {DifficultyAdjustmentPattern} sats */ /** @@ -4668,72 +4780,72 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} CatalogTree_Indexed_Address - * @property {MetricPattern25} firstP2aaddressindex - * @property {MetricPattern25} firstP2pk33addressindex - * @property {MetricPattern25} firstP2pk65addressindex - * @property {MetricPattern25} firstP2pkhaddressindex - * @property {MetricPattern25} firstP2shaddressindex - * @property {MetricPattern25} firstP2traddressindex - * @property {MetricPattern25} firstP2wpkhaddressindex - * @property {MetricPattern25} firstP2wshaddressindex - * @property {MetricPattern29} p2abytes - * @property {MetricPattern31} p2pk33bytes - * @property {MetricPattern32} p2pk65bytes - * @property {MetricPattern33} p2pkhbytes - * @property {MetricPattern34} p2shbytes - * @property {MetricPattern35} p2trbytes - * @property {MetricPattern36} p2wpkhbytes - * @property {MetricPattern37} p2wshbytes + * @property {MetricPattern26} firstP2aaddressindex + * @property {MetricPattern26} firstP2pk33addressindex + * @property {MetricPattern26} firstP2pk65addressindex + * @property {MetricPattern26} firstP2pkhaddressindex + * @property {MetricPattern26} firstP2shaddressindex + * @property {MetricPattern26} firstP2traddressindex + * @property {MetricPattern26} firstP2wpkhaddressindex + * @property {MetricPattern26} firstP2wshaddressindex + * @property {MetricPattern30} p2abytes + * @property {MetricPattern32} p2pk33bytes + * @property {MetricPattern33} p2pk65bytes + * @property {MetricPattern34} p2pkhbytes + * @property {MetricPattern35} p2shbytes + * @property {MetricPattern36} p2trbytes + * @property {MetricPattern37} p2wpkhbytes + * @property {MetricPattern38} p2wshbytes */ /** * @typedef {Object} CatalogTree_Indexed_Block - * @property {MetricPattern25} blockhash - * @property {MetricPattern25} difficulty - * @property {MetricPattern25} timestamp - * @property {MetricPattern25} totalSize - * @property {MetricPattern25} weight + * @property {MetricPattern26} blockhash + * @property {MetricPattern26} difficulty + * @property {MetricPattern26} timestamp + * @property {MetricPattern26} totalSize + * @property {MetricPattern26} weight */ /** * @typedef {Object} CatalogTree_Indexed_Output - * @property {MetricPattern25} firstEmptyoutputindex - * @property {MetricPattern25} firstOpreturnindex - * @property {MetricPattern25} firstP2msoutputindex - * @property {MetricPattern25} firstUnknownoutputindex - * @property {MetricPattern7} txindex + * @property {MetricPattern26} firstEmptyoutputindex + * @property {MetricPattern26} firstOpreturnindex + * @property {MetricPattern26} firstP2msoutputindex + * @property {MetricPattern26} firstUnknownoutputindex + * @property {MetricPattern8} txindex */ /** * @typedef {Object} CatalogTree_Indexed_Tx - * @property {MetricPattern38} baseSize - * @property {MetricPattern25} firstTxindex - * @property {MetricPattern38} firstTxinindex - * @property {MetricPattern38} firstTxoutindex - * @property {MetricPattern38} height - * @property {MetricPattern38} isExplicitlyRbf - * @property {MetricPattern38} rawlocktime - * @property {MetricPattern38} totalSize - * @property {MetricPattern38} txid - * @property {MetricPattern38} txversion + * @property {MetricPattern39} baseSize + * @property {MetricPattern26} firstTxindex + * @property {MetricPattern39} firstTxinindex + * @property {MetricPattern39} firstTxoutindex + * @property {MetricPattern39} height + * @property {MetricPattern39} isExplicitlyRbf + * @property {MetricPattern39} rawlocktime + * @property {MetricPattern39} totalSize + * @property {MetricPattern39} txid + * @property {MetricPattern39} txversion */ /** * @typedef {Object} CatalogTree_Indexed_Txin - * @property {MetricPattern25} firstTxinindex - * @property {MetricPattern26} outpoint - * @property {MetricPattern26} outputtype - * @property {MetricPattern26} txindex - * @property {MetricPattern26} typeindex + * @property {MetricPattern26} firstTxinindex + * @property {MetricPattern27} outpoint + * @property {MetricPattern27} outputtype + * @property {MetricPattern27} txindex + * @property {MetricPattern27} typeindex */ /** * @typedef {Object} CatalogTree_Indexed_Txout - * @property {MetricPattern25} firstTxoutindex - * @property {MetricPattern28} outputtype - * @property {MetricPattern28} txindex - * @property {MetricPattern28} typeindex - * @property {MetricPattern28} value + * @property {MetricPattern26} firstTxoutindex + * @property {MetricPattern29} outputtype + * @property {MetricPattern29} txindex + * @property {MetricPattern29} typeindex + * @property {MetricPattern29} value */ /** @@ -4741,7 +4853,7 @@ function createRealizedPriceExtraPattern(client, acc) { * @extends BrkClientBase */ class BrkClient extends BrkClientBase { - VERSION = "v0.1.0-alpha.1"; + VERSION = "v0.1.0-alpha.2"; INDEXES = /** @type {const} */ ([ "dateindex", @@ -5653,30 +5765,30 @@ class BrkClient extends BrkClientBase { computed: { blocks: { count: { - _1mBlockCount: createMetricPattern4(this, '1m_block_count'), - _1wBlockCount: createMetricPattern4(this, '1w_block_count'), - _1yBlockCount: createMetricPattern4(this, '1y_block_count'), - _24hBlockCount: createMetricPattern25(this, '24h_block_count'), + _1mBlockCount: createMetricPattern5(this, '1m_block_count'), + _1wBlockCount: createMetricPattern5(this, '1w_block_count'), + _1yBlockCount: createMetricPattern5(this, '1y_block_count'), + _24hBlockCount: createMetricPattern26(this, '24h_block_count'), blockCount: createBlockCountPattern(this, 'block_count'), - blockCountTarget: createMetricPattern4(this, 'block_count_target') + blockCountTarget: createMetricPattern5(this, 'block_count_target') }, difficulty: { blocksBeforeNextDifficultyAdjustment: createMetricPattern1(this, 'blocks_before_next_difficulty_adjustment'), daysBeforeNextDifficultyAdjustment: createMetricPattern1(this, 'days_before_next_difficulty_adjustment'), - difficultyepoch: createMetricPattern4(this, 'difficultyepoch') + difficultyepoch: createMetricPattern5(this, 'difficultyepoch') }, halving: { blocksBeforeNextHalving: createMetricPattern1(this, 'blocks_before_next_halving'), daysBeforeNextHalving: createMetricPattern1(this, 'days_before_next_halving'), - halvingepoch: createMetricPattern4(this, 'halvingepoch') + halvingepoch: createMetricPattern5(this, 'halvingepoch') }, interval: { blockInterval: createBlockIntervalPattern(this, 'block_interval'), - interval: createMetricPattern25(this, 'interval') + interval: createMetricPattern26(this, 'interval') }, mining: { difficulty: createMetricPattern2(this, 'difficulty'), - difficultyAdjustment: createMetricPattern1(this, 'difficulty_adjustment'), + difficultyAdjustment: createDifficultyAdjustmentPattern(this, 'difficulty_adjustment'), difficultyAsHash: createMetricPattern1(this, 'difficulty_as_hash'), hashPricePhs: createMetricPattern1(this, 'hash_price_phs'), hashPricePhsMin: createMetricPattern1(this, 'hash_price_phs_min'), @@ -5684,10 +5796,10 @@ class BrkClient extends BrkClientBase { hashPriceThs: createMetricPattern1(this, 'hash_price_ths'), hashPriceThsMin: createMetricPattern1(this, 'hash_price_ths_min'), hashRate: createMetricPattern1(this, 'hash_rate'), - hashRate1mSma: createMetricPattern4(this, 'hash_rate_1m_sma'), - hashRate1wSma: createMetricPattern4(this, 'hash_rate_1w_sma'), - hashRate1ySma: createMetricPattern4(this, 'hash_rate_1y_sma'), - hashRate2mSma: createMetricPattern4(this, 'hash_rate_2m_sma'), + hashRate1mSma: createMetricPattern5(this, 'hash_rate_1m_sma'), + hashRate1wSma: createMetricPattern5(this, 'hash_rate_1w_sma'), + hashRate1ySma: createMetricPattern5(this, 'hash_rate_1y_sma'), + hashRate2mSma: createMetricPattern5(this, 'hash_rate_2m_sma'), hashValuePhs: createMetricPattern1(this, 'hash_value_phs'), hashValuePhsMin: createMetricPattern1(this, 'hash_value_phs_min'), hashValueRebound: createMetricPattern1(this, 'hash_value_rebound'), @@ -5695,25 +5807,25 @@ class BrkClient extends BrkClientBase { hashValueThsMin: createMetricPattern1(this, 'hash_value_ths_min') }, rewards: { - _24hCoinbaseSum: createMetricPattern25(this, '24h_coinbase_sum'), - _24hCoinbaseUsdSum: createMetricPattern25(this, '24h_coinbase_usd_sum'), + _24hCoinbaseSum: createMetricPattern26(this, '24h_coinbase_sum'), + _24hCoinbaseUsdSum: createMetricPattern26(this, '24h_coinbase_usd_sum'), coinbase: createCoinbasePattern(this, 'coinbase'), - feeDominance: createMetricPattern21(this, 'fee_dominance'), + feeDominance: createMetricPattern22(this, 'fee_dominance'), subsidy: createCoinbasePattern(this, 'subsidy'), - subsidyDominance: createMetricPattern21(this, 'subsidy_dominance'), - subsidyUsd1ySma: createMetricPattern4(this, 'subsidy_usd_1y_sma'), + subsidyDominance: createMetricPattern22(this, 'subsidy_dominance'), + subsidyUsd1ySma: createMetricPattern5(this, 'subsidy_usd_1y_sma'), unclaimedRewards: createUnclaimedRewardsPattern(this, 'unclaimed_rewards') }, size: { blockSize: createBlockSizePattern(this, 'block_size'), blockVbytes: createBlockSizePattern(this, 'block_vbytes'), - vbytes: createMetricPattern25(this, 'vbytes') + vbytes: createMetricPattern26(this, 'vbytes') }, time: { - date: createMetricPattern25(this, 'date'), - dateFixed: createMetricPattern25(this, 'date_fixed'), + date: createMetricPattern26(this, 'date'), + dateFixed: createMetricPattern26(this, 'date_fixed'), timestamp: createMetricPattern2(this, 'timestamp'), - timestampFixed: createMetricPattern25(this, 'timestamp_fixed') + timestampFixed: createMetricPattern26(this, 'timestamp_fixed') }, weight: { blockFullness: createBitcoinPattern(this, 'block_fullness'), @@ -5729,9 +5841,9 @@ class BrkClient extends BrkClientBase { vaultedness: createMetricPattern1(this, 'vaultedness') }, adjusted: { - cointimeAdjInflationRate: createMetricPattern4(this, 'cointime_adj_inflation_rate'), - cointimeAdjTxBtcVelocity: createMetricPattern4(this, 'cointime_adj_tx_btc_velocity'), - cointimeAdjTxUsdVelocity: createMetricPattern4(this, 'cointime_adj_tx_usd_velocity') + cointimeAdjInflationRate: createMetricPattern5(this, 'cointime_adj_inflation_rate'), + cointimeAdjTxBtcVelocity: createMetricPattern5(this, 'cointime_adj_tx_btc_velocity'), + cointimeAdjTxUsdVelocity: createMetricPattern5(this, 'cointime_adj_tx_usd_velocity') }, cap: { activeCap: createMetricPattern1(this, 'active_cap'), @@ -5832,18 +5944,18 @@ class BrkClient extends BrkClientBase { } }, addressesData: { - empty: createMetricPattern41(this, 'emptyaddressdata'), - loaded: createMetricPattern40(this, 'loadedaddressdata') + empty: createMetricPattern42(this, 'emptyaddressdata'), + loaded: createMetricPattern41(this, 'loadedaddressdata') }, addresstypeToHeightToAddrCount: createAddresstypeToHeightToAddrCountPattern(this, 'addr_count'), addresstypeToHeightToEmptyAddrCount: createAddresstypeToHeightToAddrCountPattern(this, 'empty_addr_count'), addresstypeToIndexesToAddrCount: createAddresstypeToHeightToAddrCountPattern(this, 'addr_count'), addresstypeToIndexesToEmptyAddrCount: createAddresstypeToHeightToAddrCountPattern(this, 'empty_addr_count'), anyAddressIndexes: createAddresstypeToHeightToAddrCountPattern(this, 'anyaddressindex'), - chainState: createMetricPattern25(this, 'chain'), + chainState: createMetricPattern26(this, 'chain'), emptyAddrCount: createMetricPattern1(this, 'empty_addr_count'), - emptyaddressindex: createMetricPattern41(this, 'emptyaddressindex'), - loadedaddressindex: createMetricPattern40(this, 'loadedaddressindex'), + emptyaddressindex: createMetricPattern42(this, 'emptyaddressindex'), + loadedaddressindex: createMetricPattern41(this, 'loadedaddressindex'), utxoCohorts: { ageRange: { _10yTo12y: create_10yTo12yPattern(this, 'utxos_at_least_10y_up_to_12y_old'), @@ -5873,12 +5985,12 @@ class BrkClient extends BrkClientBase { costBasis: createCostBasisPattern2(this, ''), realized: createRealizedPattern3(this, ''), relative: { - negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern5(this, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl'), + negUnrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern3(this, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl'), netUnrealizedPnlRelToOwnTotalUnrealizedPnl: createMetricPattern3(this, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl'), - supplyInLossRelToOwnSupply: createMetricPattern5(this, 'supply_in_loss_rel_to_own_supply'), - supplyInProfitRelToOwnSupply: createMetricPattern5(this, 'supply_in_profit_rel_to_own_supply'), - unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern5(this, 'unrealized_loss_rel_to_own_total_unrealized_pnl'), - unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern5(this, 'unrealized_profit_rel_to_own_total_unrealized_pnl') + supplyInLossRelToOwnSupply: createMetricPattern3(this, 'supply_in_loss_rel_to_own_supply'), + supplyInProfitRelToOwnSupply: createMetricPattern3(this, 'supply_in_profit_rel_to_own_supply'), + unrealizedLossRelToOwnTotalUnrealizedPnl: createMetricPattern3(this, 'unrealized_loss_rel_to_own_total_unrealized_pnl'), + unrealizedProfitRelToOwnTotalUnrealizedPnl: createMetricPattern3(this, 'unrealized_profit_rel_to_own_total_unrealized_pnl') }, supply: createSupplyPattern3(this, ''), unrealized: createUnrealizedPattern(this, '') @@ -6032,74 +6144,75 @@ class BrkClient extends BrkClientBase { }, indexes: { address: { - emptyoutputindex: createMetricPattern24(this, 'emptyoutputindex'), - opreturnindex: createMetricPattern27(this, 'opreturnindex'), - p2aaddressindex: createMetricPattern29(this, 'p2aaddressindex'), - p2msoutputindex: createMetricPattern30(this, 'p2msoutputindex'), - p2pk33addressindex: createMetricPattern31(this, 'p2pk33addressindex'), - p2pk65addressindex: createMetricPattern32(this, 'p2pk65addressindex'), - p2pkhaddressindex: createMetricPattern33(this, 'p2pkhaddressindex'), - p2shaddressindex: createMetricPattern34(this, 'p2shaddressindex'), - p2traddressindex: createMetricPattern35(this, 'p2traddressindex'), - p2wpkhaddressindex: createMetricPattern36(this, 'p2wpkhaddressindex'), - p2wshaddressindex: createMetricPattern37(this, 'p2wshaddressindex'), - unknownoutputindex: createMetricPattern39(this, 'unknownoutputindex') + emptyoutputindex: createMetricPattern25(this, 'emptyoutputindex'), + opreturnindex: createMetricPattern28(this, 'opreturnindex'), + p2aaddressindex: createMetricPattern30(this, 'p2aaddressindex'), + p2msoutputindex: createMetricPattern31(this, 'p2msoutputindex'), + p2pk33addressindex: createMetricPattern32(this, 'p2pk33addressindex'), + p2pk65addressindex: createMetricPattern33(this, 'p2pk65addressindex'), + p2pkhaddressindex: createMetricPattern34(this, 'p2pkhaddressindex'), + p2shaddressindex: createMetricPattern35(this, 'p2shaddressindex'), + p2traddressindex: createMetricPattern36(this, 'p2traddressindex'), + p2wpkhaddressindex: createMetricPattern37(this, 'p2wpkhaddressindex'), + p2wshaddressindex: createMetricPattern38(this, 'p2wshaddressindex'), + unknownoutputindex: createMetricPattern40(this, 'unknownoutputindex') }, block: { - dateindex: createMetricPattern25(this, 'dateindex'), - difficultyepoch: createMetricPattern14(this, 'difficultyepoch'), - firstHeight: createMetricPattern13(this, 'first_height'), - halvingepoch: createMetricPattern15(this, 'halvingepoch'), - height: createMetricPattern25(this, 'height'), - heightCount: createMetricPattern23(this, 'height_count'), - txindexCount: createMetricPattern25(this, 'txindex_count') + dateindex: createMetricPattern26(this, 'dateindex'), + difficultyepoch: createMetricPattern15(this, 'difficultyepoch'), + firstHeight: createMetricPattern14(this, 'first_height'), + halvingepoch: createMetricPattern16(this, 'halvingepoch'), + height: createMetricPattern26(this, 'height'), + heightCount: createMetricPattern24(this, 'height_count'), + txindexCount: createMetricPattern26(this, 'txindex_count') }, time: { - date: createMetricPattern21(this, 'date'), - dateindex: createMetricPattern21(this, 'dateindex'), - dateindexCount: createMetricPattern19(this, 'dateindex_count'), - decadeindex: createMetricPattern12(this, 'decadeindex'), - firstDateindex: createMetricPattern19(this, 'first_dateindex'), - firstHeight: createMetricPattern21(this, 'first_height'), - firstMonthindex: createMetricPattern8(this, 'first_monthindex'), - firstYearindex: createMetricPattern22(this, 'first_yearindex'), - heightCount: createMetricPattern21(this, 'height_count'), - monthindex: createMetricPattern10(this, 'monthindex'), - monthindexCount: createMetricPattern8(this, 'monthindex_count'), - quarterindex: createMetricPattern17(this, 'quarterindex'), - semesterindex: createMetricPattern18(this, 'semesterindex'), - weekindex: createMetricPattern11(this, 'weekindex'), - yearindex: createMetricPattern20(this, 'yearindex'), - yearindexCount: createMetricPattern22(this, 'yearindex_count') + date: createMetricPattern22(this, 'date'), + dateindex: createMetricPattern22(this, 'dateindex'), + dateindexCount: createMetricPattern20(this, 'dateindex_count'), + decadeindex: createMetricPattern13(this, 'decadeindex'), + firstDateindex: createMetricPattern20(this, 'first_dateindex'), + firstHeight: createMetricPattern22(this, 'first_height'), + firstMonthindex: createMetricPattern9(this, 'first_monthindex'), + firstYearindex: createMetricPattern23(this, 'first_yearindex'), + heightCount: createMetricPattern22(this, 'height_count'), + monthindex: createMetricPattern11(this, 'monthindex'), + monthindexCount: createMetricPattern9(this, 'monthindex_count'), + quarterindex: createMetricPattern18(this, 'quarterindex'), + semesterindex: createMetricPattern19(this, 'semesterindex'), + weekindex: createMetricPattern12(this, 'weekindex'), + yearindex: createMetricPattern21(this, 'yearindex'), + yearindexCount: createMetricPattern23(this, 'yearindex_count') }, transaction: { - inputCount: createMetricPattern38(this, 'input_count'), - outputCount: createMetricPattern38(this, 'output_count'), - txindex: createMetricPattern38(this, 'txindex'), - txinindex: createMetricPattern26(this, 'txinindex'), - txoutindex: createMetricPattern28(this, 'txoutindex') + inputCount: createMetricPattern39(this, 'input_count'), + outputCount: createMetricPattern39(this, 'output_count'), + txindex: createMetricPattern39(this, 'txindex'), + txinindex: createMetricPattern27(this, 'txinindex'), + txoutindex: createMetricPattern29(this, 'txoutindex') } }, inputs: { count: { - count: createBlockSizePattern(this, 'input_count') + count: createCountPattern2(this, 'input_count') }, spent: { - txoutindex: createMetricPattern26(this, 'txoutindex'), - value: createMetricPattern26(this, 'value') + txoutindex: createMetricPattern27(this, 'txoutindex'), + value: createMetricPattern27(this, 'value') } }, market: { ath: { - daysSincePriceAth: createMetricPattern4(this, 'days_since_price_ath'), - maxDaysBetweenPriceAths: createMetricPattern4(this, 'max_days_between_price_aths'), - maxYearsBetweenPriceAths: createMetricPattern4(this, 'max_years_between_price_aths'), + daysSincePriceAth: createMetricPattern5(this, 'days_since_price_ath'), + maxDaysBetweenPriceAths: createMetricPattern5(this, 'max_days_between_price_aths'), + maxYearsBetweenPriceAths: createMetricPattern5(this, 'max_years_between_price_aths'), priceAth: createMetricPattern3(this, 'price_ath'), - priceDrawdown: createMetricPattern3(this, 'price_drawdown') + priceDrawdown: createMetricPattern3(this, 'price_drawdown'), + yearsSincePriceAth: createMetricPattern5(this, 'years_since_price_ath') }, dca: { - classAvgPrice: createClassAvgPricePattern(this, 'dca_class'), - classReturns: createClassAvgPricePattern(this, 'dca_class'), + classAveragePrice: createClassAveragePricePattern(this, 'dca_class'), + classReturns: createClassAveragePricePattern(this, 'dca_class'), classStack: { _2015: createActiveSupplyPattern(this, 'dca_class_2015_stack'), _2016: createActiveSupplyPattern(this, 'dca_class_2016_stack'), @@ -6113,32 +6226,32 @@ class BrkClient extends BrkClientBase { _2024: createActiveSupplyPattern(this, 'dca_class_2024_stack'), _2025: createActiveSupplyPattern(this, 'dca_class_2025_stack') }, - periodAvgPrice: createPeriodAvgPricePattern(this, 'dca_avg_price'), + periodAveragePrice: createPeriodAveragePricePattern(this, 'dca_average_price'), periodCagr: createPeriodCagrPattern(this, 'dca_cagr'), periodLumpSumStack: createPeriodLumpSumStackPattern(this, ''), - periodReturns: createPeriodAvgPricePattern(this, 'dca_returns'), + periodReturns: createPeriodAveragePricePattern(this, 'dca_returns'), periodStack: createPeriodLumpSumStackPattern(this, '') }, indicators: { - gini: createMetricPattern21(this, 'gini'), - macdHistogram: createMetricPattern21(this, 'macd_histogram'), - macdLine: createMetricPattern21(this, 'macd_line'), - macdSignal: createMetricPattern21(this, 'macd_signal'), - nvt: createMetricPattern21(this, 'nvt'), - piCycle: createMetricPattern21(this, 'pi_cycle'), - puellMultiple: createMetricPattern4(this, 'puell_multiple'), - rsi14d: createMetricPattern21(this, 'rsi_14d'), - rsi14dMax: createMetricPattern21(this, 'rsi_14d_max'), - rsi14dMin: createMetricPattern21(this, 'rsi_14d_min'), - rsiAvgGain14d: createMetricPattern21(this, 'rsi_avg_gain_14d'), - rsiAvgLoss14d: createMetricPattern21(this, 'rsi_avg_loss_14d'), - rsiGains: createMetricPattern21(this, 'rsi_gains'), - rsiLosses: createMetricPattern21(this, 'rsi_losses'), - stochD: createMetricPattern21(this, 'stoch_d'), - stochK: createMetricPattern21(this, 'stoch_k'), - stochRsi: createMetricPattern21(this, 'stoch_rsi'), - stochRsiD: createMetricPattern21(this, 'stoch_rsi_d'), - stochRsiK: createMetricPattern21(this, 'stoch_rsi_k') + gini: createMetricPattern22(this, 'gini'), + macdHistogram: createMetricPattern22(this, 'macd_histogram'), + macdLine: createMetricPattern22(this, 'macd_line'), + macdSignal: createMetricPattern22(this, 'macd_signal'), + nvt: createMetricPattern5(this, 'nvt'), + piCycle: createMetricPattern22(this, 'pi_cycle'), + puellMultiple: createMetricPattern5(this, 'puell_multiple'), + rsi14d: createMetricPattern22(this, 'rsi_14d'), + rsi14dMax: createMetricPattern22(this, 'rsi_14d_max'), + rsi14dMin: createMetricPattern22(this, 'rsi_14d_min'), + rsiAverageGain14d: createMetricPattern22(this, 'rsi_average_gain_14d'), + rsiAverageLoss14d: createMetricPattern22(this, 'rsi_average_loss_14d'), + rsiGains: createMetricPattern22(this, 'rsi_gains'), + rsiLosses: createMetricPattern22(this, 'rsi_losses'), + stochD: createMetricPattern22(this, 'stoch_d'), + stochK: createMetricPattern22(this, 'stoch_k'), + stochRsi: createMetricPattern22(this, 'stoch_rsi'), + stochRsiD: createMetricPattern22(this, 'stoch_rsi_d'), + stochRsiK: createMetricPattern22(this, 'stoch_rsi_k') }, lookback: { priceAgo: createPriceAgoPattern(this, 'price') @@ -6158,8 +6271,8 @@ class BrkClient extends BrkClientBase { price1ySma: createPrice111dSmaPattern(this, 'price_1y_sma'), price200dEma: createPrice111dSmaPattern(this, 'price_200d_ema'), price200dSma: createPrice111dSmaPattern(this, 'price_200d_sma'), - price200dSmaX08: createMetricPattern4(this, 'price_200d_sma_x0_8'), - price200dSmaX24: createMetricPattern4(this, 'price_200d_sma_x2_4'), + price200dSmaX08: createMetricPattern5(this, 'price_200d_sma_x0_8'), + price200dSmaX24: createMetricPattern5(this, 'price_200d_sma_x2_4'), price200wEma: createPrice111dSmaPattern(this, 'price_200w_ema'), price200wSma: createPrice111dSmaPattern(this, 'price_200w_sma'), price21dEma: createPrice111dSmaPattern(this, 'price_21d_ema'), @@ -6170,7 +6283,7 @@ class BrkClient extends BrkClientBase { price34dEma: createPrice111dSmaPattern(this, 'price_34d_ema'), price34dSma: createPrice111dSmaPattern(this, 'price_34d_sma'), price350dSma: createPrice111dSmaPattern(this, 'price_350d_sma'), - price350dSmaX2: createMetricPattern4(this, 'price_350d_sma_x2'), + price350dSmaX2: createMetricPattern5(this, 'price_350d_sma_x2'), price4yEma: createPrice111dSmaPattern(this, 'price_4y_ema'), price4ySma: createPrice111dSmaPattern(this, 'price_4y_sma'), price55dEma: createPrice111dSmaPattern(this, 'price_55d_ema'), @@ -6181,17 +6294,17 @@ class BrkClient extends BrkClientBase { price8dSma: createPrice111dSmaPattern(this, 'price_8d_sma') }, range: { - price1mMax: createMetricPattern4(this, 'price_1m_max'), - price1mMin: createMetricPattern4(this, 'price_1m_min'), - price1wMax: createMetricPattern4(this, 'price_1w_max'), - price1wMin: createMetricPattern4(this, 'price_1w_min'), - price1yMax: createMetricPattern4(this, 'price_1y_max'), - price1yMin: createMetricPattern4(this, 'price_1y_min'), - price2wChoppinessIndex: createMetricPattern4(this, 'price_2w_choppiness_index'), - price2wMax: createMetricPattern4(this, 'price_2w_max'), - price2wMin: createMetricPattern4(this, 'price_2w_min'), - priceTrueRange: createMetricPattern21(this, 'price_true_range'), - priceTrueRange2wSum: createMetricPattern21(this, 'price_true_range_2w_sum') + price1mMax: createMetricPattern5(this, 'price_1m_max'), + price1mMin: createMetricPattern5(this, 'price_1m_min'), + price1wMax: createMetricPattern5(this, 'price_1w_max'), + price1wMin: createMetricPattern5(this, 'price_1w_min'), + price1yMax: createMetricPattern5(this, 'price_1y_max'), + price1yMin: createMetricPattern5(this, 'price_1y_min'), + price2wChoppinessIndex: createMetricPattern5(this, 'price_2w_choppiness_index'), + price2wMax: createMetricPattern5(this, 'price_2w_max'), + price2wMin: createMetricPattern5(this, 'price_2w_min'), + priceTrueRange: createMetricPattern22(this, 'price_true_range'), + priceTrueRange2wSum: createMetricPattern22(this, 'price_true_range_2w_sum') }, returns: { _1dReturns1mSd: create_1dReturns1mSdPattern(this, '1d_returns_1m_sd'), @@ -6201,32 +6314,32 @@ class BrkClient extends BrkClientBase { downside1mSd: create_1dReturns1mSdPattern(this, 'downside_1m_sd'), downside1wSd: create_1dReturns1mSdPattern(this, 'downside_1w_sd'), downside1ySd: create_1dReturns1mSdPattern(this, 'downside_1y_sd'), - downsideReturns: createMetricPattern21(this, 'downside_returns'), + downsideReturns: createMetricPattern22(this, 'downside_returns'), priceReturns: createPriceAgoPattern(this, 'price_returns') }, volatility: { - price1mVolatility: createMetricPattern4(this, 'price_1m_volatility'), - price1wVolatility: createMetricPattern4(this, 'price_1w_volatility'), - price1yVolatility: createMetricPattern4(this, 'price_1y_volatility'), - sharpe1m: createMetricPattern21(this, 'sharpe_1m'), - sharpe1w: createMetricPattern21(this, 'sharpe_1w'), - sharpe1y: createMetricPattern21(this, 'sharpe_1y'), - sortino1m: createMetricPattern21(this, 'sortino_1m'), - sortino1w: createMetricPattern21(this, 'sortino_1w'), - sortino1y: createMetricPattern21(this, 'sortino_1y') + price1mVolatility: createMetricPattern5(this, 'price_1m_volatility'), + price1wVolatility: createMetricPattern5(this, 'price_1w_volatility'), + price1yVolatility: createMetricPattern5(this, 'price_1y_volatility'), + sharpe1m: createMetricPattern22(this, 'sharpe_1m'), + sharpe1w: createMetricPattern22(this, 'sharpe_1w'), + sharpe1y: createMetricPattern22(this, 'sharpe_1y'), + sortino1m: createMetricPattern22(this, 'sortino_1m'), + sortino1w: createMetricPattern22(this, 'sortino_1w'), + sortino1y: createMetricPattern22(this, 'sortino_1y') } }, outputs: { count: { - count: createBlockSizePattern(this, 'output_count'), - utxoCount: createBitcoinPattern(this, 'exact_utxo_count') + count: createCountPattern2(this, 'output_count'), + utxoCount: createDollarsPattern(this, 'exact_utxo_count') }, spent: { - txinindex: createMetricPattern28(this, 'txinindex') + txinindex: createMetricPattern29(this, 'txinindex') } }, pools: { - pool: createMetricPattern25(this, 'pool'), + pool: createMetricPattern26(this, 'pool'), vecs: { aXbt: createAXbtPattern(this, 'axbt'), aaoPool: createAXbtPattern(this, 'aaopool'), @@ -6389,120 +6502,109 @@ class BrkClient extends BrkClientBase { } }, positions: { - position: createMetricPattern16(this, 'position') + position: createMetricPattern17(this, 'position') }, price: { ohlc: { - ohlcInCents: createMetricPattern9(this, 'ohlc_in_cents') + ohlcInCents: createMetricPattern10(this, 'ohlc_in_cents') }, sats: { priceCloseInSats: createMetricPattern1(this, 'price_close_in_sats'), - priceHighInSats: createMetricPattern1(this, 'price_high_in_sats'), - priceLowInSats: createMetricPattern1(this, 'price_low_in_sats'), + priceHighInSats: createPriceHighInSatsPattern(this, 'price_high_in_sats'), + priceLowInSats: createPriceLowInSatsPattern(this, 'price_low_in_sats'), priceOhlcInSats: createMetricPattern1(this, 'price_ohlc_in_sats'), priceOpenInSats: createMetricPattern1(this, 'price_open_in_sats') }, usd: { priceClose: createMetricPattern1(this, 'price_close'), - priceCloseInCents: createMetricPattern9(this, 'price_close_in_cents'), - priceHigh: createMetricPattern1(this, 'price_high'), - priceHighInCents: createMetricPattern9(this, 'price_high_in_cents'), - priceLow: createMetricPattern1(this, 'price_low'), - priceLowInCents: createMetricPattern9(this, 'price_low_in_cents'), + priceCloseInCents: createMetricPattern10(this, 'price_close_in_cents'), + priceHigh: createPriceHighInSatsPattern(this, 'price_high'), + priceHighInCents: createMetricPattern10(this, 'price_high_in_cents'), + priceLow: createPriceLowInSatsPattern(this, 'price_low'), + priceLowInCents: createMetricPattern10(this, 'price_low_in_cents'), priceOhlc: createMetricPattern1(this, 'price_ohlc'), priceOpen: createMetricPattern1(this, 'price_open'), - priceOpenInCents: createMetricPattern9(this, 'price_open_in_cents') + priceOpenInCents: createMetricPattern10(this, 'price_open_in_cents') } }, scripts: { count: { - emptyoutputCount: createBitcoinPattern(this, 'emptyoutput_count'), - opreturnCount: createBitcoinPattern(this, 'opreturn_count'), - p2aCount: createBitcoinPattern(this, 'p2a_count'), - p2msCount: createBitcoinPattern(this, 'p2ms_count'), - p2pk33Count: createBitcoinPattern(this, 'p2pk33_count'), - p2pk65Count: createBitcoinPattern(this, 'p2pk65_count'), - p2pkhCount: createBitcoinPattern(this, 'p2pkh_count'), - p2shCount: createBitcoinPattern(this, 'p2sh_count'), - p2trCount: createBitcoinPattern(this, 'p2tr_count'), - p2wpkhCount: createBitcoinPattern(this, 'p2wpkh_count'), - p2wshCount: createBitcoinPattern(this, 'p2wsh_count'), - segwitAdoption: createSegwitAdoptionPattern(this, 'segwit_adoption'), - segwitCount: createBitcoinPattern(this, 'segwit_count'), - taprootAdoption: createSegwitAdoptionPattern(this, 'taproot_adoption'), - unknownoutputCount: createBitcoinPattern(this, 'unknownoutput_count') + emptyoutputCount: createDollarsPattern(this, 'emptyoutput_count'), + opreturnCount: createDollarsPattern(this, 'opreturn_count'), + p2aCount: createDollarsPattern(this, 'p2a_count'), + p2msCount: createDollarsPattern(this, 'p2ms_count'), + p2pk33Count: createDollarsPattern(this, 'p2pk33_count'), + p2pk65Count: createDollarsPattern(this, 'p2pk65_count'), + p2pkhCount: createDollarsPattern(this, 'p2pkh_count'), + p2shCount: createDollarsPattern(this, 'p2sh_count'), + p2trCount: createDollarsPattern(this, 'p2tr_count'), + p2wpkhCount: createDollarsPattern(this, 'p2wpkh_count'), + p2wshCount: createDollarsPattern(this, 'p2wsh_count'), + segwitAdoption: createBlockCountPattern(this, 'segwit_adoption'), + segwitCount: createDollarsPattern(this, 'segwit_count'), + taprootAdoption: createBlockCountPattern(this, 'taproot_adoption'), + unknownoutputCount: createDollarsPattern(this, 'unknownoutput_count') }, value: { - opreturnValue: { - base: createMetricPattern25(this, 'opreturn_value'), - bitcoin: createSegwitAdoptionPattern(this, 'opreturn_value_btc'), - dollars: createSegwitAdoptionPattern(this, 'opreturn_value_usd'), - sats: { - average: createMetricPattern2(this, 'opreturn_value_avg'), - cumulative: createMetricPattern1(this, 'opreturn_value_cumulative'), - max: createMetricPattern2(this, 'opreturn_value_max'), - min: createMetricPattern2(this, 'opreturn_value_min'), - sum: createMetricPattern2(this, 'opreturn_value_sum') - } - } + opreturnValue: createCoinbasePattern(this, 'opreturn_value') } }, supply: { burned: { - opreturn: createOpreturnPattern(this, 'opreturn_supply'), - unspendable: createOpreturnPattern(this, 'unspendable_supply') + opreturn: createUnclaimedRewardsPattern(this, 'opreturn_supply'), + unspendable: createUnclaimedRewardsPattern(this, 'unspendable_supply') }, circulating: { - btc: createMetricPattern25(this, 'circulating_btc'), + btc: createMetricPattern26(this, 'circulating_btc'), indexes: createActiveSupplyPattern(this, 'circulating'), - sats: createMetricPattern25(this, 'circulating_sats'), - usd: createMetricPattern25(this, 'circulating_usd') + sats: createMetricPattern26(this, 'circulating_sats'), + usd: createMetricPattern26(this, 'circulating_usd') }, inflation: { - indexes: createMetricPattern4(this, 'inflation_rate') + indexes: createIndexesPattern2(this, 'inflation_rate') }, marketCap: { - height: createMetricPattern25(this, 'market_cap'), - indexes: createMetricPattern4(this, 'market_cap') + height: createMetricPattern26(this, 'market_cap'), + indexes: createMetricPattern5(this, 'market_cap') }, velocity: { - btc: createMetricPattern4(this, 'btc_velocity'), - usd: createMetricPattern4(this, 'usd_velocity') + btc: createIndexesPattern2(this, 'btc_velocity'), + usd: createIndexesPattern2(this, 'usd_velocity') } }, transactions: { count: { - isCoinbase: createMetricPattern38(this, 'is_coinbase'), - txCount: createBitcoinPattern(this, 'tx_count') + isCoinbase: createMetricPattern39(this, 'is_coinbase'), + txCount: createDollarsPattern(this, 'tx_count') }, fees: { fee: { - base: createMetricPattern38(this, 'fee'), - bitcoin: createBlockSizePattern(this, 'fee_btc'), - bitcoinTxindex: createMetricPattern38(this, 'fee_btc'), - dollars: createBlockSizePattern(this, 'fee_usd'), - dollarsTxindex: createMetricPattern38(this, 'fee_usd'), - sats: createBlockSizePattern(this, 'fee') + base: createMetricPattern39(this, 'fee'), + bitcoin: { + average: createMetricPattern1(this, 'fee_btc_average'), + cumulative: createMetricPattern1(this, 'fee_btc_cum'), + max: createMetricPattern1(this, 'fee_btc_max'), + min: createMetricPattern1(this, 'fee_btc_min'), + sum: createMetricPattern1(this, 'fee_btc_sum') + }, + dollars: createCountPattern2(this, 'fee_usd'), + sats: createCountPattern2(this, 'fee') }, feeRate: { - average: createMetricPattern1(this, 'fee_rate_avg'), - base: createMetricPattern38(this, 'fee_rate'), + average: createMetricPattern1(this, 'fee_rate_average'), + base: createMetricPattern39(this, 'fee_rate'), max: createMetricPattern1(this, 'fee_rate_max'), - median: createMetricPattern25(this, 'fee_rate_median'), min: createMetricPattern1(this, 'fee_rate_min'), - pct10: createMetricPattern25(this, 'fee_rate_pct10'), - pct25: createMetricPattern25(this, 'fee_rate_pct25'), - pct75: createMetricPattern25(this, 'fee_rate_pct75'), - pct90: createMetricPattern25(this, 'fee_rate_pct90') + percentiles: createPercentilesPattern(this, 'fee_rate') }, - inputValue: createMetricPattern38(this, 'input_value'), - outputValue: createMetricPattern38(this, 'output_value') + inputValue: createMetricPattern39(this, 'input_value'), + outputValue: createMetricPattern39(this, 'output_value') }, size: { txVsize: createBlockIntervalPattern(this, 'tx_vsize'), txWeight: createBlockIntervalPattern(this, 'tx_weight'), - vsize: createMetricPattern38(this, 'vsize'), - weight: createMetricPattern38(this, 'weight') + vsize: createMetricPattern39(this, 'vsize'), + weight: createMetricPattern39(this, 'weight') }, versions: { txV1: createBlockCountPattern(this, 'tx_v1'), @@ -6510,78 +6612,78 @@ class BrkClient extends BrkClientBase { txV3: createBlockCountPattern(this, 'tx_v3') }, volume: { - annualizedVolume: createMetricPattern4(this, 'annualized_volume'), - annualizedVolumeBtc: createMetricPattern4(this, 'annualized_volume_btc'), - annualizedVolumeUsd: createMetricPattern4(this, 'annualized_volume_usd'), - inputsPerSec: createMetricPattern4(this, 'inputs_per_sec'), - outputsPerSec: createMetricPattern4(this, 'outputs_per_sec'), + annualizedVolume: createMetricPattern5(this, 'annualized_volume'), + annualizedVolumeBtc: createMetricPattern5(this, 'annualized_volume_btc'), + annualizedVolumeUsd: createMetricPattern5(this, 'annualized_volume_usd'), + inputsPerSec: createMetricPattern5(this, 'inputs_per_sec'), + outputsPerSec: createMetricPattern5(this, 'outputs_per_sec'), sentSum: { - bitcoin: createTotalRealizedPnlPattern(this, 'sent_sum_btc'), - dollars: createMetricPattern1(this, 'sent_sum_usd'), - sats: createMetricPattern1(this, 'sent_sum') + bitcoin: createMetricPattern1(this, 'sent_sum_btc'), + dollars: createDifficultyAdjustmentPattern(this, 'sent_sum_usd'), + sats: createDifficultyAdjustmentPattern(this, 'sent_sum') }, - txPerSec: createMetricPattern4(this, 'tx_per_sec') + txPerSec: createMetricPattern5(this, 'tx_per_sec') } } }, indexed: { address: { - firstP2aaddressindex: createMetricPattern25(this, 'first_p2aaddressindex'), - firstP2pk33addressindex: createMetricPattern25(this, 'first_p2pk33addressindex'), - firstP2pk65addressindex: createMetricPattern25(this, 'first_p2pk65addressindex'), - firstP2pkhaddressindex: createMetricPattern25(this, 'first_p2pkhaddressindex'), - firstP2shaddressindex: createMetricPattern25(this, 'first_p2shaddressindex'), - firstP2traddressindex: createMetricPattern25(this, 'first_p2traddressindex'), - firstP2wpkhaddressindex: createMetricPattern25(this, 'first_p2wpkhaddressindex'), - firstP2wshaddressindex: createMetricPattern25(this, 'first_p2wshaddressindex'), - p2abytes: createMetricPattern29(this, 'p2abytes'), - p2pk33bytes: createMetricPattern31(this, 'p2pk33bytes'), - p2pk65bytes: createMetricPattern32(this, 'p2pk65bytes'), - p2pkhbytes: createMetricPattern33(this, 'p2pkhbytes'), - p2shbytes: createMetricPattern34(this, 'p2shbytes'), - p2trbytes: createMetricPattern35(this, 'p2trbytes'), - p2wpkhbytes: createMetricPattern36(this, 'p2wpkhbytes'), - p2wshbytes: createMetricPattern37(this, 'p2wshbytes') + firstP2aaddressindex: createMetricPattern26(this, 'first_p2aaddressindex'), + firstP2pk33addressindex: createMetricPattern26(this, 'first_p2pk33addressindex'), + firstP2pk65addressindex: createMetricPattern26(this, 'first_p2pk65addressindex'), + firstP2pkhaddressindex: createMetricPattern26(this, 'first_p2pkhaddressindex'), + firstP2shaddressindex: createMetricPattern26(this, 'first_p2shaddressindex'), + firstP2traddressindex: createMetricPattern26(this, 'first_p2traddressindex'), + firstP2wpkhaddressindex: createMetricPattern26(this, 'first_p2wpkhaddressindex'), + firstP2wshaddressindex: createMetricPattern26(this, 'first_p2wshaddressindex'), + p2abytes: createMetricPattern30(this, 'p2abytes'), + p2pk33bytes: createMetricPattern32(this, 'p2pk33bytes'), + p2pk65bytes: createMetricPattern33(this, 'p2pk65bytes'), + p2pkhbytes: createMetricPattern34(this, 'p2pkhbytes'), + p2shbytes: createMetricPattern35(this, 'p2shbytes'), + p2trbytes: createMetricPattern36(this, 'p2trbytes'), + p2wpkhbytes: createMetricPattern37(this, 'p2wpkhbytes'), + p2wshbytes: createMetricPattern38(this, 'p2wshbytes') }, block: { - blockhash: createMetricPattern25(this, 'blockhash'), - difficulty: createMetricPattern25(this, 'difficulty'), - timestamp: createMetricPattern25(this, 'timestamp'), - totalSize: createMetricPattern25(this, 'total_size'), - weight: createMetricPattern25(this, 'weight') + blockhash: createMetricPattern26(this, 'blockhash'), + difficulty: createMetricPattern26(this, 'difficulty'), + timestamp: createMetricPattern26(this, 'timestamp'), + totalSize: createMetricPattern26(this, 'total_size'), + weight: createMetricPattern26(this, 'weight') }, output: { - firstEmptyoutputindex: createMetricPattern25(this, 'first_emptyoutputindex'), - firstOpreturnindex: createMetricPattern25(this, 'first_opreturnindex'), - firstP2msoutputindex: createMetricPattern25(this, 'first_p2msoutputindex'), - firstUnknownoutputindex: createMetricPattern25(this, 'first_unknownoutputindex'), - txindex: createMetricPattern7(this, 'txindex') + firstEmptyoutputindex: createMetricPattern26(this, 'first_emptyoutputindex'), + firstOpreturnindex: createMetricPattern26(this, 'first_opreturnindex'), + firstP2msoutputindex: createMetricPattern26(this, 'first_p2msoutputindex'), + firstUnknownoutputindex: createMetricPattern26(this, 'first_unknownoutputindex'), + txindex: createMetricPattern8(this, 'txindex') }, tx: { - baseSize: createMetricPattern38(this, 'base_size'), - firstTxindex: createMetricPattern25(this, 'first_txindex'), - firstTxinindex: createMetricPattern38(this, 'first_txinindex'), - firstTxoutindex: createMetricPattern38(this, 'first_txoutindex'), - height: createMetricPattern38(this, 'height'), - isExplicitlyRbf: createMetricPattern38(this, 'is_explicitly_rbf'), - rawlocktime: createMetricPattern38(this, 'rawlocktime'), - totalSize: createMetricPattern38(this, 'total_size'), - txid: createMetricPattern38(this, 'txid'), - txversion: createMetricPattern38(this, 'txversion') + baseSize: createMetricPattern39(this, 'base_size'), + firstTxindex: createMetricPattern26(this, 'first_txindex'), + firstTxinindex: createMetricPattern39(this, 'first_txinindex'), + firstTxoutindex: createMetricPattern39(this, 'first_txoutindex'), + height: createMetricPattern39(this, 'height'), + isExplicitlyRbf: createMetricPattern39(this, 'is_explicitly_rbf'), + rawlocktime: createMetricPattern39(this, 'rawlocktime'), + totalSize: createMetricPattern39(this, 'total_size'), + txid: createMetricPattern39(this, 'txid'), + txversion: createMetricPattern39(this, 'txversion') }, txin: { - firstTxinindex: createMetricPattern25(this, 'first_txinindex'), - outpoint: createMetricPattern26(this, 'outpoint'), - outputtype: createMetricPattern26(this, 'outputtype'), - txindex: createMetricPattern26(this, 'txindex'), - typeindex: createMetricPattern26(this, 'typeindex') + firstTxinindex: createMetricPattern26(this, 'first_txinindex'), + outpoint: createMetricPattern27(this, 'outpoint'), + outputtype: createMetricPattern27(this, 'outputtype'), + txindex: createMetricPattern27(this, 'txindex'), + typeindex: createMetricPattern27(this, 'typeindex') }, txout: { - firstTxoutindex: createMetricPattern25(this, 'first_txoutindex'), - outputtype: createMetricPattern28(this, 'outputtype'), - txindex: createMetricPattern28(this, 'txindex'), - typeindex: createMetricPattern28(this, 'typeindex'), - value: createMetricPattern28(this, 'value') + firstTxoutindex: createMetricPattern26(this, 'first_txoutindex'), + outputtype: createMetricPattern29(this, 'outputtype'), + txindex: createMetricPattern29(this, 'txindex'), + typeindex: createMetricPattern29(this, 'typeindex'), + value: createMetricPattern29(this, 'value') } } }; @@ -6777,7 +6879,7 @@ class BrkClient extends BrkClientBase { * @param {*=} [to] Exclusive ending index, if negative counts from end * @param {*=} [count] Number of values to return (ignored if `to` is set) * @param {Format=} [format] Format of the output - * @returns {Promise} + * @returns {Promise} */ async getMetricByIndex(metric, index, from, to, count, format) { const params = new URLSearchParams(); @@ -6798,7 +6900,7 @@ class BrkClient extends BrkClientBase { * @param {*=} [to] Exclusive ending index, if negative counts from end * @param {*=} [count] Number of values to return (ignored if `to` is set) * @param {Format=} [format] Format of the output - * @returns {Promise} + * @returns {Promise} */ async getMetricsBulk(metrics, index, from, to, count, format) { const params = new URLSearchParams(); @@ -7089,6 +7191,51 @@ class BrkClient extends BrkClientBase { return this.get(`/version`); } + + /** + * Merge multiple MetricPatterns into a single pattern. + * Throws if any two patterns have overlapping indexes. + * @template T + * @param {...MetricPattern} patterns - The patterns to merge + * @returns {MetricPattern} A new merged pattern + */ + mergeMetricPatterns(...patterns) { + if (patterns.length === 0) { + throw new BrkError('mergeMetricPatterns requires at least one pattern'); + } + if (patterns.length === 1) { + return patterns[0]; + } + + const seenIndexes = /** @type {Map} */ (new Map()); + const mergedBy = /** @type {Partial>>} */ ({}); + + for (const pattern of patterns) { + for (const index of pattern.indexes()) { + const existing = seenIndexes.get(index); + if (existing !== undefined) { + throw new BrkError(`Index '${index}' exists in both '${existing}' and '${pattern.name}'`); + } + seenIndexes.set(index, pattern.name); + Object.defineProperty(mergedBy, index, { + get() { return pattern.get(index); }, + enumerable: true, + configurable: true, + }); + } + } + + const allIndexes = /** @type {Index[]} */ ([...seenIndexes.keys()]); + const firstName = patterns[0].name; + + return { + name: firstName, + by: mergedBy, + indexes() { return allIndexes; }, + get(index) { return mergedBy[index]; }, + }; + } + } -export { BrkClient, BrkClientBase, BrkError }; +export { BrkClient, BrkError }; diff --git a/modules/brk-client/package.json b/modules/brk-client/package.json index 0ec7acec2..462ba3bbc 100644 --- a/modules/brk-client/package.json +++ b/modules/brk-client/package.json @@ -1,6 +1,6 @@ { "name": "@bitcoinresearchkit/client", - "version": "0.1.0-alpha.1", + "version": "0.1.0-alpha.2", "description": "BRK JavaScript client", "type": "module", "main": "index.js", diff --git a/modules/lean-qr/2.6.0/index.mjs b/modules/lean-qr/2.6.0/index.mjs index c83e283e3..163dd46b9 100644 --- a/modules/lean-qr/2.6.0/index.mjs +++ b/modules/lean-qr/2.6.0/index.mjs @@ -1 +1,2 @@ +// @ts-nocheck const t=[.2,3/8,5/9,2/3],o=(o,e)=>r=>{const n=4*o+r-4,s="*-04-39?2$%%$%%'$%''%'''%')(%'))%(++'(++'(+.'+-.',/3',33)-/5)-43).36)058*18<+37<+4:<,4:E,5C/8@F/:EH/8?s:1,c=e/f|0,i=e%f,l=f-i,a=n>8?c*t[r]+(o>5)&-2:s,_=c-a;return{t:l*_+i*_+i,o:[[l,_],[i,_+1]],i:a}},e={min:0,L:0,M:1,Q:2,H:3,max:3},r=t=>new Uint8Array(t),n=t=>{const o=new Error(`lean-qr error ${t}`);throw o.code=t,o},s=t=>"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".indexOf(t),f=t=>t.charCodeAt(0),c=(...t)=>(o,e)=>t.forEach(t=>t(o,e)),i=t=>o=>{o.eci!==t&&(o.push(7,4),o.push(t,8),o.eci=t)},l=t=>(o,e)=>{o.push(4,4),o.push(t.length,8+8*(e>9)),t.forEach(t=>o.push(t,8))},a=(t,o,e,r,n=(t,o)=>e(t.length,o),s=(r?o=>c(i(r),t(o)):t))=>(s.test=o,s.l=e,s.est=n,s.eci=r&&[r],s),_=a(t=>(o,e)=>{o.push(1,4),o.push(t.length,10+2*(e>26)+2*(e>9));let r=0;for(;r/[0-9]/.test(t),(t,o)=>14+2*(o>26)+2*(o>9)+10*t/3),u=a(t=>(o,e)=>{o.push(2,4),o.push(t.length,9+2*(e>26)+2*(e>9));let r=0;for(;rs(t)>=0,(t,o)=>13+2*(o>26)+2*(o>9)+5.5*t),d=a(t=>l([...t].map(f)),t=>f(t)<128,(t,o)=>12+8*(o>9)+8*t);d._=!0,d.u=!0;const p=a(d,t=>f(t)<256,d.l,3);p._=!0;const m=new TextEncoder,h=a(t=>l(m.encode(t)),()=>1,0,26,(t,o)=>12+8*(o>9)+8*m.encode(t).length);h._=!0;let w=()=>{const t=new Map,o=new TextDecoder("sjis"),e=r(2);for(let r=0;r<7973;++r)e[0]=r/192+129+64*(r>5951),e[1]=r%192+64,t.set(o.decode(e),r);return t.delete("\ufffd"),w=()=>t,t};const y=a(t=>(o,e)=>{o.push(8,4),o.push(t.length,8+2*(e>26)+2*(e>9));for(const e of t)o.push(w().get(e),13)},t=>w().has(t),(t,o)=>12+2*(o>26)+2*(o>9)+13*t);y._=!0;const g=[_,u,d,p,y,h],b={auto:(t,{modes:o=g}={})=>(e,r)=>{const s=o.map((o,e)=>{const n=new Map,s=(t,o)=>(n.has(t)||n.set(t,o(t,r)),n.get(t));return{m:o,h:1<s(e-t,o.l):(e,r)=>s(t.slice(e,r),o.est)}});let f=[{v:0}],c=0,i=0,l=-1;for(const o of[...t,""]){let t=0;if(o)for(const e of s)e.m.test(o)&&(t|=e.h);if(!o||t!==l){if(-1!==l){const t=new Set(f.map(t=>t.D)),o=[];for(const{m:e,C:r,S:n,h:a}of s)if(l&a){const s=n(c,i);for(const l of e.eci??t)if(!e.u||!l){let t;for(const o of f)if(o.D===l||e.eci){const f=o.m===e&&o.D===l,a=f?o.V:o,_=e._&&f?o.v+s-r:a.v+12*(a.D!==l)+(f?n(f?o.$:c,i):s);(!t||_o.vt(e,r))},multi:c,eci:i,bytes:l,numeric:_,alphaNumeric:u,ascii:d,iso8859_1:p,shift_jis:y,utf8:h},C=()=>({F:r(2956),I:0,push(t,o){for(let e=o,r=8-(7&this.I);e>0;e-=r,r=8)this.F[this.I>>3]|=t<>e,this.I+=e({size:t,K:e,get:(o,r)=>o>=0&&o1&(t^o),(t,o)=>1&o,t=>t%3,(t,o)=>(t+o)%3,(t,o)=>1&(t/3^o>>1),(t,o)=>(t&o&1)+t*o%3,(t,o)=>(t&o)+t*o%3&1,(t,o)=>(t^o)+t*o%3&1],E=r(511);for(let t=0,o=1;t<255;o=2*o^285*(o>127))E[E[o+255]=t++]=o;const M=t=>E[t%255],S=t=>E[t+255],v=(t,o)=>{const e=r(t.length+o.length-1);for(let r=0;r{const e=r(t.length+o.length-1);e.set(t,0);for(let r=0;r{const e=[[],[]];let n=0,s=0;for(const[r,f]of o.o)for(let c=0;c{let r=t<<=e;for(let t=134217728;t>>=1;)r&t&&(r^=o*(t>>e));return r|t},A=({size:t,K:o},e)=>{const r=(e,r,n,s)=>{for(;n-- >0;e+=t)o.fill(s,e,e+r)},n=(o,e,n)=>{for(let s=0;s++<3;n-=2)r(e*t+o-(n>>1)*(t+1),n,n,2|s)},s=2*((t-13)/(1+(e/7|0))/2+.75|0);if(e>1)for(let o=t-7;o>8;o-=s){for(let t=o;t>8;t-=s)n(o,t,5);o6)for(let r=$(e,7973,12),n=1;n<7;++n)for(let e=12;e-- >9;r>>=1)o[n*t-e]=2|1&r;r(7,2,9,2),r(t-8,8,9,2);for(let e=0;e{const e=[];for(let r=t-2,n=t,s=-1;r>=0;r-=2){for(5===r&&(r=4);n+=s,-1!==n&&n!==t;){const s=n*t+r;o[s+1]||e.push(s+1),o[s]||e.push(s)}s*=-1}return e},H=({K:t},o,e)=>o.forEach((o,r)=>t[o]=e[r>>3]>>(7&~r)&1),I=({size:t,K:o},e,r,n)=>{for(let r=0;r>=1)o[(e-(e<7))*t+8]=1&s,o[9*t-e]=1&s;for(let e=8;--e,s;s>>=1)o[8*t+e-(e<7)]=1&s,o[(t-e)*t+8]=1&s},K=({size:t,K:o},e=0,r=0)=>{for(let n=0;n>1|2098176)&(3047517^a-1),2049&i&&(e+=40),a!==f&&(l=0),f=a,e+=5===++l?3:l>5}if(n)for(let r=t+n,s=5*o[n-1]^o[n];r{r>3);if(8*f(e).t=e;--t){const o=f(t);if(8*o.t{const n=x(e.size,e.K);return I(n,o,c??r,t),n.s=K(n),n}).reduce((t,o)=>o.s(o,e)=>P(o,{modes:[...g,...t],...e});export{e as correction,P as generate,b as mode}; diff --git a/modules/lean-qr/2.6.1/index.mjs b/modules/lean-qr/2.6.1/index.mjs index c83e283e3..163dd46b9 100644 --- a/modules/lean-qr/2.6.1/index.mjs +++ b/modules/lean-qr/2.6.1/index.mjs @@ -1 +1,2 @@ +// @ts-nocheck const t=[.2,3/8,5/9,2/3],o=(o,e)=>r=>{const n=4*o+r-4,s="*-04-39?2$%%$%%'$%''%'''%')(%'))%(++'(++'(+.'+-.',/3',33)-/5)-43).36)058*18<+37<+4:<,4:E,5C/8@F/:EH/8?s:1,c=e/f|0,i=e%f,l=f-i,a=n>8?c*t[r]+(o>5)&-2:s,_=c-a;return{t:l*_+i*_+i,o:[[l,_],[i,_+1]],i:a}},e={min:0,L:0,M:1,Q:2,H:3,max:3},r=t=>new Uint8Array(t),n=t=>{const o=new Error(`lean-qr error ${t}`);throw o.code=t,o},s=t=>"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".indexOf(t),f=t=>t.charCodeAt(0),c=(...t)=>(o,e)=>t.forEach(t=>t(o,e)),i=t=>o=>{o.eci!==t&&(o.push(7,4),o.push(t,8),o.eci=t)},l=t=>(o,e)=>{o.push(4,4),o.push(t.length,8+8*(e>9)),t.forEach(t=>o.push(t,8))},a=(t,o,e,r,n=(t,o)=>e(t.length,o),s=(r?o=>c(i(r),t(o)):t))=>(s.test=o,s.l=e,s.est=n,s.eci=r&&[r],s),_=a(t=>(o,e)=>{o.push(1,4),o.push(t.length,10+2*(e>26)+2*(e>9));let r=0;for(;r/[0-9]/.test(t),(t,o)=>14+2*(o>26)+2*(o>9)+10*t/3),u=a(t=>(o,e)=>{o.push(2,4),o.push(t.length,9+2*(e>26)+2*(e>9));let r=0;for(;rs(t)>=0,(t,o)=>13+2*(o>26)+2*(o>9)+5.5*t),d=a(t=>l([...t].map(f)),t=>f(t)<128,(t,o)=>12+8*(o>9)+8*t);d._=!0,d.u=!0;const p=a(d,t=>f(t)<256,d.l,3);p._=!0;const m=new TextEncoder,h=a(t=>l(m.encode(t)),()=>1,0,26,(t,o)=>12+8*(o>9)+8*m.encode(t).length);h._=!0;let w=()=>{const t=new Map,o=new TextDecoder("sjis"),e=r(2);for(let r=0;r<7973;++r)e[0]=r/192+129+64*(r>5951),e[1]=r%192+64,t.set(o.decode(e),r);return t.delete("\ufffd"),w=()=>t,t};const y=a(t=>(o,e)=>{o.push(8,4),o.push(t.length,8+2*(e>26)+2*(e>9));for(const e of t)o.push(w().get(e),13)},t=>w().has(t),(t,o)=>12+2*(o>26)+2*(o>9)+13*t);y._=!0;const g=[_,u,d,p,y,h],b={auto:(t,{modes:o=g}={})=>(e,r)=>{const s=o.map((o,e)=>{const n=new Map,s=(t,o)=>(n.has(t)||n.set(t,o(t,r)),n.get(t));return{m:o,h:1<s(e-t,o.l):(e,r)=>s(t.slice(e,r),o.est)}});let f=[{v:0}],c=0,i=0,l=-1;for(const o of[...t,""]){let t=0;if(o)for(const e of s)e.m.test(o)&&(t|=e.h);if(!o||t!==l){if(-1!==l){const t=new Set(f.map(t=>t.D)),o=[];for(const{m:e,C:r,S:n,h:a}of s)if(l&a){const s=n(c,i);for(const l of e.eci??t)if(!e.u||!l){let t;for(const o of f)if(o.D===l||e.eci){const f=o.m===e&&o.D===l,a=f?o.V:o,_=e._&&f?o.v+s-r:a.v+12*(a.D!==l)+(f?n(f?o.$:c,i):s);(!t||_o.vt(e,r))},multi:c,eci:i,bytes:l,numeric:_,alphaNumeric:u,ascii:d,iso8859_1:p,shift_jis:y,utf8:h},C=()=>({F:r(2956),I:0,push(t,o){for(let e=o,r=8-(7&this.I);e>0;e-=r,r=8)this.F[this.I>>3]|=t<>e,this.I+=e({size:t,K:e,get:(o,r)=>o>=0&&o1&(t^o),(t,o)=>1&o,t=>t%3,(t,o)=>(t+o)%3,(t,o)=>1&(t/3^o>>1),(t,o)=>(t&o&1)+t*o%3,(t,o)=>(t&o)+t*o%3&1,(t,o)=>(t^o)+t*o%3&1],E=r(511);for(let t=0,o=1;t<255;o=2*o^285*(o>127))E[E[o+255]=t++]=o;const M=t=>E[t%255],S=t=>E[t+255],v=(t,o)=>{const e=r(t.length+o.length-1);for(let r=0;r{const e=r(t.length+o.length-1);e.set(t,0);for(let r=0;r{const e=[[],[]];let n=0,s=0;for(const[r,f]of o.o)for(let c=0;c{let r=t<<=e;for(let t=134217728;t>>=1;)r&t&&(r^=o*(t>>e));return r|t},A=({size:t,K:o},e)=>{const r=(e,r,n,s)=>{for(;n-- >0;e+=t)o.fill(s,e,e+r)},n=(o,e,n)=>{for(let s=0;s++<3;n-=2)r(e*t+o-(n>>1)*(t+1),n,n,2|s)},s=2*((t-13)/(1+(e/7|0))/2+.75|0);if(e>1)for(let o=t-7;o>8;o-=s){for(let t=o;t>8;t-=s)n(o,t,5);o6)for(let r=$(e,7973,12),n=1;n<7;++n)for(let e=12;e-- >9;r>>=1)o[n*t-e]=2|1&r;r(7,2,9,2),r(t-8,8,9,2);for(let e=0;e{const e=[];for(let r=t-2,n=t,s=-1;r>=0;r-=2){for(5===r&&(r=4);n+=s,-1!==n&&n!==t;){const s=n*t+r;o[s+1]||e.push(s+1),o[s]||e.push(s)}s*=-1}return e},H=({K:t},o,e)=>o.forEach((o,r)=>t[o]=e[r>>3]>>(7&~r)&1),I=({size:t,K:o},e,r,n)=>{for(let r=0;r>=1)o[(e-(e<7))*t+8]=1&s,o[9*t-e]=1&s;for(let e=8;--e,s;s>>=1)o[8*t+e-(e<7)]=1&s,o[(t-e)*t+8]=1&s},K=({size:t,K:o},e=0,r=0)=>{for(let n=0;n>1|2098176)&(3047517^a-1),2049&i&&(e+=40),a!==f&&(l=0),f=a,e+=5===++l?3:l>5}if(n)for(let r=t+n,s=5*o[n-1]^o[n];r{r>3);if(8*f(e).t=e;--t){const o=f(t);if(8*o.t{const n=x(e.size,e.K);return I(n,o,c??r,t),n.s=K(n),n}).reduce((t,o)=>o.s(o,e)=>P(o,{modes:[...g,...t],...e});export{e as correction,P as generate,b as mode}; diff --git a/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs b/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs index 7103bd55f..b594ef501 100644 --- a/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs +++ b/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Copyright (c) 2025, Leon Sorokin * All rights reserved. (MIT Licensed) diff --git a/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs b/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs index 4fdaeca2d..5b856fec9 100644 --- a/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs +++ b/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs @@ -1,3 +1,4 @@ +// @ts-nocheck /*! * @license * TradingView Lightweight Charts™ v5.0.9 diff --git a/modules/lightweight-charts/5.1.0/dist/lightweight-charts.standalone.production.mjs b/modules/lightweight-charts/5.1.0/dist/lightweight-charts.standalone.production.mjs index fad91e326..703ef408d 100644 --- a/modules/lightweight-charts/5.1.0/dist/lightweight-charts.standalone.production.mjs +++ b/modules/lightweight-charts/5.1.0/dist/lightweight-charts.standalone.production.mjs @@ -1,3 +1,4 @@ +// @ts-nocheck /*! * @license * TradingView Lightweight Charts™ v5.1.0 diff --git a/modules/solidjs-signals/0.6.3/dist/prod.js b/modules/solidjs-signals/0.6.3/dist/prod.js index cad891f7a..f84d128cc 100644 --- a/modules/solidjs-signals/0.6.3/dist/prod.js +++ b/modules/solidjs-signals/0.6.3/dist/prod.js @@ -1,3 +1,4 @@ +// @ts-nocheck // src/core/error.ts var NotReadyError = class extends Error { }; diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index af9fa3a0a..68e73280c 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -219,12 +219,6 @@ class MetricCount(TypedDict): lazy_endpoints: int stored_endpoints: int -class MetricData(TypedDict): - total: int - from_: int - to: int - data: List[Any] - class MetricParam(TypedDict): metric: Metric @@ -501,7 +495,19 @@ def _m(acc: str, s: str) -> str: return f"{acc}_{s}" if acc else s -class Endpoint(Generic[T]): +class MetricData(TypedDict, Generic[T]): + """Metric data with range information.""" + total: int + from_: int # 'from' is reserved in Python + to: int + data: List[T] + + +# Type alias for non-generic usage +AnyMetricData = MetricData[Any] + + +class MetricEndpoint(Generic[T]): """An endpoint for a specific metric + index combination.""" def __init__(self, client: BrkClientBase, name: str, index: str): @@ -509,11 +515,11 @@ class Endpoint(Generic[T]): self._name = name self._index = index - def get(self) -> List[T]: + def get(self) -> MetricData[T]: """Fetch all data points for this metric/index.""" return self._client.get(self.path()) - def range(self, from_val: Optional[int] = None, to_val: Optional[int] = None) -> List[T]: + def range(self, from_val: Optional[int] = None, to_val: Optional[int] = None) -> MetricData[T]: """Fetch data points within a range.""" params = [] if from_val is not None: @@ -529,6 +535,10 @@ class Endpoint(Generic[T]): return f"/api/metric/{self._name}/{self._index}" +# Type alias for non-generic usage +AnyMetricEndpoint = MetricEndpoint[Any] + + class MetricPattern(Protocol[T]): """Protocol for metric patterns with different index sets.""" @@ -541,7 +551,7 @@ class MetricPattern(Protocol[T]): """Get the list of available indexes for this metric.""" ... - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" ... @@ -555,32 +565,32 @@ class _MetricPattern1By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_difficultyepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'difficultyepoch') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern1(Generic[T]): """Index accessor for metrics with 9 indexes.""" @@ -599,7 +609,7 @@ class MetricPattern1(Generic[T]): """Get the list of available indexes.""" return ['dateindex', 'decadeindex', 'difficultyepoch', 'height', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'dateindex': return self.by.by_dateindex() elif index == 'decadeindex': return self.by.by_decadeindex() @@ -619,29 +629,29 @@ class _MetricPattern2By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_difficultyepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'difficultyepoch') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern2(Generic[T]): """Index accessor for metrics with 8 indexes.""" @@ -660,7 +670,7 @@ class MetricPattern2(Generic[T]): """Get the list of available indexes.""" return ['dateindex', 'decadeindex', 'difficultyepoch', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'dateindex': return self.by.by_dateindex() elif index == 'decadeindex': return self.by.by_decadeindex() @@ -679,29 +689,29 @@ class _MetricPattern3By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern3(Generic[T]): """Index accessor for metrics with 8 indexes.""" @@ -720,7 +730,7 @@ class MetricPattern3(Generic[T]): """Get the list of available indexes.""" return ['dateindex', 'decadeindex', 'height', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'dateindex': return self.by.by_dateindex() elif index == 'decadeindex': return self.by.by_decadeindex() @@ -739,29 +749,32 @@ class _MetricPattern4By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') + + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern4(Generic[T]): - """Index accessor for metrics with 7 indexes.""" + """Index accessor for metrics with 8 indexes.""" def __init__(self, client: BrkClientBase, name: str): self._client = client @@ -775,12 +788,13 @@ class MetricPattern4(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['dateindex', 'decadeindex', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] + return ['decadeindex', 'difficultyepoch', 'height', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'dateindex': return self.by.by_dateindex() - elif index == 'decadeindex': return self.by.by_decadeindex() + if index == 'decadeindex': return self.by.by_decadeindex() + elif index == 'difficultyepoch': return self.by.by_difficultyepoch() + elif index == 'height': return self.by.by_height() elif index == 'monthindex': return self.by.by_monthindex() elif index == 'quarterindex': return self.by.by_quarterindex() elif index == 'semesterindex': return self.by.by_semesterindex() @@ -795,26 +809,26 @@ class _MetricPattern5By(Generic[T]): self._client = client self._name = name - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern5(Generic[T]): """Index accessor for metrics with 7 indexes.""" @@ -831,12 +845,12 @@ class MetricPattern5(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['decadeindex', 'height', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] + return ['dateindex', 'decadeindex', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'decadeindex': return self.by.by_decadeindex() - elif index == 'height': return self.by.by_height() + if index == 'dateindex': return self.by.by_dateindex() + elif index == 'decadeindex': return self.by.by_decadeindex() elif index == 'monthindex': return self.by.by_monthindex() elif index == 'quarterindex': return self.by.by_quarterindex() elif index == 'semesterindex': return self.by.by_semesterindex() @@ -851,26 +865,29 @@ class _MetricPattern6By(Generic[T]): self._client = client self._name = name - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') + + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern6(Generic[T]): - """Index accessor for metrics with 6 indexes.""" + """Index accessor for metrics with 7 indexes.""" def __init__(self, client: BrkClientBase, name: str): self._client = client @@ -884,11 +901,12 @@ class MetricPattern6(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['decadeindex', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] + return ['decadeindex', 'difficultyepoch', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'decadeindex': return self.by.by_decadeindex() + elif index == 'difficultyepoch': return self.by.by_difficultyepoch() elif index == 'monthindex': return self.by.by_monthindex() elif index == 'quarterindex': return self.by.by_quarterindex() elif index == 'semesterindex': return self.by.by_semesterindex() @@ -903,20 +921,26 @@ class _MetricPattern7By(Generic[T]): self._client = client self._name = name - def by_emptyoutputindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'emptyoutputindex') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_opreturnindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'opreturnindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_p2msoutputindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2msoutputindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_unknownoutputindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'unknownoutputindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') + + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') + + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern7(Generic[T]): - """Index accessor for metrics with 4 indexes.""" + """Index accessor for metrics with 6 indexes.""" def __init__(self, client: BrkClientBase, name: str): self._client = client @@ -930,14 +954,16 @@ class MetricPattern7(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['emptyoutputindex', 'opreturnindex', 'p2msoutputindex', 'unknownoutputindex'] + return ['decadeindex', 'monthindex', 'quarterindex', 'semesterindex', 'weekindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'emptyoutputindex': return self.by.by_emptyoutputindex() - elif index == 'opreturnindex': return self.by.by_opreturnindex() - elif index == 'p2msoutputindex': return self.by.by_p2msoutputindex() - elif index == 'unknownoutputindex': return self.by.by_unknownoutputindex() + if index == 'decadeindex': return self.by.by_decadeindex() + elif index == 'monthindex': return self.by.by_monthindex() + elif index == 'quarterindex': return self.by.by_quarterindex() + elif index == 'semesterindex': return self.by.by_semesterindex() + elif index == 'weekindex': return self.by.by_weekindex() + elif index == 'yearindex': return self.by.by_yearindex() return None class _MetricPattern8By(Generic[T]): @@ -947,17 +973,20 @@ class _MetricPattern8By(Generic[T]): self._client = client self._name = name - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_emptyoutputindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'emptyoutputindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_opreturnindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'opreturnindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_p2msoutputindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2msoutputindex') + + def by_unknownoutputindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'unknownoutputindex') class MetricPattern8(Generic[T]): - """Index accessor for metrics with 3 indexes.""" + """Index accessor for metrics with 4 indexes.""" def __init__(self, client: BrkClientBase, name: str): self._client = client @@ -971,13 +1000,14 @@ class MetricPattern8(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['quarterindex', 'semesterindex', 'yearindex'] + return ['emptyoutputindex', 'opreturnindex', 'p2msoutputindex', 'unknownoutputindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'quarterindex': return self.by.by_quarterindex() - elif index == 'semesterindex': return self.by.by_semesterindex() - elif index == 'yearindex': return self.by.by_yearindex() + if index == 'emptyoutputindex': return self.by.by_emptyoutputindex() + elif index == 'opreturnindex': return self.by.by_opreturnindex() + elif index == 'p2msoutputindex': return self.by.by_p2msoutputindex() + elif index == 'unknownoutputindex': return self.by.by_unknownoutputindex() return None class _MetricPattern9By(Generic[T]): @@ -987,14 +1017,17 @@ class _MetricPattern9By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') + + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern9(Generic[T]): - """Index accessor for metrics with 2 indexes.""" + """Index accessor for metrics with 3 indexes.""" def __init__(self, client: BrkClientBase, name: str): self._client = client @@ -1008,12 +1041,13 @@ class MetricPattern9(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['dateindex', 'height'] + return ['quarterindex', 'semesterindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'dateindex': return self.by.by_dateindex() - elif index == 'height': return self.by.by_height() + if index == 'quarterindex': return self.by.by_quarterindex() + elif index == 'semesterindex': return self.by.by_semesterindex() + elif index == 'yearindex': return self.by.by_yearindex() return None class _MetricPattern10By(Generic[T]): @@ -1023,11 +1057,11 @@ class _MetricPattern10By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') class MetricPattern10(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1044,12 +1078,12 @@ class MetricPattern10(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['dateindex', 'monthindex'] + return ['dateindex', 'height'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'dateindex': return self.by.by_dateindex() - elif index == 'monthindex': return self.by.by_monthindex() + elif index == 'height': return self.by.by_height() return None class _MetricPattern11By(Generic[T]): @@ -1059,11 +1093,11 @@ class _MetricPattern11By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') class MetricPattern11(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1080,12 +1114,12 @@ class MetricPattern11(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['dateindex', 'weekindex'] + return ['dateindex', 'monthindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'dateindex': return self.by.by_dateindex() - elif index == 'weekindex': return self.by.by_weekindex() + elif index == 'monthindex': return self.by.by_monthindex() return None class _MetricPattern12By(Generic[T]): @@ -1095,11 +1129,11 @@ class _MetricPattern12By(Generic[T]): self._client = client self._name = name - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') class MetricPattern12(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1116,12 +1150,12 @@ class MetricPattern12(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['decadeindex', 'yearindex'] + return ['dateindex', 'weekindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'decadeindex': return self.by.by_decadeindex() - elif index == 'yearindex': return self.by.by_yearindex() + if index == 'dateindex': return self.by.by_dateindex() + elif index == 'weekindex': return self.by.by_weekindex() return None class _MetricPattern13By(Generic[T]): @@ -1131,11 +1165,11 @@ class _MetricPattern13By(Generic[T]): self._client = client self._name = name - def by_difficultyepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'difficultyepoch') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') - def by_halvingepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'halvingepoch') + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern13(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1152,12 +1186,12 @@ class MetricPattern13(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['difficultyepoch', 'halvingepoch'] + return ['decadeindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'difficultyepoch': return self.by.by_difficultyepoch() - elif index == 'halvingepoch': return self.by.by_halvingepoch() + if index == 'decadeindex': return self.by.by_decadeindex() + elif index == 'yearindex': return self.by.by_yearindex() return None class _MetricPattern14By(Generic[T]): @@ -1167,11 +1201,11 @@ class _MetricPattern14By(Generic[T]): self._client = client self._name = name - def by_difficultyepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'difficultyepoch') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_halvingepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'halvingepoch') class MetricPattern14(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1188,12 +1222,12 @@ class MetricPattern14(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['difficultyepoch', 'height'] + return ['difficultyepoch', 'halvingepoch'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'difficultyepoch': return self.by.by_difficultyepoch() - elif index == 'height': return self.by.by_height() + elif index == 'halvingepoch': return self.by.by_halvingepoch() return None class _MetricPattern15By(Generic[T]): @@ -1203,11 +1237,11 @@ class _MetricPattern15By(Generic[T]): self._client = client self._name = name - def by_halvingepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'halvingepoch') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') class MetricPattern15(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1224,11 +1258,11 @@ class MetricPattern15(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['halvingepoch', 'height'] + return ['difficultyepoch', 'height'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'halvingepoch': return self.by.by_halvingepoch() + if index == 'difficultyepoch': return self.by.by_difficultyepoch() elif index == 'height': return self.by.by_height() return None @@ -1239,11 +1273,11 @@ class _MetricPattern16By(Generic[T]): self._client = client self._name = name - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_halvingepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'halvingepoch') - def by_txindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'txindex') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') class MetricPattern16(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1260,12 +1294,12 @@ class MetricPattern16(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['height', 'txindex'] + return ['halvingepoch', 'height'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'height': return self.by.by_height() - elif index == 'txindex': return self.by.by_txindex() + if index == 'halvingepoch': return self.by.by_halvingepoch() + elif index == 'height': return self.by.by_height() return None class _MetricPattern17By(Generic[T]): @@ -1275,11 +1309,11 @@ class _MetricPattern17By(Generic[T]): self._client = client self._name = name - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') - def by_quarterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'quarterindex') + def by_txindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'txindex') class MetricPattern17(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1296,12 +1330,12 @@ class MetricPattern17(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['monthindex', 'quarterindex'] + return ['height', 'txindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'monthindex': return self.by.by_monthindex() - elif index == 'quarterindex': return self.by.by_quarterindex() + if index == 'height': return self.by.by_height() + elif index == 'txindex': return self.by.by_txindex() return None class _MetricPattern18By(Generic[T]): @@ -1311,11 +1345,11 @@ class _MetricPattern18By(Generic[T]): self._client = client self._name = name - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_semesterindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'semesterindex') + def by_quarterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'quarterindex') class MetricPattern18(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1332,12 +1366,12 @@ class MetricPattern18(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['monthindex', 'semesterindex'] + return ['monthindex', 'quarterindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'monthindex': return self.by.by_monthindex() - elif index == 'semesterindex': return self.by.by_semesterindex() + elif index == 'quarterindex': return self.by.by_quarterindex() return None class _MetricPattern19By(Generic[T]): @@ -1347,11 +1381,11 @@ class _MetricPattern19By(Generic[T]): self._client = client self._name = name - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_weekindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'weekindex') + def by_semesterindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'semesterindex') class MetricPattern19(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1368,12 +1402,12 @@ class MetricPattern19(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['monthindex', 'weekindex'] + return ['monthindex', 'semesterindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'monthindex': return self.by.by_monthindex() - elif index == 'weekindex': return self.by.by_weekindex() + elif index == 'semesterindex': return self.by.by_semesterindex() return None class _MetricPattern20By(Generic[T]): @@ -1383,11 +1417,11 @@ class _MetricPattern20By(Generic[T]): self._client = client self._name = name - def by_monthindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'monthindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') - def by_yearindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'yearindex') + def by_weekindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'weekindex') class MetricPattern20(Generic[T]): """Index accessor for metrics with 2 indexes.""" @@ -1404,12 +1438,12 @@ class MetricPattern20(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['monthindex', 'yearindex'] + return ['monthindex', 'weekindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'monthindex': return self.by.by_monthindex() - elif index == 'yearindex': return self.by.by_yearindex() + elif index == 'weekindex': return self.by.by_weekindex() return None class _MetricPattern21By(Generic[T]): @@ -1419,11 +1453,14 @@ class _MetricPattern21By(Generic[T]): self._client = client self._name = name - def by_dateindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'dateindex') + def by_monthindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'monthindex') + + def by_yearindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'yearindex') class MetricPattern21(Generic[T]): - """Index accessor for metrics with 1 indexes.""" + """Index accessor for metrics with 2 indexes.""" def __init__(self, client: BrkClientBase, name: str): self._client = client @@ -1437,11 +1474,12 @@ class MetricPattern21(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['dateindex'] + return ['monthindex', 'yearindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'dateindex': return self.by.by_dateindex() + if index == 'monthindex': return self.by.by_monthindex() + elif index == 'yearindex': return self.by.by_yearindex() return None class _MetricPattern22By(Generic[T]): @@ -1451,8 +1489,8 @@ class _MetricPattern22By(Generic[T]): self._client = client self._name = name - def by_decadeindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'decadeindex') + def by_dateindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'dateindex') class MetricPattern22(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1469,11 +1507,11 @@ class MetricPattern22(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['decadeindex'] + return ['dateindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'decadeindex': return self.by.by_decadeindex() + if index == 'dateindex': return self.by.by_dateindex() return None class _MetricPattern23By(Generic[T]): @@ -1483,8 +1521,8 @@ class _MetricPattern23By(Generic[T]): self._client = client self._name = name - def by_difficultyepoch(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'difficultyepoch') + def by_decadeindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'decadeindex') class MetricPattern23(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1501,11 +1539,11 @@ class MetricPattern23(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['difficultyepoch'] + return ['decadeindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'difficultyepoch': return self.by.by_difficultyepoch() + if index == 'decadeindex': return self.by.by_decadeindex() return None class _MetricPattern24By(Generic[T]): @@ -1515,8 +1553,8 @@ class _MetricPattern24By(Generic[T]): self._client = client self._name = name - def by_emptyoutputindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'emptyoutputindex') + def by_difficultyepoch(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'difficultyepoch') class MetricPattern24(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1533,11 +1571,11 @@ class MetricPattern24(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['emptyoutputindex'] + return ['difficultyepoch'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'emptyoutputindex': return self.by.by_emptyoutputindex() + if index == 'difficultyepoch': return self.by.by_difficultyepoch() return None class _MetricPattern25By(Generic[T]): @@ -1547,8 +1585,8 @@ class _MetricPattern25By(Generic[T]): self._client = client self._name = name - def by_height(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'height') + def by_emptyoutputindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'emptyoutputindex') class MetricPattern25(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1565,11 +1603,11 @@ class MetricPattern25(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['height'] + return ['emptyoutputindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'height': return self.by.by_height() + if index == 'emptyoutputindex': return self.by.by_emptyoutputindex() return None class _MetricPattern26By(Generic[T]): @@ -1579,8 +1617,8 @@ class _MetricPattern26By(Generic[T]): self._client = client self._name = name - def by_txinindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'txinindex') + def by_height(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'height') class MetricPattern26(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1597,11 +1635,11 @@ class MetricPattern26(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['txinindex'] + return ['height'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'txinindex': return self.by.by_txinindex() + if index == 'height': return self.by.by_height() return None class _MetricPattern27By(Generic[T]): @@ -1611,8 +1649,8 @@ class _MetricPattern27By(Generic[T]): self._client = client self._name = name - def by_opreturnindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'opreturnindex') + def by_txinindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'txinindex') class MetricPattern27(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1629,11 +1667,11 @@ class MetricPattern27(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['opreturnindex'] + return ['txinindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'opreturnindex': return self.by.by_opreturnindex() + if index == 'txinindex': return self.by.by_txinindex() return None class _MetricPattern28By(Generic[T]): @@ -1643,8 +1681,8 @@ class _MetricPattern28By(Generic[T]): self._client = client self._name = name - def by_txoutindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'txoutindex') + def by_opreturnindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'opreturnindex') class MetricPattern28(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1661,11 +1699,11 @@ class MetricPattern28(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['txoutindex'] + return ['opreturnindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'txoutindex': return self.by.by_txoutindex() + if index == 'opreturnindex': return self.by.by_opreturnindex() return None class _MetricPattern29By(Generic[T]): @@ -1675,8 +1713,8 @@ class _MetricPattern29By(Generic[T]): self._client = client self._name = name - def by_p2aaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2aaddressindex') + def by_txoutindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'txoutindex') class MetricPattern29(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1693,11 +1731,11 @@ class MetricPattern29(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2aaddressindex'] + return ['txoutindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2aaddressindex': return self.by.by_p2aaddressindex() + if index == 'txoutindex': return self.by.by_txoutindex() return None class _MetricPattern30By(Generic[T]): @@ -1707,8 +1745,8 @@ class _MetricPattern30By(Generic[T]): self._client = client self._name = name - def by_p2msoutputindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2msoutputindex') + def by_p2aaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2aaddressindex') class MetricPattern30(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1725,11 +1763,11 @@ class MetricPattern30(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2msoutputindex'] + return ['p2aaddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2msoutputindex': return self.by.by_p2msoutputindex() + if index == 'p2aaddressindex': return self.by.by_p2aaddressindex() return None class _MetricPattern31By(Generic[T]): @@ -1739,8 +1777,8 @@ class _MetricPattern31By(Generic[T]): self._client = client self._name = name - def by_p2pk33addressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2pk33addressindex') + def by_p2msoutputindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2msoutputindex') class MetricPattern31(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1757,11 +1795,11 @@ class MetricPattern31(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2pk33addressindex'] + return ['p2msoutputindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2pk33addressindex': return self.by.by_p2pk33addressindex() + if index == 'p2msoutputindex': return self.by.by_p2msoutputindex() return None class _MetricPattern32By(Generic[T]): @@ -1771,8 +1809,8 @@ class _MetricPattern32By(Generic[T]): self._client = client self._name = name - def by_p2pk65addressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2pk65addressindex') + def by_p2pk33addressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2pk33addressindex') class MetricPattern32(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1789,11 +1827,11 @@ class MetricPattern32(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2pk65addressindex'] + return ['p2pk33addressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2pk65addressindex': return self.by.by_p2pk65addressindex() + if index == 'p2pk33addressindex': return self.by.by_p2pk33addressindex() return None class _MetricPattern33By(Generic[T]): @@ -1803,8 +1841,8 @@ class _MetricPattern33By(Generic[T]): self._client = client self._name = name - def by_p2pkhaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2pkhaddressindex') + def by_p2pk65addressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2pk65addressindex') class MetricPattern33(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1821,11 +1859,11 @@ class MetricPattern33(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2pkhaddressindex'] + return ['p2pk65addressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2pkhaddressindex': return self.by.by_p2pkhaddressindex() + if index == 'p2pk65addressindex': return self.by.by_p2pk65addressindex() return None class _MetricPattern34By(Generic[T]): @@ -1835,8 +1873,8 @@ class _MetricPattern34By(Generic[T]): self._client = client self._name = name - def by_p2shaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2shaddressindex') + def by_p2pkhaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2pkhaddressindex') class MetricPattern34(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1853,11 +1891,11 @@ class MetricPattern34(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2shaddressindex'] + return ['p2pkhaddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2shaddressindex': return self.by.by_p2shaddressindex() + if index == 'p2pkhaddressindex': return self.by.by_p2pkhaddressindex() return None class _MetricPattern35By(Generic[T]): @@ -1867,8 +1905,8 @@ class _MetricPattern35By(Generic[T]): self._client = client self._name = name - def by_p2traddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2traddressindex') + def by_p2shaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2shaddressindex') class MetricPattern35(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1885,11 +1923,11 @@ class MetricPattern35(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2traddressindex'] + return ['p2shaddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2traddressindex': return self.by.by_p2traddressindex() + if index == 'p2shaddressindex': return self.by.by_p2shaddressindex() return None class _MetricPattern36By(Generic[T]): @@ -1899,8 +1937,8 @@ class _MetricPattern36By(Generic[T]): self._client = client self._name = name - def by_p2wpkhaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2wpkhaddressindex') + def by_p2traddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2traddressindex') class MetricPattern36(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1917,11 +1955,11 @@ class MetricPattern36(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2wpkhaddressindex'] + return ['p2traddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2wpkhaddressindex': return self.by.by_p2wpkhaddressindex() + if index == 'p2traddressindex': return self.by.by_p2traddressindex() return None class _MetricPattern37By(Generic[T]): @@ -1931,8 +1969,8 @@ class _MetricPattern37By(Generic[T]): self._client = client self._name = name - def by_p2wshaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'p2wshaddressindex') + def by_p2wpkhaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2wpkhaddressindex') class MetricPattern37(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1949,11 +1987,11 @@ class MetricPattern37(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['p2wshaddressindex'] + return ['p2wpkhaddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'p2wshaddressindex': return self.by.by_p2wshaddressindex() + if index == 'p2wpkhaddressindex': return self.by.by_p2wpkhaddressindex() return None class _MetricPattern38By(Generic[T]): @@ -1963,8 +2001,8 @@ class _MetricPattern38By(Generic[T]): self._client = client self._name = name - def by_txindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'txindex') + def by_p2wshaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'p2wshaddressindex') class MetricPattern38(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -1981,11 +2019,11 @@ class MetricPattern38(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['txindex'] + return ['p2wshaddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'txindex': return self.by.by_txindex() + if index == 'p2wshaddressindex': return self.by.by_p2wshaddressindex() return None class _MetricPattern39By(Generic[T]): @@ -1995,8 +2033,8 @@ class _MetricPattern39By(Generic[T]): self._client = client self._name = name - def by_unknownoutputindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'unknownoutputindex') + def by_txindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'txindex') class MetricPattern39(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -2013,11 +2051,11 @@ class MetricPattern39(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['unknownoutputindex'] + return ['txindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'unknownoutputindex': return self.by.by_unknownoutputindex() + if index == 'txindex': return self.by.by_txindex() return None class _MetricPattern40By(Generic[T]): @@ -2027,8 +2065,8 @@ class _MetricPattern40By(Generic[T]): self._client = client self._name = name - def by_loadedaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'loadedaddressindex') + def by_unknownoutputindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'unknownoutputindex') class MetricPattern40(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -2045,11 +2083,11 @@ class MetricPattern40(Generic[T]): def indexes(self) -> List[str]: """Get the list of available indexes.""" - return ['loadedaddressindex'] + return ['unknownoutputindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" - if index == 'loadedaddressindex': return self.by.by_loadedaddressindex() + if index == 'unknownoutputindex': return self.by.by_unknownoutputindex() return None class _MetricPattern41By(Generic[T]): @@ -2059,8 +2097,8 @@ class _MetricPattern41By(Generic[T]): self._client = client self._name = name - def by_emptyaddressindex(self) -> Endpoint[T]: - return Endpoint(self._client, self._name, 'emptyaddressindex') + def by_loadedaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'loadedaddressindex') class MetricPattern41(Generic[T]): """Index accessor for metrics with 1 indexes.""" @@ -2075,11 +2113,43 @@ class MetricPattern41(Generic[T]): """Get the metric name.""" return self._name + def indexes(self) -> List[str]: + """Get the list of available indexes.""" + return ['loadedaddressindex'] + + def get(self, index: str) -> Optional[MetricEndpoint[T]]: + """Get an endpoint for a specific index, if supported.""" + if index == 'loadedaddressindex': return self.by.by_loadedaddressindex() + return None + +class _MetricPattern42By(Generic[T]): + """Index endpoint methods container.""" + + def __init__(self, client: BrkClientBase, name: str): + self._client = client + self._name = name + + def by_emptyaddressindex(self) -> MetricEndpoint[T]: + return MetricEndpoint(self._client, self._name, 'emptyaddressindex') + +class MetricPattern42(Generic[T]): + """Index accessor for metrics with 1 indexes.""" + + def __init__(self, client: BrkClientBase, name: str): + self._client = client + self._name = name + self.by: _MetricPattern42By[T] = _MetricPattern42By(client, name) + + @property + def name(self) -> str: + """Get the metric name.""" + return self._name + def indexes(self) -> List[str]: """Get the list of available indexes.""" return ['emptyaddressindex'] - def get(self, index: str) -> Optional[Endpoint[T]]: + def get(self, index: str) -> Optional[MetricEndpoint[T]]: """Get an endpoint for a specific index, if supported.""" if index == 'emptyaddressindex': return self.by.by_emptyaddressindex() return None @@ -2091,272 +2161,280 @@ class RealizedPattern3: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.adjusted_sopr: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'adjusted_sopr')) - self.adjusted_sopr_30d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'adjusted_sopr_30d_ema')) - self.adjusted_sopr_7d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'adjusted_sopr_7d_ema')) - self.adjusted_value_created: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_created')) - self.adjusted_value_destroyed: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_destroyed')) - self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) + self.adjusted_sopr: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'adjusted_sopr')) + self.adjusted_sopr_30d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'adjusted_sopr_30d_ema')) + self.adjusted_sopr_7d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'adjusted_sopr_7d_ema')) + self.adjusted_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_created')) + self.adjusted_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed')) + self.mvrv: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'mvrv')) self.neg_realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'net_realized_pnl')) - self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) - self.net_realized_pnl_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.net_realized_pnl_cumulative_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) + self.net_realized_pnl_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap')) - self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) + self.realized_cap_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'realized_cap_30d_delta')) self.realized_cap_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) - self.realized_loss_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')) + self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) self.realized_price_extra: ActivePriceRatioPattern = ActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) - self.realized_profit_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')) - self.realized_profit_to_loss_ratio: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'realized_profit_to_loss_ratio')) - self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) - self.sell_side_risk_ratio: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio')) - self.sell_side_risk_ratio_30d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) - self.sell_side_risk_ratio_7d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) - self.sopr: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr')) - self.sopr_30d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_30d_ema')) - self.sopr_7d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_7d_ema')) - self.total_realized_pnl: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')) - self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) - self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) + self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) + self.realized_profit_to_loss_ratio: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'realized_profit_to_loss_ratio')) + self.realized_value: DifficultyAdjustmentPattern[Dollars] = DifficultyAdjustmentPattern(client, _m(acc, 'realized_value')) + self.sell_side_risk_ratio: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio')) + self.sell_side_risk_ratio_30d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) + self.sell_side_risk_ratio_7d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sopr: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr')) + self.sopr_30d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_30d_ema')) + self.sopr_7d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_7d_ema')) + self.total_realized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_realized_pnl')) + self.value_created: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_created')) + self.value_created_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_created_sum')) + self.value_destroyed: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_destroyed')) + self.value_destroyed_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_destroyed_sum')) class RealizedPattern4: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.adjusted_sopr: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'adjusted_sopr')) - self.adjusted_sopr_30d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'adjusted_sopr_30d_ema')) - self.adjusted_sopr_7d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'adjusted_sopr_7d_ema')) - self.adjusted_value_created: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_created')) - self.adjusted_value_destroyed: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'adjusted_value_destroyed')) - self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) + self.adjusted_sopr: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'adjusted_sopr')) + self.adjusted_sopr_30d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'adjusted_sopr_30d_ema')) + self.adjusted_sopr_7d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'adjusted_sopr_7d_ema')) + self.adjusted_value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_created')) + self.adjusted_value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed')) + self.mvrv: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'mvrv')) self.neg_realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'net_realized_pnl')) - self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) - self.net_realized_pnl_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.net_realized_pnl_cumulative_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) + self.net_realized_pnl_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap')) - self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) + self.realized_cap_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'realized_cap_30d_delta')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) - self.realized_loss_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')) + self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) self.realized_price_extra: RealizedPriceExtraPattern = RealizedPriceExtraPattern(client, _m(acc, 'realized_price')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) - self.realized_profit_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')) - self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) - self.sell_side_risk_ratio: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio')) - self.sell_side_risk_ratio_30d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) - self.sell_side_risk_ratio_7d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) - self.sopr: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr')) - self.sopr_30d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_30d_ema')) - self.sopr_7d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_7d_ema')) - self.total_realized_pnl: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')) - self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) - self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) - -class Ratio1ySdPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self._0sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, '0sd_usd')) - self.m0_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm0_5sd')) - self.m0_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm0_5sd_usd')) - self.m1_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm1_5sd')) - self.m1_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm1_5sd_usd')) - self.m1sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm1sd')) - self.m1sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm1sd_usd')) - self.m2_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm2_5sd')) - self.m2_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm2_5sd_usd')) - self.m2sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm2sd')) - self.m2sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm2sd_usd')) - self.m3sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm3sd')) - self.m3sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm3sd_usd')) - self.p0_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p0_5sd')) - self.p0_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p0_5sd_usd')) - self.p1_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p1_5sd')) - self.p1_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p1_5sd_usd')) - self.p1sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p1sd')) - self.p1sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p1sd_usd')) - self.p2_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p2_5sd')) - self.p2_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p2_5sd_usd')) - self.p2sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p2sd')) - self.p2sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p2sd_usd')) - self.p3sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p3sd')) - self.p3sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p3sd_usd')) - self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd')) - self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) - self.zscore: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'zscore')) + self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) + self.realized_value: DifficultyAdjustmentPattern[Dollars] = DifficultyAdjustmentPattern(client, _m(acc, 'realized_value')) + self.sell_side_risk_ratio: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio')) + self.sell_side_risk_ratio_30d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) + self.sell_side_risk_ratio_7d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sopr: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr')) + self.sopr_30d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_30d_ema')) + self.sopr_7d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_7d_ema')) + self.total_realized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_realized_pnl')) + self.value_created: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_created')) + self.value_created_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_created_sum')) + self.value_destroyed: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_destroyed')) + self.value_destroyed_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_destroyed_sum')) class RealizedPattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) + self.mvrv: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'mvrv')) self.neg_realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'net_realized_pnl')) - self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) - self.net_realized_pnl_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.net_realized_pnl_cumulative_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) + self.net_realized_pnl_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap')) - self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) + self.realized_cap_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'realized_cap_30d_delta')) self.realized_cap_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) - self.realized_loss_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')) + self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) self.realized_price_extra: ActivePriceRatioPattern = ActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) - self.realized_profit_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')) - self.realized_profit_to_loss_ratio: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'realized_profit_to_loss_ratio')) - self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) - self.sell_side_risk_ratio: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio')) - self.sell_side_risk_ratio_30d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) - self.sell_side_risk_ratio_7d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) - self.sopr: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr')) - self.sopr_30d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_30d_ema')) - self.sopr_7d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_7d_ema')) - self.total_realized_pnl: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')) - self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) - self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) + self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) + self.realized_profit_to_loss_ratio: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'realized_profit_to_loss_ratio')) + self.realized_value: DifficultyAdjustmentPattern[Dollars] = DifficultyAdjustmentPattern(client, _m(acc, 'realized_value')) + self.sell_side_risk_ratio: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio')) + self.sell_side_risk_ratio_30d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) + self.sell_side_risk_ratio_7d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sopr: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr')) + self.sopr_30d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_30d_ema')) + self.sopr_7d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_7d_ema')) + self.total_realized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_realized_pnl')) + self.value_created: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_created')) + self.value_created_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_created_sum')) + self.value_destroyed: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_destroyed')) + self.value_destroyed_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_destroyed_sum')) + +class Ratio1ySdPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self._0sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, '0sd_usd')) + self.m0_5sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'm0_5sd')) + self.m0_5sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'm0_5sd_usd')) + self.m1_5sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'm1_5sd')) + self.m1_5sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'm1_5sd_usd')) + self.m1sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'm1sd')) + self.m1sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'm1sd_usd')) + self.m2_5sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'm2_5sd')) + self.m2_5sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'm2_5sd_usd')) + self.m2sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'm2sd')) + self.m2sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'm2sd_usd')) + self.m3sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'm3sd')) + self.m3sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'm3sd_usd')) + self.p0_5sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'p0_5sd')) + self.p0_5sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'p0_5sd_usd')) + self.p1_5sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'p1_5sd')) + self.p1_5sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'p1_5sd_usd')) + self.p1sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'p1sd')) + self.p1sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'p1sd_usd')) + self.p2_5sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'p2_5sd')) + self.p2_5sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'p2_5sd_usd')) + self.p2sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'p2sd')) + self.p2sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'p2sd_usd')) + self.p3sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'p3sd')) + self.p3sd_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'p3sd_usd')) + self.sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'sd')) + self.sma: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'sma')) + self.zscore: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'zscore')) class RealizedPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.mvrv: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'mvrv')) + self.mvrv: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'mvrv')) self.neg_realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'neg_realized_loss')) self.net_realized_pnl: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'net_realized_pnl')) - self.net_realized_pnl_cumulative_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) - self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) - self.net_realized_pnl_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) + self.net_realized_pnl_cumulative_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_market_cap')) + self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap')) + self.net_realized_pnl_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap')) self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap')) - self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) + self.realized_cap_30d_delta: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'realized_cap_30d_delta')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) - self.realized_loss_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_loss_rel_to_realized_cap')) + self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) self.realized_price_extra: RealizedPriceExtraPattern = RealizedPriceExtraPattern(client, _m(acc, 'realized_price')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) - self.realized_profit_rel_to_realized_cap: MetricPattern25[StoredF32] = MetricPattern25(client, _m(acc, 'realized_profit_rel_to_realized_cap')) - self.realized_value: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_value')) - self.sell_side_risk_ratio: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio')) - self.sell_side_risk_ratio_30d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) - self.sell_side_risk_ratio_7d_ema: MetricPattern21[StoredF32] = MetricPattern21(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) - self.sopr: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr')) - self.sopr_30d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_30d_ema')) - self.sopr_7d_ema: MetricPattern21[StoredF64] = MetricPattern21(client, _m(acc, 'sopr_7d_ema')) - self.total_realized_pnl: TotalRealizedPnlPattern[Dollars] = TotalRealizedPnlPattern(client, _m(acc, 'total_realized_pnl')) - self.value_created: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_created')) - self.value_destroyed: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'value_destroyed')) + self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) + self.realized_value: DifficultyAdjustmentPattern[Dollars] = DifficultyAdjustmentPattern(client, _m(acc, 'realized_value')) + self.sell_side_risk_ratio: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio')) + self.sell_side_risk_ratio_30d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_30d_ema')) + self.sell_side_risk_ratio_7d_ema: MetricPattern22[StoredF32] = MetricPattern22(client, _m(acc, 'sell_side_risk_ratio_7d_ema')) + self.sopr: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr')) + self.sopr_30d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_30d_ema')) + self.sopr_7d_ema: MetricPattern22[StoredF64] = MetricPattern22(client, _m(acc, 'sopr_7d_ema')) + self.total_realized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_realized_pnl')) + self.value_created: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_created')) + self.value_created_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_created_sum')) + self.value_destroyed: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'value_destroyed')) + self.value_destroyed_sum: MetricPattern2[Dollars] = MetricPattern2(client, _m(acc, 'value_destroyed_sum')) class Price111dSmaPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.price: MetricPattern4[Dollars] = MetricPattern4(client, acc) - self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio')) - self.ratio_1m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_1m_sma')) - self.ratio_1w_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_1w_sma')) + self.price: MetricPattern5[Dollars] = MetricPattern5(client, acc) + self.ratio: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio')) + self.ratio_1m_sma: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_1m_sma')) + self.ratio_1w_sma: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_1w_sma')) self.ratio_1y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio_1y')) self.ratio_2y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio_2y')) self.ratio_4y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio_4y')) - self.ratio_pct1: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct1')) - self.ratio_pct1_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct1_usd')) - self.ratio_pct2: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct2')) - self.ratio_pct2_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct2_usd')) - self.ratio_pct5: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct5')) - self.ratio_pct5_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct5_usd')) - self.ratio_pct95: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct95')) - self.ratio_pct95_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct95_usd')) - self.ratio_pct98: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct98')) - self.ratio_pct98_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct98_usd')) - self.ratio_pct99: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct99')) - self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct99_usd')) + self.ratio_pct1: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_pct1')) + self.ratio_pct1_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'ratio_pct1_usd')) + self.ratio_pct2: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_pct2')) + self.ratio_pct2_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'ratio_pct2_usd')) + self.ratio_pct5: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_pct5')) + self.ratio_pct5_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'ratio_pct5_usd')) + self.ratio_pct95: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_pct95')) + self.ratio_pct95_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'ratio_pct95_usd')) + self.ratio_pct98: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_pct98')) + self.ratio_pct98_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'ratio_pct98_usd')) + self.ratio_pct99: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio_pct99')) + self.ratio_pct99_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'ratio_pct99_usd')) self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio')) +class PercentilesPattern2: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.cost_basis_pct05: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct05')) + self.cost_basis_pct10: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct10')) + self.cost_basis_pct15: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct15')) + self.cost_basis_pct20: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct20')) + self.cost_basis_pct25: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct25')) + self.cost_basis_pct30: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct30')) + self.cost_basis_pct35: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct35')) + self.cost_basis_pct40: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct40')) + self.cost_basis_pct45: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct45')) + self.cost_basis_pct50: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct50')) + self.cost_basis_pct55: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct55')) + self.cost_basis_pct60: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct60')) + self.cost_basis_pct65: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct65')) + self.cost_basis_pct70: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct70')) + self.cost_basis_pct75: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct75')) + self.cost_basis_pct80: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct80')) + self.cost_basis_pct85: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct85')) + self.cost_basis_pct90: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct90')) + self.cost_basis_pct95: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct95')) + class ActivePriceRatioPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, acc) - self.ratio_1m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1m_sma')) - self.ratio_1w_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1w_sma')) + self.ratio: MetricPattern5[StoredF32] = MetricPattern5(client, acc) + self.ratio_1m_sma: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, '1m_sma')) + self.ratio_1w_sma: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, '1w_sma')) self.ratio_1y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '1y')) self.ratio_2y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '2y')) self.ratio_4y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '4y')) - self.ratio_pct1: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct1')) - self.ratio_pct1_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct1_usd')) - self.ratio_pct2: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct2')) - self.ratio_pct2_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct2_usd')) - self.ratio_pct5: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct5')) - self.ratio_pct5_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct5_usd')) - self.ratio_pct95: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct95')) - self.ratio_pct95_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95_usd')) - self.ratio_pct98: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct98')) - self.ratio_pct98_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct98_usd')) - self.ratio_pct99: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct99')) - self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct99_usd')) + self.ratio_pct1: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'pct1')) + self.ratio_pct1_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct1_usd')) + self.ratio_pct2: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'pct2')) + self.ratio_pct2_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct2_usd')) + self.ratio_pct5: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'pct5')) + self.ratio_pct5_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct5_usd')) + self.ratio_pct95: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'pct95')) + self.ratio_pct95_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct95_usd')) + self.ratio_pct98: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'pct98')) + self.ratio_pct98_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct98_usd')) + self.ratio_pct99: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'pct99')) + self.ratio_pct99_usd: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'pct99_usd')) self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, acc) -class PercentilesPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.cost_basis_pct05: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct05')) - self.cost_basis_pct10: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct10')) - self.cost_basis_pct15: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct15')) - self.cost_basis_pct20: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct20')) - self.cost_basis_pct25: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct25')) - self.cost_basis_pct30: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct30')) - self.cost_basis_pct35: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct35')) - self.cost_basis_pct40: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct40')) - self.cost_basis_pct45: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct45')) - self.cost_basis_pct50: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct50')) - self.cost_basis_pct55: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct55')) - self.cost_basis_pct60: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct60')) - self.cost_basis_pct65: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct65')) - self.cost_basis_pct70: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct70')) - self.cost_basis_pct75: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct75')) - self.cost_basis_pct80: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct80')) - self.cost_basis_pct85: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct85')) - self.cost_basis_pct90: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct90')) - self.cost_basis_pct95: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95')) - class RelativePattern5: """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_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')) - self.neg_unrealized_loss_rel_to_own_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')) - self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.neg_unrealized_loss_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')) + self.neg_unrealized_loss_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')) + self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')) self.net_unrealized_pnl_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')) self.net_unrealized_pnl_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')) self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')) - self.nupl: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'nupl')) - self.supply_in_loss_rel_to_circulating_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')) - self.supply_in_loss_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) - self.supply_in_profit_rel_to_circulating_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')) - self.supply_in_profit_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) - self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')) - self.unrealized_loss_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) - self.unrealized_loss_rel_to_own_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) - self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) - self.unrealized_profit_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) - self.unrealized_profit_rel_to_own_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) - self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) + self.nupl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'nupl')) + self.supply_in_loss_rel_to_circulating_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')) + self.supply_in_loss_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_circulating_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) + self.supply_rel_to_circulating_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_rel_to_circulating_supply')) + self.unrealized_loss_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) + self.unrealized_loss_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) + self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.unrealized_profit_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) + self.unrealized_profit_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) + self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) class AXbtPattern: """Pattern struct for repeated tree structure.""" @@ -2364,37 +2442,37 @@ class AXbtPattern: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" self._1d_dominance: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, '1d_dominance')) - self._1m_blocks_mined: MetricPattern4[StoredU32] = MetricPattern4(client, _m(acc, '1m_blocks_mined')) - self._1m_dominance: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1m_dominance')) - self._1w_blocks_mined: MetricPattern4[StoredU32] = MetricPattern4(client, _m(acc, '1w_blocks_mined')) - self._1w_dominance: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1w_dominance')) - self._1y_blocks_mined: MetricPattern4[StoredU32] = MetricPattern4(client, _m(acc, '1y_blocks_mined')) - self._1y_dominance: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1y_dominance')) + self._1m_blocks_mined: MetricPattern5[StoredU32] = MetricPattern5(client, _m(acc, '1m_blocks_mined')) + self._1m_dominance: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, '1m_dominance')) + self._1w_blocks_mined: MetricPattern5[StoredU32] = MetricPattern5(client, _m(acc, '1w_blocks_mined')) + self._1w_dominance: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, '1w_dominance')) + self._1y_blocks_mined: MetricPattern5[StoredU32] = MetricPattern5(client, _m(acc, '1y_blocks_mined')) + self._1y_dominance: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, '1y_dominance')) self.blocks_mined: BlockCountPattern[StoredU32] = BlockCountPattern(client, _m(acc, 'blocks_mined')) self.coinbase: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'coinbase')) - self.days_since_block: MetricPattern4[StoredU16] = MetricPattern4(client, _m(acc, 'days_since_block')) + self.days_since_block: MetricPattern5[StoredU16] = MetricPattern5(client, _m(acc, 'days_since_block')) self.dominance: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'dominance')) - self.fee: SentPattern = SentPattern(client, _m(acc, 'fee')) - self.subsidy: SentPattern = SentPattern(client, _m(acc, 'subsidy')) + self.fee: SentPattern = SentPattern(client, acc) + self.subsidy: SentPattern = SentPattern(client, acc) class PriceAgoPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self._10y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '10y_ago')) - self._1d: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1d_ago')) - self._1m: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1m_ago')) - self._1w: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1w_ago')) - self._1y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1y_ago')) - self._2y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2y_ago')) - self._3m: MetricPattern4[T] = MetricPattern4(client, _m(acc, '3m_ago')) - self._3y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '3y_ago')) - self._4y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '4y_ago')) - self._5y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '5y_ago')) - self._6m: MetricPattern4[T] = MetricPattern4(client, _m(acc, '6m_ago')) - self._6y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '6y_ago')) - self._8y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '8y_ago')) + self._10y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '10y_ago')) + self._1d: MetricPattern5[T] = MetricPattern5(client, _m(acc, '1d_ago')) + self._1m: MetricPattern5[T] = MetricPattern5(client, _m(acc, '1m_ago')) + self._1w: MetricPattern5[T] = MetricPattern5(client, _m(acc, '1w_ago')) + self._1y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '1y_ago')) + self._2y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2y_ago')) + self._3m: MetricPattern5[T] = MetricPattern5(client, _m(acc, '3m_ago')) + self._3y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '3y_ago')) + self._4y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '4y_ago')) + self._5y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '5y_ago')) + self._6m: MetricPattern5[T] = MetricPattern5(client, _m(acc, '6m_ago')) + self._6y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '6y_ago')) + self._8y: MetricPattern5[T] = MetricPattern5(client, _m(acc, '8y_ago')) class PeriodLumpSumStackPattern: """Pattern struct for repeated tree structure.""" @@ -2414,105 +2492,72 @@ class PeriodLumpSumStackPattern: self._6y: ActiveSupplyPattern = ActiveSupplyPattern(client, (f'6y_{{acc}}' if acc else '6y')) self._8y: ActiveSupplyPattern = ActiveSupplyPattern(client, (f'8y_{{acc}}' if acc else '8y')) -class PeriodAvgPricePattern(Generic[T]): +class PeriodAveragePricePattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self._10y: MetricPattern4[T] = MetricPattern4(client, (f'10y_{{acc}}' if acc else '10y')) - self._1m: MetricPattern4[T] = MetricPattern4(client, (f'1m_{{acc}}' if acc else '1m')) - self._1w: MetricPattern4[T] = MetricPattern4(client, (f'1w_{{acc}}' if acc else '1w')) - self._1y: MetricPattern4[T] = MetricPattern4(client, (f'1y_{{acc}}' if acc else '1y')) - self._2y: MetricPattern4[T] = MetricPattern4(client, (f'2y_{{acc}}' if acc else '2y')) - self._3m: MetricPattern4[T] = MetricPattern4(client, (f'3m_{{acc}}' if acc else '3m')) - self._3y: MetricPattern4[T] = MetricPattern4(client, (f'3y_{{acc}}' if acc else '3y')) - self._4y: MetricPattern4[T] = MetricPattern4(client, (f'4y_{{acc}}' if acc else '4y')) - self._5y: MetricPattern4[T] = MetricPattern4(client, (f'5y_{{acc}}' if acc else '5y')) - self._6m: MetricPattern4[T] = MetricPattern4(client, (f'6m_{{acc}}' if acc else '6m')) - self._6y: MetricPattern4[T] = MetricPattern4(client, (f'6y_{{acc}}' if acc else '6y')) - self._8y: MetricPattern4[T] = MetricPattern4(client, (f'8y_{{acc}}' if acc else '8y')) + self._10y: MetricPattern5[T] = MetricPattern5(client, (f'10y_{{acc}}' if acc else '10y')) + self._1m: MetricPattern5[T] = MetricPattern5(client, (f'1m_{{acc}}' if acc else '1m')) + self._1w: MetricPattern5[T] = MetricPattern5(client, (f'1w_{{acc}}' if acc else '1w')) + self._1y: MetricPattern5[T] = MetricPattern5(client, (f'1y_{{acc}}' if acc else '1y')) + self._2y: MetricPattern5[T] = MetricPattern5(client, (f'2y_{{acc}}' if acc else '2y')) + self._3m: MetricPattern5[T] = MetricPattern5(client, (f'3m_{{acc}}' if acc else '3m')) + self._3y: MetricPattern5[T] = MetricPattern5(client, (f'3y_{{acc}}' if acc else '3y')) + self._4y: MetricPattern5[T] = MetricPattern5(client, (f'4y_{{acc}}' if acc else '4y')) + self._5y: MetricPattern5[T] = MetricPattern5(client, (f'5y_{{acc}}' if acc else '5y')) + self._6m: MetricPattern5[T] = MetricPattern5(client, (f'6m_{{acc}}' if acc else '6m')) + self._6y: MetricPattern5[T] = MetricPattern5(client, (f'6y_{{acc}}' if acc else '6y')) + self._8y: MetricPattern5[T] = MetricPattern5(client, (f'8y_{{acc}}' if acc else '8y')) -class BitcoinPattern(Generic[T]): +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.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'avg')) - self.base: MetricPattern25[T] = MetricPattern25(client, acc) - self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) - self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) - self.median: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'median')) - self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) - self.pct10: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct10')) - self.pct25: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct25')) - self.pct75: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct75')) - self.pct90: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct90')) - self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) - -class ClassAvgPricePattern(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_avg_price')) - self._2016: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2016_avg_price')) - self._2017: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2017_avg_price')) - self._2018: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2018_avg_price')) - self._2019: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2019_avg_price')) - self._2020: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2020_avg_price')) - self._2021: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2021_avg_price')) - self._2022: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2022_avg_price')) - self._2023: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2023_avg_price')) - self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_avg_price')) - self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_avg_price')) + self._2015: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2015_average_price')) + self._2016: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2016_average_price')) + self._2017: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2017_average_price')) + self._2018: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2018_average_price')) + self._2019: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2019_average_price')) + self._2020: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2020_average_price')) + self._2021: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2021_average_price')) + self._2022: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2022_average_price')) + self._2023: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2023_average_price')) + self._2024: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2024_average_price')) + self._2025: MetricPattern5[T] = MetricPattern5(client, _m(acc, '2025_average_price')) 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: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')) - self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.neg_unrealized_loss_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_market_cap')) + self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_own_total_unrealized_pnl')) self.net_unrealized_pnl_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_market_cap')) self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_own_total_unrealized_pnl')) - self.supply_in_loss_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) - self.supply_in_profit_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) - self.unrealized_loss_rel_to_own_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) - self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) - self.unrealized_profit_rel_to_own_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) - self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) + self.supply_in_loss_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) + self.unrealized_loss_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_market_cap')) + self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_own_total_unrealized_pnl')) + self.unrealized_profit_rel_to_own_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap')) + self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl')) class RelativePattern: """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_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')) + self.neg_unrealized_loss_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')) self.net_unrealized_pnl_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')) - self.nupl: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'nupl')) - self.supply_in_loss_rel_to_circulating_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')) - self.supply_in_loss_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) - self.supply_in_profit_rel_to_circulating_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')) - self.supply_in_profit_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) - self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')) - self.unrealized_loss_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) - self.unrealized_profit_rel_to_market_cap: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) - -class BlockSizePattern(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, 'avg')) - self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) - self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) - self.median: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'median')) - self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) - self.pct10: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct10')) - self.pct25: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct25')) - self.pct75: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct75')) - self.pct90: MetricPattern21[T] = MetricPattern21(client, _m(acc, 'pct90')) - self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) + self.nupl: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'nupl')) + self.supply_in_loss_rel_to_circulating_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')) + self.supply_in_loss_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_circulating_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'supply_in_profit_rel_to_own_supply')) + self.supply_rel_to_circulating_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'supply_rel_to_circulating_supply')) + self.unrealized_loss_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_loss_rel_to_market_cap')) + self.unrealized_profit_rel_to_market_cap: MetricPattern3[StoredF32] = MetricPattern3(client, _m(acc, 'unrealized_profit_rel_to_market_cap')) class UnrealizedPattern: """Pattern struct for repeated tree structure.""" @@ -2534,28 +2579,28 @@ class AddresstypeToHeightToAddrCountPattern(Generic[T]): def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.p2a: MetricPattern29[T] = MetricPattern29(client, (f'p2a_{{acc}}' if acc else 'p2a')) - self.p2pk33: MetricPattern31[T] = MetricPattern31(client, (f'p2pk33_{{acc}}' if acc else 'p2pk33')) - self.p2pk65: MetricPattern32[T] = MetricPattern32(client, (f'p2pk65_{{acc}}' if acc else 'p2pk65')) - self.p2pkh: MetricPattern33[T] = MetricPattern33(client, (f'p2pkh_{{acc}}' if acc else 'p2pkh')) - self.p2sh: MetricPattern34[T] = MetricPattern34(client, (f'p2sh_{{acc}}' if acc else 'p2sh')) - self.p2tr: MetricPattern35[T] = MetricPattern35(client, (f'p2tr_{{acc}}' if acc else 'p2tr')) - self.p2wpkh: MetricPattern36[T] = MetricPattern36(client, (f'p2wpkh_{{acc}}' if acc else 'p2wpkh')) - self.p2wsh: MetricPattern37[T] = MetricPattern37(client, (f'p2wsh_{{acc}}' if acc else 'p2wsh')) + self.p2a: MetricPattern26[T] = MetricPattern26(client, (f'p2a_{{acc}}' if acc else 'p2a')) + self.p2pk33: MetricPattern26[T] = MetricPattern26(client, (f'p2pk33_{{acc}}' if acc else 'p2pk33')) + self.p2pk65: MetricPattern26[T] = MetricPattern26(client, (f'p2pk65_{{acc}}' if acc else 'p2pk65')) + self.p2pkh: MetricPattern26[T] = MetricPattern26(client, (f'p2pkh_{{acc}}' if acc else 'p2pkh')) + self.p2sh: MetricPattern26[T] = MetricPattern26(client, (f'p2sh_{{acc}}' if acc else 'p2sh')) + self.p2tr: MetricPattern26[T] = MetricPattern26(client, (f'p2tr_{{acc}}' if acc else 'p2tr')) + self.p2wpkh: MetricPattern26[T] = MetricPattern26(client, (f'p2wpkh_{{acc}}' if acc else 'p2wpkh')) + self.p2wsh: MetricPattern26[T] = MetricPattern26(client, (f'p2wsh_{{acc}}' if acc else 'p2wsh')) -class BlockIntervalPattern(Generic[T]): +class CountPattern2(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.average: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'avg')) - self.max: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'max')) - self.median: MetricPattern25[T] = MetricPattern25(client, _m(acc, 'median')) - self.min: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'min')) - self.pct10: MetricPattern25[T] = MetricPattern25(client, _m(acc, 'pct10')) - self.pct25: MetricPattern25[T] = MetricPattern25(client, _m(acc, 'pct25')) - self.pct75: MetricPattern25[T] = MetricPattern25(client, _m(acc, 'pct75')) - self.pct90: MetricPattern25[T] = MetricPattern25(client, _m(acc, 'pct90')) + self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average')) + self.cumulative: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'cumulative')) + self.distribution: BlockIntervalPattern[T] = BlockIntervalPattern(client, acc) + self.max: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'max')) + self.min: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'min')) + self.minmax: MinmaxPattern[T] = MinmaxPattern(client, acc) + self.sum: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'sum')) + self.sum_cum: SumCumPattern[T] = SumCumPattern(client, acc) class _0satsPattern: """Pattern struct for repeated tree structure.""" @@ -2575,25 +2620,39 @@ class PeriodCagrPattern: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self._10y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'10y_{{acc}}' if acc else '10y')) - self._2y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'2y_{{acc}}' if acc else '2y')) - self._3y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'3y_{{acc}}' if acc else '3y')) - self._4y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'4y_{{acc}}' if acc else '4y')) - self._5y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'5y_{{acc}}' if acc else '5y')) - self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'6y_{{acc}}' if acc else '6y')) - self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, (f'8y_{{acc}}' if acc else '8y')) + self._10y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'10y_{{acc}}' if acc else '10y')) + self._2y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'2y_{{acc}}' if acc else '2y')) + self._3y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'3y_{{acc}}' if acc else '3y')) + self._4y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'4y_{{acc}}' if acc else '4y')) + self._5y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'5y_{{acc}}' if acc else '5y')) + self._6y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'6y_{{acc}}' if acc else '6y')) + self._8y: MetricPattern5[StoredF32] = MetricPattern5(client, (f'8y_{{acc}}' if acc else '8y')) -class _0satsPattern2: +class BlockSizePattern(Generic[T]): """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: CostBasisPattern = CostBasisPattern(client, acc) - self.realized: RealizedPattern = RealizedPattern(client, acc) - self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in')) - self.supply: SupplyPattern3 = SupplyPattern3(client, acc) - self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + self.average: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'average')) + self.cumulative: MetricPattern4[T] = MetricPattern4(client, _m(acc, 'cumulative')) + self.distribution: BlockIntervalPattern[T] = BlockIntervalPattern(client, acc) + self.max: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'max')) + self.min: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'min')) + self.sum: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'sum')) + self.sum_cum: SumCumPattern[T] = SumCumPattern(client, acc) + +class DollarsPattern(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: MetricPattern26[T] = MetricPattern26(client, acc) + self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) + self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) + self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) + self.percentiles: PercentilesPattern[T] = PercentilesPattern(client, acc) + self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) class _10yPattern: """Pattern struct for repeated tree structure.""" @@ -2607,18 +2666,6 @@ class _10yPattern: self.supply: SupplyPattern3 = SupplyPattern3(client, acc) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) -class _100btcPattern: - """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: CostBasisPattern = CostBasisPattern(client, acc) - self.realized: RealizedPattern = RealizedPattern(client, acc) - self.relative: RelativePattern = RelativePattern(client, acc) - self.supply: SupplyPattern3 = SupplyPattern3(client, acc) - self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) - class _10yTo12yPattern: """Pattern struct for repeated tree structure.""" @@ -2631,14 +2678,38 @@ class _10yTo12yPattern: self.supply: SupplyPattern3 = SupplyPattern3(client, acc) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) -class SegwitAdoptionPattern(Generic[T]): +class _100btcPattern: """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, 'avg')) - self.base: MetricPattern25[T] = MetricPattern25(client, acc) - self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) + self.activity: ActivityPattern2 = ActivityPattern2(client, acc) + self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) + self.realized: RealizedPattern = RealizedPattern(client, acc) + self.relative: RelativePattern = RelativePattern(client, acc) + self.supply: SupplyPattern3 = SupplyPattern3(client, acc) + self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + +class _0satsPattern2: + """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: CostBasisPattern = CostBasisPattern(client, acc) + self.realized: RealizedPattern = RealizedPattern(client, acc) + self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in')) + self.supply: SupplyPattern3 = SupplyPattern3(client, acc) + self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + +class BitcoinPattern(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: MetricPattern26[T] = MetricPattern26(client, acc) + self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cum')) self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) @@ -2650,10 +2721,21 @@ class ActivityPattern2: """Create pattern node with accumulated metric name.""" self.coinblocks_destroyed: BlockCountPattern[StoredF64] = BlockCountPattern(client, _m(acc, 'coinblocks_destroyed')) self.coindays_destroyed: BlockCountPattern[StoredF64] = BlockCountPattern(client, _m(acc, 'coindays_destroyed')) - self.satblocks_destroyed: MetricPattern25[Sats] = MetricPattern25(client, _m(acc, 'satblocks_destroyed')) - self.satdays_destroyed: MetricPattern25[Sats] = MetricPattern25(client, _m(acc, 'satdays_destroyed')) + self.satblocks_destroyed: MetricPattern26[Sats] = MetricPattern26(client, _m(acc, 'satblocks_destroyed')) + self.satdays_destroyed: MetricPattern26[Sats] = MetricPattern26(client, _m(acc, 'satdays_destroyed')) self.sent: SentPattern = SentPattern(client, _m(acc, 'sent')) +class SentPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.base: MetricPattern26[Sats] = MetricPattern26(client, _m(acc, 'height_fee')) + self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc')) + self.dollars: SumCumPattern[Dollars] = SumCumPattern(client, _m(acc, 'usd')) + self.dollars_source: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'usd')) + self.sats: SumCumPattern[Sats] = SumCumPattern(client, _m(acc, 'fee')) + class SupplyPattern3: """Pattern struct for repeated tree structure.""" @@ -2665,53 +2747,56 @@ class SupplyPattern3: self.supply_value: SupplyValuePattern = SupplyValuePattern(client, _m(acc, 'supply')) self.utxo_count: MetricPattern1[StoredU64] = MetricPattern1(client, _m(acc, 'utxo_count')) +class PercentilesPattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.median: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'median')) + self.pct10: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'pct10')) + self.pct25: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'pct25')) + self.pct75: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'pct75')) + self.pct90: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'pct90')) + class SupplyPattern2: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.base: MetricPattern25[Sats] = MetricPattern25(client, acc) - 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) + self.base: MetricPattern26[Sats] = MetricPattern26(client, acc) + self.bitcoin: MetricPattern5[Bitcoin] = MetricPattern5(client, _m(acc, 'btc')) + self.dollars: MetricPattern5[Dollars] = MetricPattern5(client, _m(acc, 'usd')) + self.sats: MetricPattern7[Sats] = MetricPattern7(client, acc) -class OpreturnPattern: +class PriceHighInSatsPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.base: MetricPattern25[Sats] = MetricPattern25(client, acc) - self.bitcoin: BitcoinPattern2[Bitcoin] = BitcoinPattern2(client, _m(acc, 'btc')) - self.dollars: BitcoinPattern2[Dollars] = BitcoinPattern2(client, _m(acc, 'usd')) - self.sats: SatsPattern4 = SatsPattern4(client, acc) + self.dateindex: MetricPattern22[T] = MetricPattern22(client, acc) + self.height: MetricPattern26[T] = MetricPattern26(client, acc) + self.max: MetricPattern24[T] = MetricPattern24(client, _m(acc, 'max')) + self.rest: MetricPattern7[T] = MetricPattern7(client, _m(acc, 'max')) -class SentPattern: +class PriceLowInSatsPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.base: MetricPattern25[Sats] = MetricPattern25(client, acc) - self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc')) - self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) - self.sats: SatsPattern = SatsPattern(client, acc) + self.dateindex: MetricPattern22[T] = MetricPattern22(client, acc) + self.height: MetricPattern26[T] = MetricPattern26(client, acc) + self.min: MetricPattern24[T] = MetricPattern24(client, _m(acc, 'min')) + self.rest: MetricPattern7[T] = MetricPattern7(client, _m(acc, 'min')) -class CoinbasePattern: +class BlockIntervalPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.bitcoin: BitcoinPattern[Bitcoin] = BitcoinPattern(client, _m(acc, 'btc')) - self.dollars: BitcoinPattern[Dollars] = BitcoinPattern(client, _m(acc, 'usd')) - self.sats: BitcoinPattern[Sats] = BitcoinPattern(client, acc) - -class UnclaimedRewardsPattern: - """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) + self.average: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'average')) + self.max: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'max')) + self.min: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'min')) + self.percentiles: PercentilesPattern[T] = PercentilesPattern(client, acc) class ActiveSupplyPattern: """Pattern struct for repeated tree structure.""" @@ -2729,49 +2814,50 @@ class CostBasisPattern2: """Create pattern node with accumulated metric name.""" self.max_cost_basis: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) self.min_cost_basis: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) - self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis')) + self.percentiles: PercentilesPattern2 = PercentilesPattern2(client, _m(acc, 'cost_basis')) + +class CoinbasePattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.bitcoin: BitcoinPattern[Bitcoin] = BitcoinPattern(client, _m(acc, 'btc')) + self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd')) + self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc) + +class UnclaimedRewardsPattern: + """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 BlockCountPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.base: MetricPattern25[T] = MetricPattern25(client, acc) - self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) + self.base: MetricPattern26[T] = MetricPattern26(client, acc) + self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative')) self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) -class BitcoinPattern2(Generic[T]): +class SupplyValuePattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.base: MetricPattern25[T] = MetricPattern25(client, acc) - self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) - self.last: MetricPattern2[T] = MetricPattern2(client, acc) - -class SatsPattern4: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.cumulative: MetricPattern1[Sats] = MetricPattern1(client, _m(acc, 'cumulative')) - self.last: MetricPattern2[Sats] = MetricPattern2(client, acc) + self.bitcoin: MetricPattern26[Bitcoin] = MetricPattern26(client, _m(acc, 'btc')) + self.dollars: MetricPattern26[Dollars] = MetricPattern26(client, _m(acc, 'usd')) class RelativePattern4: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.supply_in_loss_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'loss_rel_to_own_supply')) - self.supply_in_profit_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, _m(acc, 'profit_rel_to_own_supply')) - -class SatsPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.cumulative: MetricPattern1[Sats] = MetricPattern1(client, _m(acc, 'cumulative')) - self.sum: MetricPattern2[Sats] = MetricPattern2(client, acc) + self.supply_in_loss_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'loss_rel_to_own_supply')) + self.supply_in_profit_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, _m(acc, 'profit_rel_to_own_supply')) class CostBasisPattern: """Pattern struct for repeated tree structure.""" @@ -2781,36 +2867,52 @@ class CostBasisPattern: self.max_cost_basis: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) self.min_cost_basis: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) -class SupplyValuePattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.bitcoin: MetricPattern25[Bitcoin] = MetricPattern25(client, _m(acc, 'btc')) - self.dollars: MetricPattern25[Dollars] = MetricPattern25(client, _m(acc, 'usd')) - 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')) + self.sd: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'sd')) + self.sma: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'sma')) -class TotalRealizedPnlPattern(Generic[T]): +class MinmaxPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.base: MetricPattern25[T] = MetricPattern25(client, acc) + self.max: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'max')) + self.min: MetricPattern22[T] = MetricPattern22(client, _m(acc, 'min')) + +class SumCumPattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) +class IndexesPattern2(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.dateindex: MetricPattern22[T] = MetricPattern22(client, acc) + self.rest: MetricPattern7[T] = MetricPattern7(client, _m(acc, 'average')) + +class DifficultyAdjustmentPattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.base: MetricPattern26[T] = MetricPattern26(client, acc) + self.rest: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum')) + class RealizedPriceExtraPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio')) + self.ratio: MetricPattern5[StoredF32] = MetricPattern5(client, _m(acc, 'ratio')) # Catalog tree classes @@ -2858,12 +2960,12 @@ class CatalogTree_Computed_Blocks_Count: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._1m_block_count: MetricPattern4[StoredU32] = MetricPattern4(client, f'{base_path}_1m_block_count') - self._1w_block_count: MetricPattern4[StoredU32] = MetricPattern4(client, f'{base_path}_1w_block_count') - self._1y_block_count: MetricPattern4[StoredU32] = MetricPattern4(client, f'{base_path}_1y_block_count') - self._24h_block_count: MetricPattern25[StoredU32] = MetricPattern25(client, f'{base_path}_24h_block_count') + self._1m_block_count: MetricPattern5[StoredU32] = MetricPattern5(client, f'{base_path}_1m_block_count') + self._1w_block_count: MetricPattern5[StoredU32] = MetricPattern5(client, f'{base_path}_1w_block_count') + self._1y_block_count: MetricPattern5[StoredU32] = MetricPattern5(client, f'{base_path}_1y_block_count') + self._24h_block_count: MetricPattern26[StoredU32] = MetricPattern26(client, f'{base_path}_24h_block_count') self.block_count: BlockCountPattern[StoredU32] = BlockCountPattern(client, 'block_count') - self.block_count_target: MetricPattern4[StoredU64] = MetricPattern4(client, f'{base_path}_block_count_target') + self.block_count_target: MetricPattern5[StoredU64] = MetricPattern5(client, f'{base_path}_block_count_target') class CatalogTree_Computed_Blocks_Difficulty: """Catalog tree node.""" @@ -2871,7 +2973,7 @@ class CatalogTree_Computed_Blocks_Difficulty: def __init__(self, client: BrkClientBase, base_path: str = ''): self.blocks_before_next_difficulty_adjustment: MetricPattern1[StoredU32] = MetricPattern1(client, f'{base_path}_blocks_before_next_difficulty_adjustment') self.days_before_next_difficulty_adjustment: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_days_before_next_difficulty_adjustment') - self.difficultyepoch: MetricPattern4[DifficultyEpoch] = MetricPattern4(client, f'{base_path}_difficultyepoch') + self.difficultyepoch: MetricPattern5[DifficultyEpoch] = MetricPattern5(client, f'{base_path}_difficultyepoch') class CatalogTree_Computed_Blocks_Halving: """Catalog tree node.""" @@ -2879,21 +2981,21 @@ class CatalogTree_Computed_Blocks_Halving: def __init__(self, client: BrkClientBase, base_path: str = ''): self.blocks_before_next_halving: MetricPattern1[StoredU32] = MetricPattern1(client, f'{base_path}_blocks_before_next_halving') self.days_before_next_halving: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_days_before_next_halving') - self.halvingepoch: MetricPattern4[HalvingEpoch] = MetricPattern4(client, f'{base_path}_halvingepoch') + self.halvingepoch: MetricPattern5[HalvingEpoch] = MetricPattern5(client, f'{base_path}_halvingepoch') class CatalogTree_Computed_Blocks_Interval: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): self.block_interval: BlockIntervalPattern[Timestamp] = BlockIntervalPattern(client, 'block_interval') - self.interval: MetricPattern25[Timestamp] = MetricPattern25(client, f'{base_path}_interval') + self.interval: MetricPattern26[Timestamp] = MetricPattern26(client, f'{base_path}_interval') class CatalogTree_Computed_Blocks_Mining: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): self.difficulty: MetricPattern2[StoredF64] = MetricPattern2(client, f'{base_path}_difficulty') - self.difficulty_adjustment: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_difficulty_adjustment') + self.difficulty_adjustment: DifficultyAdjustmentPattern[StoredF32] = DifficultyAdjustmentPattern(client, 'difficulty_adjustment') self.difficulty_as_hash: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_difficulty_as_hash') self.hash_price_phs: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_price_phs') self.hash_price_phs_min: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_price_phs_min') @@ -2901,10 +3003,10 @@ class CatalogTree_Computed_Blocks_Mining: self.hash_price_ths: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_price_ths') self.hash_price_ths_min: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_price_ths_min') self.hash_rate: MetricPattern1[StoredF64] = MetricPattern1(client, f'{base_path}_hash_rate') - self.hash_rate_1m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_hash_rate_1m_sma') - self.hash_rate_1w_sma: MetricPattern4[StoredF64] = MetricPattern4(client, f'{base_path}_hash_rate_1w_sma') - self.hash_rate_1y_sma: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_hash_rate_1y_sma') - self.hash_rate_2m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_hash_rate_2m_sma') + self.hash_rate_1m_sma: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_hash_rate_1m_sma') + self.hash_rate_1w_sma: MetricPattern5[StoredF64] = MetricPattern5(client, f'{base_path}_hash_rate_1w_sma') + self.hash_rate_1y_sma: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_hash_rate_1y_sma') + self.hash_rate_2m_sma: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_hash_rate_2m_sma') self.hash_value_phs: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_value_phs') self.hash_value_phs_min: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_value_phs_min') self.hash_value_rebound: MetricPattern1[StoredF32] = MetricPattern1(client, f'{base_path}_hash_value_rebound') @@ -2915,13 +3017,13 @@ class CatalogTree_Computed_Blocks_Rewards: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._24h_coinbase_sum: MetricPattern25[Sats] = MetricPattern25(client, f'{base_path}_24h_coinbase_sum') - self._24h_coinbase_usd_sum: MetricPattern25[Dollars] = MetricPattern25(client, f'{base_path}_24h_coinbase_usd_sum') + self._24h_coinbase_sum: MetricPattern26[Sats] = MetricPattern26(client, f'{base_path}_24h_coinbase_sum') + self._24h_coinbase_usd_sum: MetricPattern26[Dollars] = MetricPattern26(client, f'{base_path}_24h_coinbase_usd_sum') self.coinbase: CoinbasePattern = CoinbasePattern(client, 'coinbase') - self.fee_dominance: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_fee_dominance') + self.fee_dominance: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_fee_dominance') self.subsidy: CoinbasePattern = CoinbasePattern(client, 'subsidy') - self.subsidy_dominance: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_subsidy_dominance') - self.subsidy_usd_1y_sma: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_subsidy_usd_1y_sma') + self.subsidy_dominance: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_subsidy_dominance') + self.subsidy_usd_1y_sma: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_subsidy_usd_1y_sma') self.unclaimed_rewards: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, 'unclaimed_rewards') class CatalogTree_Computed_Blocks_Size: @@ -2930,16 +3032,16 @@ class CatalogTree_Computed_Blocks_Size: def __init__(self, client: BrkClientBase, base_path: str = ''): self.block_size: BlockSizePattern[StoredU64] = BlockSizePattern(client, 'block_size') self.block_vbytes: BlockSizePattern[StoredU64] = BlockSizePattern(client, 'block_vbytes') - self.vbytes: MetricPattern25[StoredU64] = MetricPattern25(client, f'{base_path}_vbytes') + self.vbytes: MetricPattern26[StoredU64] = MetricPattern26(client, f'{base_path}_vbytes') class CatalogTree_Computed_Blocks_Time: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.date: MetricPattern25[Date] = MetricPattern25(client, f'{base_path}_date') - self.date_fixed: MetricPattern25[Date] = MetricPattern25(client, f'{base_path}_date_fixed') + self.date: MetricPattern26[Date] = MetricPattern26(client, f'{base_path}_date') + self.date_fixed: MetricPattern26[Date] = MetricPattern26(client, f'{base_path}_date_fixed') self.timestamp: MetricPattern2[Timestamp] = MetricPattern2(client, f'{base_path}_timestamp') - self.timestamp_fixed: MetricPattern25[Timestamp] = MetricPattern25(client, f'{base_path}_timestamp_fixed') + self.timestamp_fixed: MetricPattern26[Timestamp] = MetricPattern26(client, f'{base_path}_timestamp_fixed') class CatalogTree_Computed_Blocks_Weight: """Catalog tree node.""" @@ -2973,9 +3075,9 @@ class CatalogTree_Computed_Cointime_Adjusted: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.cointime_adj_inflation_rate: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_cointime_adj_inflation_rate') - self.cointime_adj_tx_btc_velocity: MetricPattern4[StoredF64] = MetricPattern4(client, f'{base_path}_cointime_adj_tx_btc_velocity') - self.cointime_adj_tx_usd_velocity: MetricPattern4[StoredF64] = MetricPattern4(client, f'{base_path}_cointime_adj_tx_usd_velocity') + self.cointime_adj_inflation_rate: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_cointime_adj_inflation_rate') + self.cointime_adj_tx_btc_velocity: MetricPattern5[StoredF64] = MetricPattern5(client, f'{base_path}_cointime_adj_tx_btc_velocity') + self.cointime_adj_tx_usd_velocity: MetricPattern5[StoredF64] = MetricPattern5(client, f'{base_path}_cointime_adj_tx_usd_velocity') class CatalogTree_Computed_Cointime_Cap: """Catalog tree node.""" @@ -3050,10 +3152,10 @@ class CatalogTree_Computed_Distribution: self.addresstype_to_indexes_to_addr_count: AddresstypeToHeightToAddrCountPattern[StoredU64] = AddresstypeToHeightToAddrCountPattern(client, 'addr_count') self.addresstype_to_indexes_to_empty_addr_count: AddresstypeToHeightToAddrCountPattern[StoredU64] = AddresstypeToHeightToAddrCountPattern(client, 'empty_addr_count') self.any_address_indexes: AddresstypeToHeightToAddrCountPattern[AnyAddressIndex] = AddresstypeToHeightToAddrCountPattern(client, 'anyaddressindex') - self.chain_state: MetricPattern25[SupplyState] = MetricPattern25(client, f'{base_path}_chain_state') + self.chain_state: MetricPattern26[SupplyState] = MetricPattern26(client, f'{base_path}_chain_state') self.empty_addr_count: MetricPattern1[StoredU64] = MetricPattern1(client, f'{base_path}_empty_addr_count') - self.emptyaddressindex: MetricPattern41[EmptyAddressIndex] = MetricPattern41(client, f'{base_path}_emptyaddressindex') - self.loadedaddressindex: MetricPattern40[LoadedAddressIndex] = MetricPattern40(client, f'{base_path}_loadedaddressindex') + self.emptyaddressindex: MetricPattern42[EmptyAddressIndex] = MetricPattern42(client, f'{base_path}_emptyaddressindex') + self.loadedaddressindex: MetricPattern41[LoadedAddressIndex] = MetricPattern41(client, f'{base_path}_loadedaddressindex') self.utxo_cohorts: CatalogTree_Computed_Distribution_UtxoCohorts = CatalogTree_Computed_Distribution_UtxoCohorts(client, f'{base_path}_utxo_cohorts') class CatalogTree_Computed_Distribution_AddressCohorts: @@ -3124,8 +3226,8 @@ class CatalogTree_Computed_Distribution_AddressesData: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.empty: MetricPattern41[EmptyAddressData] = MetricPattern41(client, f'{base_path}_empty') - self.loaded: MetricPattern40[LoadedAddressData] = MetricPattern40(client, f'{base_path}_loaded') + self.empty: MetricPattern42[EmptyAddressData] = MetricPattern42(client, f'{base_path}_empty') + self.loaded: MetricPattern41[LoadedAddressData] = MetricPattern41(client, f'{base_path}_loaded') class CatalogTree_Computed_Distribution_UtxoCohorts: """Catalog tree node.""" @@ -3184,12 +3286,12 @@ class CatalogTree_Computed_Distribution_UtxoCohorts_All_Relative: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_neg_unrealized_loss_rel_to_own_total_unrealized_pnl') + self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, f'{base_path}_neg_unrealized_loss_rel_to_own_total_unrealized_pnl') self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, f'{base_path}_net_unrealized_pnl_rel_to_own_total_unrealized_pnl') - self.supply_in_loss_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, f'{base_path}_supply_in_loss_rel_to_own_supply') - self.supply_in_profit_rel_to_own_supply: MetricPattern5[StoredF64] = MetricPattern5(client, f'{base_path}_supply_in_profit_rel_to_own_supply') - self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_unrealized_loss_rel_to_own_total_unrealized_pnl') - self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_unrealized_profit_rel_to_own_total_unrealized_pnl') + self.supply_in_loss_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, f'{base_path}_supply_in_loss_rel_to_own_supply') + self.supply_in_profit_rel_to_own_supply: MetricPattern3[StoredF64] = MetricPattern3(client, f'{base_path}_supply_in_profit_rel_to_own_supply') + self.unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, f'{base_path}_unrealized_loss_rel_to_own_total_unrealized_pnl') + self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern3[StoredF32] = MetricPattern3(client, f'{base_path}_unrealized_profit_rel_to_own_total_unrealized_pnl') class CatalogTree_Computed_Distribution_UtxoCohorts_AmountRange: """Catalog tree node.""" @@ -3384,61 +3486,61 @@ class CatalogTree_Computed_Indexes_Address: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.emptyoutputindex: MetricPattern24[EmptyOutputIndex] = MetricPattern24(client, f'{base_path}_emptyoutputindex') - self.opreturnindex: MetricPattern27[OpReturnIndex] = MetricPattern27(client, f'{base_path}_opreturnindex') - self.p2aaddressindex: MetricPattern29[P2AAddressIndex] = MetricPattern29(client, f'{base_path}_p2aaddressindex') - self.p2msoutputindex: MetricPattern30[P2MSOutputIndex] = MetricPattern30(client, f'{base_path}_p2msoutputindex') - self.p2pk33addressindex: MetricPattern31[P2PK33AddressIndex] = MetricPattern31(client, f'{base_path}_p2pk33addressindex') - self.p2pk65addressindex: MetricPattern32[P2PK65AddressIndex] = MetricPattern32(client, f'{base_path}_p2pk65addressindex') - self.p2pkhaddressindex: MetricPattern33[P2PKHAddressIndex] = MetricPattern33(client, f'{base_path}_p2pkhaddressindex') - self.p2shaddressindex: MetricPattern34[P2SHAddressIndex] = MetricPattern34(client, f'{base_path}_p2shaddressindex') - self.p2traddressindex: MetricPattern35[P2TRAddressIndex] = MetricPattern35(client, f'{base_path}_p2traddressindex') - self.p2wpkhaddressindex: MetricPattern36[P2WPKHAddressIndex] = MetricPattern36(client, f'{base_path}_p2wpkhaddressindex') - self.p2wshaddressindex: MetricPattern37[P2WSHAddressIndex] = MetricPattern37(client, f'{base_path}_p2wshaddressindex') - self.unknownoutputindex: MetricPattern39[UnknownOutputIndex] = MetricPattern39(client, f'{base_path}_unknownoutputindex') + self.emptyoutputindex: MetricPattern25[EmptyOutputIndex] = MetricPattern25(client, f'{base_path}_emptyoutputindex') + self.opreturnindex: MetricPattern28[OpReturnIndex] = MetricPattern28(client, f'{base_path}_opreturnindex') + self.p2aaddressindex: MetricPattern30[P2AAddressIndex] = MetricPattern30(client, f'{base_path}_p2aaddressindex') + self.p2msoutputindex: MetricPattern31[P2MSOutputIndex] = MetricPattern31(client, f'{base_path}_p2msoutputindex') + self.p2pk33addressindex: MetricPattern32[P2PK33AddressIndex] = MetricPattern32(client, f'{base_path}_p2pk33addressindex') + self.p2pk65addressindex: MetricPattern33[P2PK65AddressIndex] = MetricPattern33(client, f'{base_path}_p2pk65addressindex') + self.p2pkhaddressindex: MetricPattern34[P2PKHAddressIndex] = MetricPattern34(client, f'{base_path}_p2pkhaddressindex') + self.p2shaddressindex: MetricPattern35[P2SHAddressIndex] = MetricPattern35(client, f'{base_path}_p2shaddressindex') + self.p2traddressindex: MetricPattern36[P2TRAddressIndex] = MetricPattern36(client, f'{base_path}_p2traddressindex') + self.p2wpkhaddressindex: MetricPattern37[P2WPKHAddressIndex] = MetricPattern37(client, f'{base_path}_p2wpkhaddressindex') + self.p2wshaddressindex: MetricPattern38[P2WSHAddressIndex] = MetricPattern38(client, f'{base_path}_p2wshaddressindex') + self.unknownoutputindex: MetricPattern40[UnknownOutputIndex] = MetricPattern40(client, f'{base_path}_unknownoutputindex') class CatalogTree_Computed_Indexes_Block: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.dateindex: MetricPattern25[DateIndex] = MetricPattern25(client, f'{base_path}_dateindex') - self.difficultyepoch: MetricPattern14[DifficultyEpoch] = MetricPattern14(client, f'{base_path}_difficultyepoch') - self.first_height: MetricPattern13[Height] = MetricPattern13(client, f'{base_path}_first_height') - self.halvingepoch: MetricPattern15[HalvingEpoch] = MetricPattern15(client, f'{base_path}_halvingepoch') - self.height: MetricPattern25[Height] = MetricPattern25(client, f'{base_path}_height') - self.height_count: MetricPattern23[StoredU64] = MetricPattern23(client, f'{base_path}_height_count') - self.txindex_count: MetricPattern25[StoredU64] = MetricPattern25(client, f'{base_path}_txindex_count') + self.dateindex: MetricPattern26[DateIndex] = MetricPattern26(client, f'{base_path}_dateindex') + self.difficultyepoch: MetricPattern15[DifficultyEpoch] = MetricPattern15(client, f'{base_path}_difficultyepoch') + self.first_height: MetricPattern14[Height] = MetricPattern14(client, f'{base_path}_first_height') + self.halvingepoch: MetricPattern16[HalvingEpoch] = MetricPattern16(client, f'{base_path}_halvingepoch') + self.height: MetricPattern26[Height] = MetricPattern26(client, f'{base_path}_height') + self.height_count: MetricPattern24[StoredU64] = MetricPattern24(client, f'{base_path}_height_count') + self.txindex_count: MetricPattern26[StoredU64] = MetricPattern26(client, f'{base_path}_txindex_count') class CatalogTree_Computed_Indexes_Time: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.date: MetricPattern21[Date] = MetricPattern21(client, f'{base_path}_date') - self.dateindex: MetricPattern21[DateIndex] = MetricPattern21(client, f'{base_path}_dateindex') - self.dateindex_count: MetricPattern19[StoredU64] = MetricPattern19(client, f'{base_path}_dateindex_count') - self.decadeindex: MetricPattern12[DecadeIndex] = MetricPattern12(client, f'{base_path}_decadeindex') - self.first_dateindex: MetricPattern19[DateIndex] = MetricPattern19(client, f'{base_path}_first_dateindex') - self.first_height: MetricPattern21[Height] = MetricPattern21(client, f'{base_path}_first_height') - self.first_monthindex: MetricPattern8[MonthIndex] = MetricPattern8(client, f'{base_path}_first_monthindex') - self.first_yearindex: MetricPattern22[YearIndex] = MetricPattern22(client, f'{base_path}_first_yearindex') - self.height_count: MetricPattern21[StoredU64] = MetricPattern21(client, f'{base_path}_height_count') - self.monthindex: MetricPattern10[MonthIndex] = MetricPattern10(client, f'{base_path}_monthindex') - self.monthindex_count: MetricPattern8[StoredU64] = MetricPattern8(client, f'{base_path}_monthindex_count') - self.quarterindex: MetricPattern17[QuarterIndex] = MetricPattern17(client, f'{base_path}_quarterindex') - self.semesterindex: MetricPattern18[SemesterIndex] = MetricPattern18(client, f'{base_path}_semesterindex') - self.weekindex: MetricPattern11[WeekIndex] = MetricPattern11(client, f'{base_path}_weekindex') - self.yearindex: MetricPattern20[YearIndex] = MetricPattern20(client, f'{base_path}_yearindex') - self.yearindex_count: MetricPattern22[StoredU64] = MetricPattern22(client, f'{base_path}_yearindex_count') + self.date: MetricPattern22[Date] = MetricPattern22(client, f'{base_path}_date') + self.dateindex: MetricPattern22[DateIndex] = MetricPattern22(client, f'{base_path}_dateindex') + self.dateindex_count: MetricPattern20[StoredU64] = MetricPattern20(client, f'{base_path}_dateindex_count') + self.decadeindex: MetricPattern13[DecadeIndex] = MetricPattern13(client, f'{base_path}_decadeindex') + self.first_dateindex: MetricPattern20[DateIndex] = MetricPattern20(client, f'{base_path}_first_dateindex') + self.first_height: MetricPattern22[Height] = MetricPattern22(client, f'{base_path}_first_height') + self.first_monthindex: MetricPattern9[MonthIndex] = MetricPattern9(client, f'{base_path}_first_monthindex') + self.first_yearindex: MetricPattern23[YearIndex] = MetricPattern23(client, f'{base_path}_first_yearindex') + self.height_count: MetricPattern22[StoredU64] = MetricPattern22(client, f'{base_path}_height_count') + self.monthindex: MetricPattern11[MonthIndex] = MetricPattern11(client, f'{base_path}_monthindex') + self.monthindex_count: MetricPattern9[StoredU64] = MetricPattern9(client, f'{base_path}_monthindex_count') + self.quarterindex: MetricPattern18[QuarterIndex] = MetricPattern18(client, f'{base_path}_quarterindex') + self.semesterindex: MetricPattern19[SemesterIndex] = MetricPattern19(client, f'{base_path}_semesterindex') + self.weekindex: MetricPattern12[WeekIndex] = MetricPattern12(client, f'{base_path}_weekindex') + self.yearindex: MetricPattern21[YearIndex] = MetricPattern21(client, f'{base_path}_yearindex') + self.yearindex_count: MetricPattern23[StoredU64] = MetricPattern23(client, f'{base_path}_yearindex_count') class CatalogTree_Computed_Indexes_Transaction: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.input_count: MetricPattern38[StoredU64] = MetricPattern38(client, f'{base_path}_input_count') - self.output_count: MetricPattern38[StoredU64] = MetricPattern38(client, f'{base_path}_output_count') - self.txindex: MetricPattern38[TxIndex] = MetricPattern38(client, f'{base_path}_txindex') - self.txinindex: MetricPattern26[TxInIndex] = MetricPattern26(client, f'{base_path}_txinindex') - self.txoutindex: MetricPattern28[TxOutIndex] = MetricPattern28(client, f'{base_path}_txoutindex') + self.input_count: MetricPattern39[StoredU64] = MetricPattern39(client, f'{base_path}_input_count') + self.output_count: MetricPattern39[StoredU64] = MetricPattern39(client, f'{base_path}_output_count') + self.txindex: MetricPattern39[TxIndex] = MetricPattern39(client, f'{base_path}_txindex') + self.txinindex: MetricPattern27[TxInIndex] = MetricPattern27(client, f'{base_path}_txinindex') + self.txoutindex: MetricPattern29[TxOutIndex] = MetricPattern29(client, f'{base_path}_txoutindex') class CatalogTree_Computed_Inputs: """Catalog tree node.""" @@ -3451,14 +3553,14 @@ class CatalogTree_Computed_Inputs_Count: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.count: BlockSizePattern[StoredU64] = BlockSizePattern(client, 'input_count') + self.count: CountPattern2[StoredU64] = CountPattern2(client, 'input_count') class CatalogTree_Computed_Inputs_Spent: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.txoutindex: MetricPattern26[TxOutIndex] = MetricPattern26(client, f'{base_path}_txoutindex') - self.value: MetricPattern26[Sats] = MetricPattern26(client, f'{base_path}_value') + self.txoutindex: MetricPattern27[TxOutIndex] = MetricPattern27(client, f'{base_path}_txoutindex') + self.value: MetricPattern27[Sats] = MetricPattern27(client, f'{base_path}_value') class CatalogTree_Computed_Market: """Catalog tree node.""" @@ -3477,23 +3579,24 @@ class CatalogTree_Computed_Market_Ath: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.days_since_price_ath: MetricPattern4[StoredU16] = MetricPattern4(client, f'{base_path}_days_since_price_ath') - self.max_days_between_price_aths: MetricPattern4[StoredU16] = MetricPattern4(client, f'{base_path}_max_days_between_price_aths') - self.max_years_between_price_aths: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_max_years_between_price_aths') + self.days_since_price_ath: MetricPattern5[StoredU16] = MetricPattern5(client, f'{base_path}_days_since_price_ath') + self.max_days_between_price_aths: MetricPattern5[StoredU16] = MetricPattern5(client, f'{base_path}_max_days_between_price_aths') + self.max_years_between_price_aths: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_max_years_between_price_aths') self.price_ath: MetricPattern3[Dollars] = MetricPattern3(client, f'{base_path}_price_ath') self.price_drawdown: MetricPattern3[StoredF32] = MetricPattern3(client, f'{base_path}_price_drawdown') + self.years_since_price_ath: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_years_since_price_ath') class CatalogTree_Computed_Market_Dca: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.class_avg_price: ClassAvgPricePattern[Dollars] = ClassAvgPricePattern(client, 'dca_class') - self.class_returns: ClassAvgPricePattern[StoredF32] = ClassAvgPricePattern(client, 'dca_class') + self.class_average_price: ClassAveragePricePattern[Dollars] = ClassAveragePricePattern(client, 'dca_class') + self.class_returns: ClassAveragePricePattern[StoredF32] = ClassAveragePricePattern(client, 'dca_class') self.class_stack: CatalogTree_Computed_Market_Dca_ClassStack = CatalogTree_Computed_Market_Dca_ClassStack(client, f'{base_path}_class_stack') - self.period_avg_price: PeriodAvgPricePattern[Dollars] = PeriodAvgPricePattern(client, 'dca_avg_price') + self.period_average_price: PeriodAveragePricePattern[Dollars] = PeriodAveragePricePattern(client, 'dca_average_price') self.period_cagr: PeriodCagrPattern = PeriodCagrPattern(client, 'dca_cagr') self.period_lump_sum_stack: PeriodLumpSumStackPattern = PeriodLumpSumStackPattern(client, '') - self.period_returns: PeriodAvgPricePattern[StoredF32] = PeriodAvgPricePattern(client, 'dca_returns') + self.period_returns: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'dca_returns') self.period_stack: PeriodLumpSumStackPattern = PeriodLumpSumStackPattern(client, '') class CatalogTree_Computed_Market_Dca_ClassStack: @@ -3516,25 +3619,25 @@ class CatalogTree_Computed_Market_Indicators: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.gini: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_gini') - self.macd_histogram: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_macd_histogram') - self.macd_line: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_macd_line') - self.macd_signal: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_macd_signal') - self.nvt: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_nvt') - self.pi_cycle: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_pi_cycle') - self.puell_multiple: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_puell_multiple') - self.rsi_14d: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_14d') - self.rsi_14d_max: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_14d_max') - self.rsi_14d_min: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_14d_min') - self.rsi_avg_gain_14d: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_avg_gain_14d') - self.rsi_avg_loss_14d: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_avg_loss_14d') - self.rsi_gains: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_gains') - self.rsi_losses: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_rsi_losses') - self.stoch_d: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_stoch_d') - self.stoch_k: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_stoch_k') - self.stoch_rsi: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_stoch_rsi') - self.stoch_rsi_d: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_stoch_rsi_d') - self.stoch_rsi_k: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_stoch_rsi_k') + self.gini: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_gini') + self.macd_histogram: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_macd_histogram') + self.macd_line: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_macd_line') + self.macd_signal: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_macd_signal') + self.nvt: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_nvt') + self.pi_cycle: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_pi_cycle') + self.puell_multiple: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_puell_multiple') + self.rsi_14d: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_14d') + self.rsi_14d_max: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_14d_max') + self.rsi_14d_min: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_14d_min') + self.rsi_average_gain_14d: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_average_gain_14d') + self.rsi_average_loss_14d: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_average_loss_14d') + self.rsi_gains: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_gains') + self.rsi_losses: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_rsi_losses') + self.stoch_d: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_stoch_d') + self.stoch_k: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_stoch_k') + self.stoch_rsi: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_stoch_rsi') + self.stoch_rsi_d: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_stoch_rsi_d') + self.stoch_rsi_k: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_stoch_rsi_k') class CatalogTree_Computed_Market_Lookback: """Catalog tree node.""" @@ -3560,8 +3663,8 @@ class CatalogTree_Computed_Market_MovingAverage: self.price_1y_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_1y_sma') self.price_200d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200d_ema') self.price_200d_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200d_sma') - self.price_200d_sma_x0_8: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_200d_sma_x0_8') - self.price_200d_sma_x2_4: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_200d_sma_x2_4') + self.price_200d_sma_x0_8: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_200d_sma_x0_8') + self.price_200d_sma_x2_4: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_200d_sma_x2_4') self.price_200w_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200w_ema') self.price_200w_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200w_sma') self.price_21d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_21d_ema') @@ -3572,7 +3675,7 @@ class CatalogTree_Computed_Market_MovingAverage: self.price_34d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_34d_ema') self.price_34d_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_34d_sma') self.price_350d_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_350d_sma') - self.price_350d_sma_x2: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_350d_sma_x2') + self.price_350d_sma_x2: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_350d_sma_x2') self.price_4y_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_4y_ema') self.price_4y_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_4y_sma') self.price_55d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_55d_ema') @@ -3586,17 +3689,17 @@ class CatalogTree_Computed_Market_Range: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.price_1m_max: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_1m_max') - self.price_1m_min: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_1m_min') - self.price_1w_max: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_1w_max') - self.price_1w_min: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_1w_min') - self.price_1y_max: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_1y_max') - self.price_1y_min: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_1y_min') - self.price_2w_choppiness_index: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_price_2w_choppiness_index') - self.price_2w_max: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_2w_max') - self.price_2w_min: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_price_2w_min') - self.price_true_range: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_price_true_range') - self.price_true_range_2w_sum: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_price_true_range_2w_sum') + self.price_1m_max: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_1m_max') + self.price_1m_min: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_1m_min') + self.price_1w_max: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_1w_max') + self.price_1w_min: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_1w_min') + self.price_1y_max: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_1y_max') + self.price_1y_min: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_1y_min') + self.price_2w_choppiness_index: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_price_2w_choppiness_index') + self.price_2w_max: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_2w_max') + self.price_2w_min: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_price_2w_min') + self.price_true_range: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_price_true_range') + self.price_true_range_2w_sum: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_price_true_range_2w_sum') class CatalogTree_Computed_Market_Returns: """Catalog tree node.""" @@ -3609,22 +3712,22 @@ class CatalogTree_Computed_Market_Returns: self.downside_1m_sd: _1dReturns1mSdPattern = _1dReturns1mSdPattern(client, 'downside_1m_sd') self.downside_1w_sd: _1dReturns1mSdPattern = _1dReturns1mSdPattern(client, 'downside_1w_sd') self.downside_1y_sd: _1dReturns1mSdPattern = _1dReturns1mSdPattern(client, 'downside_1y_sd') - self.downside_returns: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_downside_returns') + self.downside_returns: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_downside_returns') self.price_returns: PriceAgoPattern[StoredF32] = PriceAgoPattern(client, 'price_returns') class CatalogTree_Computed_Market_Volatility: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.price_1m_volatility: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_price_1m_volatility') - self.price_1w_volatility: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_price_1w_volatility') - self.price_1y_volatility: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_price_1y_volatility') - self.sharpe_1m: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_sharpe_1m') - self.sharpe_1w: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_sharpe_1w') - self.sharpe_1y: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_sharpe_1y') - self.sortino_1m: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_sortino_1m') - self.sortino_1w: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_sortino_1w') - self.sortino_1y: MetricPattern21[StoredF32] = MetricPattern21(client, f'{base_path}_sortino_1y') + self.price_1m_volatility: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_price_1m_volatility') + self.price_1w_volatility: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_price_1w_volatility') + self.price_1y_volatility: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_price_1y_volatility') + self.sharpe_1m: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_sharpe_1m') + self.sharpe_1w: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_sharpe_1w') + self.sharpe_1y: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_sharpe_1y') + self.sortino_1m: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_sortino_1m') + self.sortino_1w: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_sortino_1w') + self.sortino_1y: MetricPattern22[StoredF32] = MetricPattern22(client, f'{base_path}_sortino_1y') class CatalogTree_Computed_Outputs: """Catalog tree node.""" @@ -3637,20 +3740,20 @@ class CatalogTree_Computed_Outputs_Count: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.count: BlockSizePattern[StoredU64] = BlockSizePattern(client, 'output_count') - self.utxo_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'exact_utxo_count') + self.count: CountPattern2[StoredU64] = CountPattern2(client, 'output_count') + self.utxo_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'exact_utxo_count') class CatalogTree_Computed_Outputs_Spent: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.txinindex: MetricPattern28[TxInIndex] = MetricPattern28(client, f'{base_path}_txinindex') + self.txinindex: MetricPattern29[TxInIndex] = MetricPattern29(client, f'{base_path}_txinindex') class CatalogTree_Computed_Pools: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.pool: MetricPattern25[PoolSlug] = MetricPattern25(client, f'{base_path}_pool') + self.pool: MetricPattern26[PoolSlug] = MetricPattern26(client, f'{base_path}_pool') self.vecs: CatalogTree_Computed_Pools_Vecs = CatalogTree_Computed_Pools_Vecs(client, f'{base_path}_vecs') class CatalogTree_Computed_Pools_Vecs: @@ -3820,7 +3923,7 @@ class CatalogTree_Computed_Positions: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.position: MetricPattern16[BlkPosition] = MetricPattern16(client, f'{base_path}_position') + self.position: MetricPattern17[BlkPosition] = MetricPattern17(client, f'{base_path}_position') class CatalogTree_Computed_Price: """Catalog tree node.""" @@ -3834,15 +3937,15 @@ class CatalogTree_Computed_Price_Ohlc: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.ohlc_in_cents: MetricPattern9[OHLCCents] = MetricPattern9(client, f'{base_path}_ohlc_in_cents') + self.ohlc_in_cents: MetricPattern10[OHLCCents] = MetricPattern10(client, f'{base_path}_ohlc_in_cents') class CatalogTree_Computed_Price_Sats: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): self.price_close_in_sats: MetricPattern1[Sats] = MetricPattern1(client, f'{base_path}_price_close_in_sats') - self.price_high_in_sats: MetricPattern1[Sats] = MetricPattern1(client, f'{base_path}_price_high_in_sats') - self.price_low_in_sats: MetricPattern1[Sats] = MetricPattern1(client, f'{base_path}_price_low_in_sats') + self.price_high_in_sats: PriceHighInSatsPattern[Sats] = PriceHighInSatsPattern(client, 'price_high_in_sats') + self.price_low_in_sats: PriceLowInSatsPattern[Sats] = PriceLowInSatsPattern(client, 'price_low_in_sats') self.price_ohlc_in_sats: MetricPattern1[OHLCSats] = MetricPattern1(client, f'{base_path}_price_ohlc_in_sats') self.price_open_in_sats: MetricPattern1[Sats] = MetricPattern1(client, f'{base_path}_price_open_in_sats') @@ -3851,14 +3954,14 @@ class CatalogTree_Computed_Price_Usd: def __init__(self, client: BrkClientBase, base_path: str = ''): self.price_close: MetricPattern1[Dollars] = MetricPattern1(client, f'{base_path}_price_close') - self.price_close_in_cents: MetricPattern9[Cents] = MetricPattern9(client, f'{base_path}_price_close_in_cents') - self.price_high: MetricPattern1[Dollars] = MetricPattern1(client, f'{base_path}_price_high') - self.price_high_in_cents: MetricPattern9[Cents] = MetricPattern9(client, f'{base_path}_price_high_in_cents') - self.price_low: MetricPattern1[Dollars] = MetricPattern1(client, f'{base_path}_price_low') - self.price_low_in_cents: MetricPattern9[Cents] = MetricPattern9(client, f'{base_path}_price_low_in_cents') + self.price_close_in_cents: MetricPattern10[Cents] = MetricPattern10(client, f'{base_path}_price_close_in_cents') + self.price_high: PriceHighInSatsPattern[Dollars] = PriceHighInSatsPattern(client, 'price_high') + self.price_high_in_cents: MetricPattern10[Cents] = MetricPattern10(client, f'{base_path}_price_high_in_cents') + self.price_low: PriceLowInSatsPattern[Dollars] = PriceLowInSatsPattern(client, 'price_low') + self.price_low_in_cents: MetricPattern10[Cents] = MetricPattern10(client, f'{base_path}_price_low_in_cents') self.price_ohlc: MetricPattern1[OHLCDollars] = MetricPattern1(client, f'{base_path}_price_ohlc') self.price_open: MetricPattern1[Dollars] = MetricPattern1(client, f'{base_path}_price_open') - self.price_open_in_cents: MetricPattern9[Cents] = MetricPattern9(client, f'{base_path}_price_open_in_cents') + self.price_open_in_cents: MetricPattern10[Cents] = MetricPattern10(client, f'{base_path}_price_open_in_cents') class CatalogTree_Computed_Scripts: """Catalog tree node.""" @@ -3871,46 +3974,27 @@ class CatalogTree_Computed_Scripts_Count: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.emptyoutput_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'emptyoutput_count') - self.opreturn_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'opreturn_count') - self.p2a_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2a_count') - self.p2ms_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2ms_count') - self.p2pk33_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2pk33_count') - self.p2pk65_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2pk65_count') - self.p2pkh_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2pkh_count') - self.p2sh_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2sh_count') - self.p2tr_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2tr_count') - self.p2wpkh_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2wpkh_count') - self.p2wsh_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'p2wsh_count') - self.segwit_adoption: SegwitAdoptionPattern[StoredF32] = SegwitAdoptionPattern(client, 'segwit_adoption') - self.segwit_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'segwit_count') - self.taproot_adoption: SegwitAdoptionPattern[StoredF32] = SegwitAdoptionPattern(client, 'taproot_adoption') - self.unknownoutput_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'unknownoutput_count') + self.emptyoutput_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'emptyoutput_count') + self.opreturn_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'opreturn_count') + self.p2a_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2a_count') + self.p2ms_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2ms_count') + self.p2pk33_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2pk33_count') + self.p2pk65_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2pk65_count') + self.p2pkh_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2pkh_count') + self.p2sh_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2sh_count') + self.p2tr_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2tr_count') + self.p2wpkh_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2wpkh_count') + self.p2wsh_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'p2wsh_count') + self.segwit_adoption: BlockCountPattern[StoredF32] = BlockCountPattern(client, 'segwit_adoption') + self.segwit_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'segwit_count') + self.taproot_adoption: BlockCountPattern[StoredF32] = BlockCountPattern(client, 'taproot_adoption') + self.unknownoutput_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'unknownoutput_count') class CatalogTree_Computed_Scripts_Value: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.opreturn_value: CatalogTree_Computed_Scripts_Value_OpreturnValue = CatalogTree_Computed_Scripts_Value_OpreturnValue(client, f'{base_path}_opreturn_value') - -class CatalogTree_Computed_Scripts_Value_OpreturnValue: - """Catalog tree node.""" - - def __init__(self, client: BrkClientBase, base_path: str = ''): - self.base: MetricPattern25[Sats] = MetricPattern25(client, f'{base_path}_base') - self.bitcoin: SegwitAdoptionPattern[Bitcoin] = SegwitAdoptionPattern(client, 'opreturn_value_btc') - self.dollars: SegwitAdoptionPattern[Dollars] = SegwitAdoptionPattern(client, 'opreturn_value_usd') - self.sats: CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats = CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats(client, f'{base_path}_sats') - -class CatalogTree_Computed_Scripts_Value_OpreturnValue_Sats: - """Catalog tree node.""" - - def __init__(self, client: BrkClientBase, base_path: str = ''): - self.average: MetricPattern2[Sats] = MetricPattern2(client, f'{base_path}_average') - self.cumulative: MetricPattern1[Sats] = MetricPattern1(client, f'{base_path}_cumulative') - self.max: MetricPattern2[Sats] = MetricPattern2(client, f'{base_path}_max') - self.min: MetricPattern2[Sats] = MetricPattern2(client, f'{base_path}_min') - self.sum: MetricPattern2[Sats] = MetricPattern2(client, f'{base_path}_sum') + self.opreturn_value: CoinbasePattern = CoinbasePattern(client, 'opreturn_value') class CatalogTree_Computed_Supply: """Catalog tree node.""" @@ -3926,37 +4010,37 @@ class CatalogTree_Computed_Supply_Burned: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.opreturn: OpreturnPattern = OpreturnPattern(client, 'opreturn_supply') - self.unspendable: OpreturnPattern = OpreturnPattern(client, 'unspendable_supply') + self.opreturn: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, 'opreturn_supply') + self.unspendable: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, 'unspendable_supply') class CatalogTree_Computed_Supply_Circulating: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.btc: MetricPattern25[Bitcoin] = MetricPattern25(client, f'{base_path}_btc') + self.btc: MetricPattern26[Bitcoin] = MetricPattern26(client, f'{base_path}_btc') self.indexes: ActiveSupplyPattern = ActiveSupplyPattern(client, 'circulating') - self.sats: MetricPattern25[Sats] = MetricPattern25(client, f'{base_path}_sats') - self.usd: MetricPattern25[Dollars] = MetricPattern25(client, f'{base_path}_usd') + self.sats: MetricPattern26[Sats] = MetricPattern26(client, f'{base_path}_sats') + self.usd: MetricPattern26[Dollars] = MetricPattern26(client, f'{base_path}_usd') class CatalogTree_Computed_Supply_Inflation: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.indexes: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_indexes') + self.indexes: IndexesPattern2[StoredF32] = IndexesPattern2(client, 'inflation_rate') class CatalogTree_Computed_Supply_MarketCap: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.height: MetricPattern25[Dollars] = MetricPattern25(client, f'{base_path}_height') - self.indexes: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_indexes') + self.height: MetricPattern26[Dollars] = MetricPattern26(client, f'{base_path}_height') + self.indexes: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_indexes') class CatalogTree_Computed_Supply_Velocity: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.btc: MetricPattern4[StoredF64] = MetricPattern4(client, f'{base_path}_btc') - self.usd: MetricPattern4[StoredF64] = MetricPattern4(client, f'{base_path}_usd') + self.btc: IndexesPattern2[StoredF64] = IndexesPattern2(client, 'btc_velocity') + self.usd: IndexesPattern2[StoredF64] = IndexesPattern2(client, 'usd_velocity') class CatalogTree_Computed_Transactions: """Catalog tree node.""" @@ -3972,8 +4056,8 @@ class CatalogTree_Computed_Transactions_Count: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.is_coinbase: MetricPattern38[StoredBool] = MetricPattern38(client, f'{base_path}_is_coinbase') - self.tx_count: BitcoinPattern[StoredU64] = BitcoinPattern(client, 'tx_count') + self.is_coinbase: MetricPattern39[StoredBool] = MetricPattern39(client, f'{base_path}_is_coinbase') + self.tx_count: DollarsPattern[StoredU64] = DollarsPattern(client, 'tx_count') class CatalogTree_Computed_Transactions_Fees: """Catalog tree node.""" @@ -3981,33 +4065,37 @@ class CatalogTree_Computed_Transactions_Fees: def __init__(self, client: BrkClientBase, base_path: str = ''): self.fee: CatalogTree_Computed_Transactions_Fees_Fee = CatalogTree_Computed_Transactions_Fees_Fee(client, f'{base_path}_fee') self.fee_rate: CatalogTree_Computed_Transactions_Fees_FeeRate = CatalogTree_Computed_Transactions_Fees_FeeRate(client, f'{base_path}_fee_rate') - self.input_value: MetricPattern38[Sats] = MetricPattern38(client, f'{base_path}_input_value') - self.output_value: MetricPattern38[Sats] = MetricPattern38(client, f'{base_path}_output_value') + self.input_value: MetricPattern39[Sats] = MetricPattern39(client, f'{base_path}_input_value') + self.output_value: MetricPattern39[Sats] = MetricPattern39(client, f'{base_path}_output_value') class CatalogTree_Computed_Transactions_Fees_Fee: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.base: MetricPattern38[Sats] = MetricPattern38(client, f'{base_path}_base') - self.bitcoin: BlockSizePattern[Bitcoin] = BlockSizePattern(client, 'fee_btc') - self.bitcoin_txindex: MetricPattern38[Bitcoin] = MetricPattern38(client, f'{base_path}_bitcoin_txindex') - self.dollars: BlockSizePattern[Dollars] = BlockSizePattern(client, 'fee_usd') - self.dollars_txindex: MetricPattern38[Dollars] = MetricPattern38(client, f'{base_path}_dollars_txindex') - self.sats: BlockSizePattern[Sats] = BlockSizePattern(client, 'fee') + self.base: MetricPattern39[Sats] = MetricPattern39(client, f'{base_path}_base') + self.bitcoin: CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin = CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin(client, f'{base_path}_bitcoin') + self.dollars: CountPattern2[Dollars] = CountPattern2(client, 'fee_usd') + self.sats: CountPattern2[Sats] = CountPattern2(client, 'fee') + +class CatalogTree_Computed_Transactions_Fees_Fee_Bitcoin: + """Catalog tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self.average: MetricPattern1[Bitcoin] = MetricPattern1(client, f'{base_path}_average') + self.cumulative: MetricPattern1[Bitcoin] = MetricPattern1(client, f'{base_path}_cumulative') + self.max: MetricPattern1[Bitcoin] = MetricPattern1(client, f'{base_path}_max') + self.min: MetricPattern1[Bitcoin] = MetricPattern1(client, f'{base_path}_min') + self.sum: MetricPattern1[Bitcoin] = MetricPattern1(client, f'{base_path}_sum') class CatalogTree_Computed_Transactions_Fees_FeeRate: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): self.average: MetricPattern1[FeeRate] = MetricPattern1(client, f'{base_path}_average') - self.base: MetricPattern38[FeeRate] = MetricPattern38(client, f'{base_path}_base') + self.base: MetricPattern39[FeeRate] = MetricPattern39(client, f'{base_path}_base') self.max: MetricPattern1[FeeRate] = MetricPattern1(client, f'{base_path}_max') - self.median: MetricPattern25[FeeRate] = MetricPattern25(client, f'{base_path}_median') self.min: MetricPattern1[FeeRate] = MetricPattern1(client, f'{base_path}_min') - self.pct10: MetricPattern25[FeeRate] = MetricPattern25(client, f'{base_path}_pct10') - self.pct25: MetricPattern25[FeeRate] = MetricPattern25(client, f'{base_path}_pct25') - self.pct75: MetricPattern25[FeeRate] = MetricPattern25(client, f'{base_path}_pct75') - self.pct90: MetricPattern25[FeeRate] = MetricPattern25(client, f'{base_path}_pct90') + self.percentiles: PercentilesPattern[FeeRate] = PercentilesPattern(client, 'fee_rate') class CatalogTree_Computed_Transactions_Size: """Catalog tree node.""" @@ -4015,8 +4103,8 @@ class CatalogTree_Computed_Transactions_Size: def __init__(self, client: BrkClientBase, base_path: str = ''): self.tx_vsize: BlockIntervalPattern[VSize] = BlockIntervalPattern(client, 'tx_vsize') self.tx_weight: BlockIntervalPattern[Weight] = BlockIntervalPattern(client, 'tx_weight') - self.vsize: MetricPattern38[VSize] = MetricPattern38(client, f'{base_path}_vsize') - self.weight: MetricPattern38[Weight] = MetricPattern38(client, f'{base_path}_weight') + self.vsize: MetricPattern39[VSize] = MetricPattern39(client, f'{base_path}_vsize') + self.weight: MetricPattern39[Weight] = MetricPattern39(client, f'{base_path}_weight') class CatalogTree_Computed_Transactions_Versions: """Catalog tree node.""" @@ -4030,21 +4118,21 @@ class CatalogTree_Computed_Transactions_Volume: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.annualized_volume: MetricPattern4[Sats] = MetricPattern4(client, f'{base_path}_annualized_volume') - self.annualized_volume_btc: MetricPattern4[Bitcoin] = MetricPattern4(client, f'{base_path}_annualized_volume_btc') - self.annualized_volume_usd: MetricPattern4[Dollars] = MetricPattern4(client, f'{base_path}_annualized_volume_usd') - self.inputs_per_sec: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_inputs_per_sec') - self.outputs_per_sec: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_outputs_per_sec') + self.annualized_volume: MetricPattern5[Sats] = MetricPattern5(client, f'{base_path}_annualized_volume') + self.annualized_volume_btc: MetricPattern5[Bitcoin] = MetricPattern5(client, f'{base_path}_annualized_volume_btc') + self.annualized_volume_usd: MetricPattern5[Dollars] = MetricPattern5(client, f'{base_path}_annualized_volume_usd') + self.inputs_per_sec: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_inputs_per_sec') + self.outputs_per_sec: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_outputs_per_sec') self.sent_sum: CatalogTree_Computed_Transactions_Volume_SentSum = CatalogTree_Computed_Transactions_Volume_SentSum(client, f'{base_path}_sent_sum') - self.tx_per_sec: MetricPattern4[StoredF32] = MetricPattern4(client, f'{base_path}_tx_per_sec') + self.tx_per_sec: MetricPattern5[StoredF32] = MetricPattern5(client, f'{base_path}_tx_per_sec') class CatalogTree_Computed_Transactions_Volume_SentSum: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.bitcoin: TotalRealizedPnlPattern[Bitcoin] = TotalRealizedPnlPattern(client, 'sent_sum_btc') - self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, f'{base_path}_dollars') - self.sats: MetricPattern1[Sats] = MetricPattern1(client, f'{base_path}_sats') + self.bitcoin: MetricPattern1[Bitcoin] = MetricPattern1(client, f'{base_path}_bitcoin') + self.dollars: DifficultyAdjustmentPattern[Dollars] = DifficultyAdjustmentPattern(client, 'sent_sum_usd') + self.sats: DifficultyAdjustmentPattern[Sats] = DifficultyAdjustmentPattern(client, 'sent_sum') class CatalogTree_Indexed: """Catalog tree node.""" @@ -4061,82 +4149,82 @@ class CatalogTree_Indexed_Address: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.first_p2aaddressindex: MetricPattern25[P2AAddressIndex] = MetricPattern25(client, f'{base_path}_first_p2aaddressindex') - self.first_p2pk33addressindex: MetricPattern25[P2PK33AddressIndex] = MetricPattern25(client, f'{base_path}_first_p2pk33addressindex') - self.first_p2pk65addressindex: MetricPattern25[P2PK65AddressIndex] = MetricPattern25(client, f'{base_path}_first_p2pk65addressindex') - self.first_p2pkhaddressindex: MetricPattern25[P2PKHAddressIndex] = MetricPattern25(client, f'{base_path}_first_p2pkhaddressindex') - self.first_p2shaddressindex: MetricPattern25[P2SHAddressIndex] = MetricPattern25(client, f'{base_path}_first_p2shaddressindex') - self.first_p2traddressindex: MetricPattern25[P2TRAddressIndex] = MetricPattern25(client, f'{base_path}_first_p2traddressindex') - self.first_p2wpkhaddressindex: MetricPattern25[P2WPKHAddressIndex] = MetricPattern25(client, f'{base_path}_first_p2wpkhaddressindex') - self.first_p2wshaddressindex: MetricPattern25[P2WSHAddressIndex] = MetricPattern25(client, f'{base_path}_first_p2wshaddressindex') - self.p2abytes: MetricPattern29[P2ABytes] = MetricPattern29(client, f'{base_path}_p2abytes') - self.p2pk33bytes: MetricPattern31[P2PK33Bytes] = MetricPattern31(client, f'{base_path}_p2pk33bytes') - self.p2pk65bytes: MetricPattern32[P2PK65Bytes] = MetricPattern32(client, f'{base_path}_p2pk65bytes') - self.p2pkhbytes: MetricPattern33[P2PKHBytes] = MetricPattern33(client, f'{base_path}_p2pkhbytes') - self.p2shbytes: MetricPattern34[P2SHBytes] = MetricPattern34(client, f'{base_path}_p2shbytes') - self.p2trbytes: MetricPattern35[P2TRBytes] = MetricPattern35(client, f'{base_path}_p2trbytes') - self.p2wpkhbytes: MetricPattern36[P2WPKHBytes] = MetricPattern36(client, f'{base_path}_p2wpkhbytes') - self.p2wshbytes: MetricPattern37[P2WSHBytes] = MetricPattern37(client, f'{base_path}_p2wshbytes') + self.first_p2aaddressindex: MetricPattern26[P2AAddressIndex] = MetricPattern26(client, f'{base_path}_first_p2aaddressindex') + self.first_p2pk33addressindex: MetricPattern26[P2PK33AddressIndex] = MetricPattern26(client, f'{base_path}_first_p2pk33addressindex') + self.first_p2pk65addressindex: MetricPattern26[P2PK65AddressIndex] = MetricPattern26(client, f'{base_path}_first_p2pk65addressindex') + self.first_p2pkhaddressindex: MetricPattern26[P2PKHAddressIndex] = MetricPattern26(client, f'{base_path}_first_p2pkhaddressindex') + self.first_p2shaddressindex: MetricPattern26[P2SHAddressIndex] = MetricPattern26(client, f'{base_path}_first_p2shaddressindex') + self.first_p2traddressindex: MetricPattern26[P2TRAddressIndex] = MetricPattern26(client, f'{base_path}_first_p2traddressindex') + self.first_p2wpkhaddressindex: MetricPattern26[P2WPKHAddressIndex] = MetricPattern26(client, f'{base_path}_first_p2wpkhaddressindex') + self.first_p2wshaddressindex: MetricPattern26[P2WSHAddressIndex] = MetricPattern26(client, f'{base_path}_first_p2wshaddressindex') + self.p2abytes: MetricPattern30[P2ABytes] = MetricPattern30(client, f'{base_path}_p2abytes') + self.p2pk33bytes: MetricPattern32[P2PK33Bytes] = MetricPattern32(client, f'{base_path}_p2pk33bytes') + self.p2pk65bytes: MetricPattern33[P2PK65Bytes] = MetricPattern33(client, f'{base_path}_p2pk65bytes') + self.p2pkhbytes: MetricPattern34[P2PKHBytes] = MetricPattern34(client, f'{base_path}_p2pkhbytes') + self.p2shbytes: MetricPattern35[P2SHBytes] = MetricPattern35(client, f'{base_path}_p2shbytes') + self.p2trbytes: MetricPattern36[P2TRBytes] = MetricPattern36(client, f'{base_path}_p2trbytes') + self.p2wpkhbytes: MetricPattern37[P2WPKHBytes] = MetricPattern37(client, f'{base_path}_p2wpkhbytes') + self.p2wshbytes: MetricPattern38[P2WSHBytes] = MetricPattern38(client, f'{base_path}_p2wshbytes') class CatalogTree_Indexed_Block: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.blockhash: MetricPattern25[BlockHash] = MetricPattern25(client, f'{base_path}_blockhash') - self.difficulty: MetricPattern25[StoredF64] = MetricPattern25(client, f'{base_path}_difficulty') - self.timestamp: MetricPattern25[Timestamp] = MetricPattern25(client, f'{base_path}_timestamp') - self.total_size: MetricPattern25[StoredU64] = MetricPattern25(client, f'{base_path}_total_size') - self.weight: MetricPattern25[Weight] = MetricPattern25(client, f'{base_path}_weight') + self.blockhash: MetricPattern26[BlockHash] = MetricPattern26(client, f'{base_path}_blockhash') + self.difficulty: MetricPattern26[StoredF64] = MetricPattern26(client, f'{base_path}_difficulty') + self.timestamp: MetricPattern26[Timestamp] = MetricPattern26(client, f'{base_path}_timestamp') + self.total_size: MetricPattern26[StoredU64] = MetricPattern26(client, f'{base_path}_total_size') + self.weight: MetricPattern26[Weight] = MetricPattern26(client, f'{base_path}_weight') class CatalogTree_Indexed_Output: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.first_emptyoutputindex: MetricPattern25[EmptyOutputIndex] = MetricPattern25(client, f'{base_path}_first_emptyoutputindex') - self.first_opreturnindex: MetricPattern25[OpReturnIndex] = MetricPattern25(client, f'{base_path}_first_opreturnindex') - self.first_p2msoutputindex: MetricPattern25[P2MSOutputIndex] = MetricPattern25(client, f'{base_path}_first_p2msoutputindex') - self.first_unknownoutputindex: MetricPattern25[UnknownOutputIndex] = MetricPattern25(client, f'{base_path}_first_unknownoutputindex') - self.txindex: MetricPattern7[TxIndex] = MetricPattern7(client, f'{base_path}_txindex') + self.first_emptyoutputindex: MetricPattern26[EmptyOutputIndex] = MetricPattern26(client, f'{base_path}_first_emptyoutputindex') + self.first_opreturnindex: MetricPattern26[OpReturnIndex] = MetricPattern26(client, f'{base_path}_first_opreturnindex') + self.first_p2msoutputindex: MetricPattern26[P2MSOutputIndex] = MetricPattern26(client, f'{base_path}_first_p2msoutputindex') + self.first_unknownoutputindex: MetricPattern26[UnknownOutputIndex] = MetricPattern26(client, f'{base_path}_first_unknownoutputindex') + self.txindex: MetricPattern8[TxIndex] = MetricPattern8(client, f'{base_path}_txindex') class CatalogTree_Indexed_Tx: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.base_size: MetricPattern38[StoredU32] = MetricPattern38(client, f'{base_path}_base_size') - self.first_txindex: MetricPattern25[TxIndex] = MetricPattern25(client, f'{base_path}_first_txindex') - self.first_txinindex: MetricPattern38[TxInIndex] = MetricPattern38(client, f'{base_path}_first_txinindex') - self.first_txoutindex: MetricPattern38[TxOutIndex] = MetricPattern38(client, f'{base_path}_first_txoutindex') - self.height: MetricPattern38[Height] = MetricPattern38(client, f'{base_path}_height') - self.is_explicitly_rbf: MetricPattern38[StoredBool] = MetricPattern38(client, f'{base_path}_is_explicitly_rbf') - self.rawlocktime: MetricPattern38[RawLockTime] = MetricPattern38(client, f'{base_path}_rawlocktime') - self.total_size: MetricPattern38[StoredU32] = MetricPattern38(client, f'{base_path}_total_size') - self.txid: MetricPattern38[Txid] = MetricPattern38(client, f'{base_path}_txid') - self.txversion: MetricPattern38[TxVersion] = MetricPattern38(client, f'{base_path}_txversion') + self.base_size: MetricPattern39[StoredU32] = MetricPattern39(client, f'{base_path}_base_size') + self.first_txindex: MetricPattern26[TxIndex] = MetricPattern26(client, f'{base_path}_first_txindex') + self.first_txinindex: MetricPattern39[TxInIndex] = MetricPattern39(client, f'{base_path}_first_txinindex') + self.first_txoutindex: MetricPattern39[TxOutIndex] = MetricPattern39(client, f'{base_path}_first_txoutindex') + self.height: MetricPattern39[Height] = MetricPattern39(client, f'{base_path}_height') + self.is_explicitly_rbf: MetricPattern39[StoredBool] = MetricPattern39(client, f'{base_path}_is_explicitly_rbf') + self.rawlocktime: MetricPattern39[RawLockTime] = MetricPattern39(client, f'{base_path}_rawlocktime') + self.total_size: MetricPattern39[StoredU32] = MetricPattern39(client, f'{base_path}_total_size') + self.txid: MetricPattern39[Txid] = MetricPattern39(client, f'{base_path}_txid') + self.txversion: MetricPattern39[TxVersion] = MetricPattern39(client, f'{base_path}_txversion') class CatalogTree_Indexed_Txin: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.first_txinindex: MetricPattern25[TxInIndex] = MetricPattern25(client, f'{base_path}_first_txinindex') - self.outpoint: MetricPattern26[OutPoint] = MetricPattern26(client, f'{base_path}_outpoint') - self.outputtype: MetricPattern26[OutputType] = MetricPattern26(client, f'{base_path}_outputtype') - self.txindex: MetricPattern26[TxIndex] = MetricPattern26(client, f'{base_path}_txindex') - self.typeindex: MetricPattern26[TypeIndex] = MetricPattern26(client, f'{base_path}_typeindex') + self.first_txinindex: MetricPattern26[TxInIndex] = MetricPattern26(client, f'{base_path}_first_txinindex') + self.outpoint: MetricPattern27[OutPoint] = MetricPattern27(client, f'{base_path}_outpoint') + self.outputtype: MetricPattern27[OutputType] = MetricPattern27(client, f'{base_path}_outputtype') + self.txindex: MetricPattern27[TxIndex] = MetricPattern27(client, f'{base_path}_txindex') + self.typeindex: MetricPattern27[TypeIndex] = MetricPattern27(client, f'{base_path}_typeindex') class CatalogTree_Indexed_Txout: """Catalog tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.first_txoutindex: MetricPattern25[TxOutIndex] = MetricPattern25(client, f'{base_path}_first_txoutindex') - self.outputtype: MetricPattern28[OutputType] = MetricPattern28(client, f'{base_path}_outputtype') - self.txindex: MetricPattern28[TxIndex] = MetricPattern28(client, f'{base_path}_txindex') - self.typeindex: MetricPattern28[TypeIndex] = MetricPattern28(client, f'{base_path}_typeindex') - self.value: MetricPattern28[Sats] = MetricPattern28(client, f'{base_path}_value') + self.first_txoutindex: MetricPattern26[TxOutIndex] = MetricPattern26(client, f'{base_path}_first_txoutindex') + self.outputtype: MetricPattern29[OutputType] = MetricPattern29(client, f'{base_path}_outputtype') + self.txindex: MetricPattern29[TxIndex] = MetricPattern29(client, f'{base_path}_txindex') + self.typeindex: MetricPattern29[TypeIndex] = MetricPattern29(client, f'{base_path}_typeindex') + self.value: MetricPattern29[Sats] = MetricPattern29(client, f'{base_path}_value') class BrkClient(BrkClientBase): """Main BRK client with catalog tree and API methods.""" - VERSION = "v0.1.0-alpha.1" + VERSION = "v0.1.0-alpha.2" INDEXES = [ "dateindex", @@ -5143,7 +5231,7 @@ class BrkClient(BrkClientBase): Returns the list of indexes are supported by the specified metric. For example, `realized_price` might be available on dateindex, weekindex, and monthindex.""" return self.get(f'/api/metric/{metric}') - def get_metric_by_index(self, metric: Metric, index: Index, from_: Optional[Any] = None, to: Optional[Any] = None, count: Optional[Any] = None, format: Optional[Format] = None) -> MetricData: + def get_metric_by_index(self, metric: Metric, index: Index, from_: Optional[Any] = None, to: Optional[Any] = None, count: Optional[Any] = None, format: Optional[Format] = None) -> AnyMetricData: """Get metric data. Fetch data for a specific metric at the given index. Use query parameters to filter by date range and format (json/csv).""" @@ -5155,7 +5243,7 @@ class BrkClient(BrkClientBase): query = '&'.join(params) return self.get(f'/api/metric/{metric}/{index}{"?" + query if query else ""}') - def get_metrics_bulk(self, metrics: Metrics, index: Index, from_: Optional[Any] = None, to: Optional[Any] = None, count: Optional[Any] = None, format: Optional[Format] = None) -> List[MetricData]: + def get_metrics_bulk(self, metrics: Metrics, index: Index, from_: Optional[Any] = None, to: Optional[Any] = None, count: Optional[Any] = None, format: Optional[Format] = None) -> List[AnyMetricData]: """Bulk metric data. Fetch multiple metrics in a single request. Supports filtering by index and date range. Returns an array of MetricData objects.""" diff --git a/websites/bitview/scripts/chart/index.js b/websites/bitview/scripts/chart/index.js index 168533cfd..1481a2dc6 100644 --- a/websites/bitview/scripts/chart/index.js +++ b/websites/bitview/scripts/chart/index.js @@ -13,12 +13,12 @@ import { createHorizontalChoiceField, createLabeledInput, createSpanName, -} from "../utils/dom"; -import { createOklchToRGBA } from "./oklch"; -import { throttle } from "../utils/timing"; -import { serdeBool } from "../utils/serde"; -import { stringToId } from "../utils/format"; -import { style } from "../utils/elements"; +} from "../utils/dom.js"; +import { createOklchToRGBA } from "./oklch.js"; +import { throttle } from "../utils/timing.js"; +import { serdeBool } from "../utils/serde.js"; +import { stringToId } from "../utils/format.js"; +import { style } from "../utils/elements.js"; /** * @typedef {Object} Valued @@ -52,7 +52,12 @@ import { style } from "../utils/elements"; * @typedef {_BaselineData} BaselineData * @typedef {_HistogramData} HistogramData * - * @typedef {function({ iseries: ISeries; unit: Unit; index: IndexName }): void} SetDataCallback + * @typedef {function({ iseries: ISeries; unit: Unit; index: ChartableIndex }): void} SetDataCallback + * + * @typedef {Object} Legend + * @property {HTMLLegendElement} element + * @property {function({ series: Series, name: string, order: number, colors: Color[] }): void} addOrReplace + * @property {function(number): void} removeFrom */ const oklchToRGBA = createOklchToRGBA(); @@ -67,7 +72,7 @@ const lineWidth = /** @type {any} */ (1.5); * @param {Colors} args.colors * @param {Resources} args.resources * @param {BrkClient} args.brk - * @param {Accessor} args.index + * @param {Accessor} args.index * @param {((unknownTimeScaleCallback: VoidFunction) => void)} [args.timeScaleSetCallback] * @param {true} [args.fitContent] * @param {{unit: Unit; blueprints: AnySeriesBlueprint[]}[]} [args.config] @@ -191,10 +196,7 @@ function createChartElement({ ichart.applyOptions({ timeScale: { - timeVisible: - index === "height" || - index === "difficultyepoch" || - index === "halvingepoch", + timeVisible: index === "height", ...(!fitContent ? { minBarSpacing, @@ -288,7 +290,7 @@ function createChartElement({ choices: /** @type {const} */ (["lin", "log"]), id: stringToId(`${id} ${paneIndex} ${unit}`), defaultValue: - unit === "usd" && seriesType !== "Baseline" ? "log" : "lin", + unit.id === "usd" && seriesType !== "Baseline" ? "log" : "lin", key: `${id}-price-scale-${paneIndex}`, signals, }); @@ -379,17 +381,20 @@ function createChartElement({ signals.createEffect(index, (index) => { // Get timestamp metric from tree based on index type // timestampFixed has height only, timestamp has date-based indexes + /** @type {AnyMetricPattern} */ const timeMetric = index === "height" ? brk.tree.computed.blocks.time.timestampFixed : brk.tree.computed.blocks.time.timestamp; + /** @type {AnyMetricPattern} */ + const valuesMetric = metric; const timeNode = timeMetric.by[index]; - const valuesNode = metric.by[index]; + const valuesNode = valuesMetric.by[index]; if (!timeNode || !valuesNode) throw new Error(`Missing node for index: ${index}`); - const timeResource = resources.useMetricNode(timeNode); - const valuesResource = resources.useMetricNode(valuesNode); + const timeResource = resources.useMetricEndpoint(timeNode); + const valuesResource = resources.useMetricEndpoint(valuesNode); _valuesResource = valuesResource; series.url.set(() => `${brk.baseUrl}${valuesResource.path}`); @@ -706,7 +711,7 @@ function createChartElement({ data, options, }) { - color ||= unit === "usd" ? colors.green : colors.orange; + color ||= unit.id === "usd" ? colors.green : colors.orange; /** @type {LineISeries} */ const iseries = /** @type {any} */ ( diff --git a/websites/bitview/scripts/entry.js b/websites/bitview/scripts/entry.js index 4981f4f44..70e3db4d1 100644 --- a/websites/bitview/scripts/entry.js +++ b/websites/bitview/scripts/entry.js @@ -1,23 +1,23 @@ /** * @import * as _ from "./modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.d.ts" * - * @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType as LCSeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData, createChart as CreateChart, LineStyle } from './modules/lightweight-charts/5.0.9/dist/typings' + * @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType as LCSeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData, createChart as CreateChart, LineStyle } from './modules/lightweight-charts/5.0.9/dist/typings.js' * - * @import { Signal, Signals, Accessor } from "./signals"; + * @import { Signal, Signals, Accessor } from "./signals.js"; * - * @import { BrkClient, CatalogTree_Computed_Distribution_UtxoCohorts as UtxoCohortTree, CatalogTree_Computed_Distribution_AddressCohorts as AddressCohortTree, CatalogTree_Computed_Distribution_UtxoCohorts_All as AllUtxoPattern, UpTo1dPattern as MaxAgePattern, _10yTo12yPattern as MinAgePattern, _0satsPattern2 as UtxoAmountPattern, _0satsPattern as AddressAmountPattern, Ratio1ySdPattern, Dollars, Price111dSmaPattern as EmaRatioPattern, Index, BlockCountPattern, BitcoinPattern, BlockSizePattern, BlockIntervalPattern, CoinbasePattern, ActivePriceRatioPattern, _0satsPattern, UnclaimedRewardsPattern as ValuePattern, SentPattern as RewardPattern, Metric, MetricPattern, AnyMetricPattern } from "./modules/brk-client/index.js" + * @import { BrkClient, CatalogTree_Computed_Distribution_UtxoCohorts as UtxoCohortTree, CatalogTree_Computed_Distribution_AddressCohorts as AddressCohortTree, CatalogTree_Computed_Distribution_UtxoCohorts_All as AllUtxoPattern, _10yTo12yPattern as MinAgePattern, _0satsPattern2 as UtxoAmountPattern, _0satsPattern as AddressAmountPattern, Ratio1ySdPattern, Dollars, Price111dSmaPattern as EmaRatioPattern, Index, BlockCountPattern, BitcoinPattern, BlockSizePattern, BlockIntervalPattern, CoinbasePattern, ActivePriceRatioPattern, _0satsPattern, UnclaimedRewardsPattern as ValuePattern, SentPattern as RewardPattern, Metric, MetricPattern, AnyMetricPattern, MetricEndpoint, MetricData, AnyMetricEndpoint, AnyMetricData, DollarsPattern, CountPattern2 } from "./modules/brk-client/index.js" * - * @import { Resources, MetricResource } from './resources' + * @import { Resources, MetricResource } from './resources.js' * - * @import { Valued, SingleValueData, CandlestickData, Series, ISeries, HistogramData, LineData, BaselineData, LineSeriesPartialOptions, BaselineSeriesPartialOptions, HistogramSeriesPartialOptions, CandlestickSeriesPartialOptions, CreateChartElement, Chart } from "./chart/index" + * @import { Valued, SingleValueData, CandlestickData, Series, ISeries, HistogramData, LineData, BaselineData, LineSeriesPartialOptions, BaselineSeriesPartialOptions, HistogramSeriesPartialOptions, CandlestickSeriesPartialOptions, CreateChartElement, Chart, Legend } from "./chart/index.js" * - * @import { Color, ColorName, Colors } from "./utils/colors" + * @import { Color, ColorName, Colors } from "./utils/colors.js" * - * @import { WebSockets } from "./utils/ws" + * @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, UtxoCohortGroupObject, AddressCohortGroupObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, AgeCohortObject, AmountCohortObject, AgeCohortGroupObject, AmountCohortGroupObject } from "./options/partial/index.js" + * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, UtxoCohortGroupObject, AddressCohortGroupObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, AgeCohortObject, AmountCohortObject, AgeCohortGroupObject, AmountCohortGroupObject } from "./options/partial.js" * - * @import { Unit } from "./utils/serde" + * @import { UnitObject as Unit } from "./utils/units.js" * * @import { ChartableIndexName } from "./panes/chart/index.js"; */ @@ -34,7 +34,7 @@ * @typedef {keyof PoolIdToPoolName} PoolId * * Pattern unions by cohort type - * @typedef {AllUtxoPattern | MaxAgePattern | MinAgePattern | UtxoAmountPattern} UtxoCohortPattern + * @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} UtxoCohortPattern * @typedef {AddressAmountPattern} AddressCohortPattern * @typedef {UtxoCohortPattern | AddressCohortPattern} CohortPattern * @@ -44,7 +44,7 @@ * @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithNupl * @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithCostBasis * @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithActivity - * @typedef {AllUtxoPattern | MaxAgePattern | MinAgePattern} PatternWithCostBasisPercentiles + * @typedef {AllUtxoPattern | MinAgePattern} PatternWithCostBasisPercentiles * * Cohort objects with specific pattern capabilities * @typedef {{ name: string, title: string, color: Color, tree: PatternWithRealizedPrice }} CohortWithRealizedPrice @@ -61,6 +61,9 @@ * * Generic tree node type for walking * @typedef {AnyMetricPattern | Record} TreeNode + * + * Chartable index IDs (subset of IndexName that can be charted) + * @typedef {"height" | "dateindex" | "weekindex" | "monthindex" | "quarterindex" | "semesterindex" | "yearindex" | "decadeindex"} ChartableIndex */ // DO NOT CHANGE, Exact format is expected in `brk_bundler` diff --git a/websites/bitview/scripts/main.js b/websites/bitview/scripts/main.js index 9e59f3ad8..49f9d80e9 100644 --- a/websites/bitview/scripts/main.js +++ b/websites/bitview/scripts/main.js @@ -1,11 +1,11 @@ -import { createColors } from "./utils/colors"; -import { createWebSockets } from "./utils/ws"; -import * as formatters from "./utils/format"; -import modules from "./lazy"; -import { onFirstIntersection, getElementById, isHidden } from "./utils/dom"; -import { next } from "./utils/timing"; -import { replaceHistory } from "./utils/url"; -import { removeStored, writeToStorage } from "./utils/storage"; +import { createColors } from "./utils/colors.js"; +import { createWebSockets } from "./utils/ws.js"; +import * as formatters from "./utils/format.js"; +import modules from "./lazy.js"; +import { onFirstIntersection, getElementById, isHidden } from "./utils/dom.js"; +import { next } from "./utils/timing.js"; +import { replaceHistory } from "./utils/url.js"; +import { removeStored, writeToStorage } from "./utils/storage.js"; import { asideElement, asideLabelElement, @@ -164,7 +164,7 @@ Promise.all([ qrcode, }); - window.addEventListener("popstate", (event) => { + window.addEventListener("popstate", (_event) => { const path = window.document.location.pathname .split("/") .filter((v) => v); @@ -375,7 +375,6 @@ Promise.all([ await getFirstChild(); if (!ul) throw Error("Unreachable"); - let i = 0; while (path.length > 1) { const name = path.shift(); if (!name) throw "Unreachable"; @@ -440,7 +439,7 @@ Promise.all([ /** @type {{ option: Option, title: string }[]} */ let list = []; - let [indexes, info, order] = searchResult || [null, null, null]; + let [indexes, _info, order] = searchResult || [null, null, null]; const minIndex = pageIndex * RESULTS_PER_PAGE; @@ -577,7 +576,6 @@ Promise.all([ const element = options.createOptionElement({ option, - frame: "search", name: title, qrcode, }); diff --git a/websites/bitview/scripts/options/chain.js b/websites/bitview/scripts/options/chain.js new file mode 100644 index 000000000..4268ed81b --- /dev/null +++ b/websites/bitview/scripts/options/chain.js @@ -0,0 +1,1242 @@ +/** Chain section builder - typed tree-based patterns */ + +import { Unit } from "../utils/units.js"; + +/** + * Create Chain section + * @param {PartialContext} ctx + * @returns {PartialOptionsGroup} + */ +export function createChainSection(ctx) { + const { colors, brk, s, createPriceLine } = ctx; + const { mergeMetricPatterns } = brk; + const { + blocks, + transactions, + pools, + inputs, + outputs, + market, + scripts, + supply, + } = brk.tree.computed; + const { indexed } = brk.tree; + + /** + * Create sum/cumulative series from a BlockCountPattern + * @template T + * @param {BlockCountPattern} pattern + * @param {string} name + * @param {Color} [sumColor] + * @param {Color} [cumulativeColor] + * @param {Unit} unit + */ + const fromBlockCount = (pattern, name, unit, sumColor, cumulativeColor) => [ + s({ + metric: mergeMetricPatterns(pattern.base, pattern.sum), + name: `${name} sum`, + color: sumColor, + unit, + }), + s({ + metric: pattern.cumulative, + name: `${name} cumulative`, + color: cumulativeColor ?? colors.blue, + unit, + defaultActive: false, + }), + ]; + + /** + * Create series from BlockSizePattern (has average, min, max, percentiles) + * @template T + * @param {BlockSizePattern} pattern + * @param {string} name + * @param {Unit} unit + */ + const fromBlockSize = (pattern, name, unit) => [ + s({ metric: pattern.distribution.average, name: `${name} avg`, unit }), + s({ + metric: pattern.sum, + name: `${name} sum`, + color: colors.blue, + unit, + defaultActive: false, + }), + s({ + metric: pattern.cumulative, + name: `${name} cumulative`, + color: colors.indigo, + unit, + defaultActive: false, + }), + s({ + metric: pattern.min, + name: `${name} min`, + color: colors.red, + unit, + defaultActive: false, + }), + s({ + metric: pattern.max, + name: `${name} max`, + color: colors.green, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct10, + name: `${name} pct10`, + color: colors.rose, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct25, + name: `${name} pct25`, + color: colors.pink, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.median, + name: `${name} median`, + color: colors.purple, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct75, + name: `${name} pct75`, + color: colors.violet, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct90, + name: `${name} pct90`, + color: colors.fuchsia, + unit, + defaultActive: false, + }), + ]; + + /** + * Create series from CountPattern2 (has distribution with percentiles, no height index on cumulative) + * @template T + * @param {CountPattern2} pattern + * @param {string} name + * @param {Unit} unit + */ + const fromCountPattern2 = (pattern, name, unit) => [ + s({ metric: pattern.average, name: `${name} Average`, unit }), + s({ + metric: pattern.sum, + name: `${name} sum`, + color: colors.blue, + unit, + defaultActive: false, + }), + s({ + metric: pattern.cumulative, + name: `${name} cumulative`, + color: colors.indigo, + unit, + defaultActive: false, + }), + s({ + metric: pattern.min, + name: `${name} min`, + color: colors.red, + unit, + defaultActive: false, + }), + s({ + metric: pattern.max, + name: `${name} max`, + color: colors.green, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct10, + name: `${name} pct10`, + color: colors.rose, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct25, + name: `${name} pct25`, + color: colors.pink, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.median, + name: `${name} median`, + color: colors.purple, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct75, + name: `${name} pct75`, + color: colors.violet, + unit, + defaultActive: false, + }), + s({ + metric: pattern.distribution.percentiles.pct90, + name: `${name} pct90`, + color: colors.fuchsia, + unit, + defaultActive: false, + }), + ]; + + /** + * Create series from BlockIntervalPattern (has average, min, max, percentiles) + * @template T + * @param {BlockIntervalPattern} pattern + * @param {string} name + * @param {Unit} unit + */ + const fromBlockInterval = (pattern, name, unit) => [ + s({ metric: pattern.average, name: `${name} avg`, unit }), + s({ + metric: pattern.min, + name: `${name} min`, + color: colors.red, + unit, + defaultActive: false, + }), + s({ + metric: pattern.max, + name: `${name} max`, + color: colors.green, + unit, + defaultActive: false, + }), + s({ + metric: pattern.percentiles.pct10, + name: `${name} pct10`, + color: colors.rose, + unit, + defaultActive: false, + }), + s({ + metric: pattern.percentiles.pct25, + name: `${name} pct25`, + color: colors.pink, + unit, + defaultActive: false, + }), + s({ + metric: pattern.percentiles.median, + name: `${name} median`, + color: colors.purple, + unit, + defaultActive: false, + }), + s({ + metric: pattern.percentiles.pct75, + name: `${name} pct75`, + color: colors.violet, + unit, + defaultActive: false, + }), + s({ + metric: pattern.percentiles.pct90, + name: `${name} pct90`, + color: colors.fuchsia, + unit, + defaultActive: false, + }), + ]; + + /** + * Create series from DollarsPattern (has base, cumulative) + * @template T + * @param {DollarsPattern} pattern + * @param {string} name + * @param {Unit} unit + * @param {Color} [sumColor] + * @param {Color} [cumulativeColor] + */ + const fromBitcoin = (pattern, name, unit, sumColor, cumulativeColor) => [ + s({ metric: pattern.base, name: `${name}`, color: sumColor, unit }), + s({ + metric: pattern.cumulative, + name: `${name} cumulative`, + color: cumulativeColor ?? colors.blue, + unit, + defaultActive: false, + }), + ]; + + /** + * Create series from CoinbasePattern (has sats, bitcoin, dollars as BitcoinPattern) + * BitcoinPattern has .base and .cumulative (no .sum) + * @param {CoinbasePattern} pattern + * @param {string} name + * @param {Color} sumColor + * @param {Color} cumulativeColor + */ + const fromCoinbase = (pattern, name, sumColor, cumulativeColor) => [ + s({ + metric: pattern.sats.base, + name: `${name}`, + color: sumColor, + unit: Unit.sats, + }), + s({ + metric: pattern.sats.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.sats, + defaultActive: false, + }), + s({ + metric: pattern.bitcoin.base, + name: `${name}`, + color: sumColor, + unit: Unit.btc, + }), + s({ + metric: pattern.bitcoin.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.btc, + defaultActive: false, + }), + s({ + metric: pattern.dollars.base, + name: `${name}`, + color: sumColor, + unit: Unit.usd, + }), + s({ + metric: pattern.dollars.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.usd, + defaultActive: false, + }), + ]; + + /** + * Create series from ValuePattern (has sats, bitcoin, dollars as BlockCountPattern) + * BlockCountPattern has .base, .sum, and .cumulative + * @param {ValuePattern} pattern + * @param {string} name + * @param {Color} sumColor + * @param {Color} cumulativeColor + */ + const fromValuePattern = (pattern, name, sumColor, cumulativeColor) => [ + s({ + metric: pattern.sats.base, + name: `${name}`, + color: sumColor, + unit: Unit.sats, + }), + s({ + metric: pattern.sats.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.sats, + defaultActive: false, + }), + s({ + metric: pattern.bitcoin.base, + name: `${name}`, + color: sumColor, + unit: Unit.btc, + }), + s({ + metric: pattern.bitcoin.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.btc, + defaultActive: false, + }), + s({ + metric: pattern.dollars.base, + name: `${name}`, + color: sumColor, + unit: Unit.usd, + }), + s({ + metric: pattern.dollars.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.usd, + defaultActive: false, + }), + ]; + + /** + * Create series from RewardPattern (has .base as Indexes2, plus bitcoin/dollars as BlockCountPattern, sats as SatsPattern) + * Note: SatsPattern only has cumulative and sum, so we use pattern.base for raw sats + * @param {RewardPattern} pattern + * @param {string} name + * @param {Color} sumColor + * @param {Color} cumulativeColor + */ + const fromRewardPattern = (pattern, name, sumColor, cumulativeColor) => [ + s({ + metric: pattern.base, + name: `${name}`, + color: sumColor, + unit: Unit.sats, + }), + s({ + metric: pattern.sats.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.sats, + defaultActive: false, + }), + s({ + metric: pattern.bitcoin.base, + name: `${name}`, + color: sumColor, + unit: Unit.btc, + }), + s({ + metric: pattern.bitcoin.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.btc, + defaultActive: false, + }), + s({ + metric: pattern.dollarsSource, + name: `${name}`, + color: sumColor, + unit: Unit.usd, + }), + s({ + metric: pattern.dollars.cumulative, + name: `${name} cumulative`, + color: cumulativeColor, + unit: Unit.usd, + defaultActive: false, + }), + ]; + + // Build pools tree dynamically + const poolEntries = Object.entries(pools.vecs); + const poolsTree = poolEntries.map(([key, pool]) => { + const poolName = + brk.POOL_ID_TO_POOL_NAME[ + /** @type {keyof typeof brk.POOL_ID_TO_POOL_NAME} */ (key.toLowerCase()) + ] || key; + return { + name: poolName, + tree: [ + { + name: "Dominance", + title: `Mining Dominance of ${poolName}`, + bottom: [ + s({ + metric: mergeMetricPatterns( + pool._1dDominance.base, + pool._1dDominance.sum, + ), + name: "1d", + color: colors.rose, + unit: Unit.percentage, + defaultActive: false, + }), + s({ + metric: pool._1wDominance, + name: "1w", + color: colors.red, + unit: Unit.percentage, + defaultActive: false, + }), + s({ metric: pool._1mDominance, name: "1m", unit: Unit.percentage }), + s({ + metric: pool._1yDominance, + name: "1y", + color: colors.lime, + unit: Unit.percentage, + defaultActive: false, + }), + s({ + metric: mergeMetricPatterns( + pool.dominance.base, + pool.dominance.sum, + ), + name: "all time", + color: colors.teal, + unit: Unit.percentage, + defaultActive: false, + }), + ], + }, + { + name: "Blocks mined", + title: `Blocks mined by ${poolName}`, + bottom: [ + s({ + metric: mergeMetricPatterns( + pool.blocksMined.base, + pool.blocksMined.sum, + ), + name: "Sum", + unit: Unit.count, + }), + s({ + metric: pool.blocksMined.cumulative, + name: "Cumulative", + color: colors.blue, + unit: Unit.count, + }), + s({ + metric: pool._1wBlocksMined, + name: "1w Sum", + color: colors.red, + unit: Unit.count, + defaultActive: false, + }), + s({ + metric: pool._1mBlocksMined, + name: "1m Sum", + color: colors.pink, + unit: Unit.count, + defaultActive: false, + }), + s({ + metric: pool._1yBlocksMined, + name: "1y Sum", + color: colors.purple, + unit: Unit.count, + defaultActive: false, + }), + ], + }, + { + name: "Rewards", + title: `Rewards collected by ${poolName}`, + bottom: [ + ...fromValuePattern( + pool.coinbase, + "coinbase", + colors.orange, + colors.red, + ), + ...fromRewardPattern( + pool.subsidy, + "subsidy", + colors.lime, + colors.emerald, + ), + ...fromRewardPattern(pool.fee, "fee", colors.cyan, colors.indigo), + ], + }, + { + name: "Days since block", + title: `Days since ${poolName} mined a block`, + bottom: [ + s({ + metric: pool.daysSinceBlock, + name: "Since block", + unit: Unit.days, + }), + ], + }, + ], + }; + }); + + return { + name: "Chain", + tree: [ + // Block + { + name: "Block", + tree: [ + { + name: "Count", + title: "Block Count", + bottom: [ + ...fromBlockCount(blocks.count.blockCount, "Block", Unit.count), + s({ + metric: blocks.count.blockCountTarget, + name: "Target", + color: colors.gray, + unit: Unit.count, + options: { lineStyle: 4 }, + }), + s({ + metric: blocks.count._1wBlockCount, + name: "1w sum", + color: colors.red, + unit: Unit.count, + defaultActive: false, + }), + s({ + metric: blocks.count._1mBlockCount, + name: "1m sum", + color: colors.pink, + unit: Unit.count, + defaultActive: false, + }), + s({ + metric: blocks.count._1yBlockCount, + name: "1y sum", + color: colors.purple, + unit: Unit.count, + defaultActive: false, + }), + ], + }, + { + name: "Interval", + title: "Block Interval", + bottom: [ + s({ + metric: blocks.interval.interval, + name: "Interval", + unit: Unit.secs, + }), + ...fromBlockInterval( + blocks.interval.blockInterval, + "Interval", + Unit.secs, + ), + createPriceLine({ unit: Unit.secs, name: "Target", number: 600 }), + ], + }, + { + name: "Size", + title: "Block Size", + bottom: [ + s({ + metric: blocks.size.vbytes, + name: "vbytes raw", + unit: Unit.vb, + }), + s({ + metric: indexed.block.weight, + name: "weight raw", + unit: Unit.wu, + }), + ...fromBlockSize(blocks.size.blockSize, "size", Unit.bytes), + ...fromBlockSize(blocks.weight.blockWeight, "weight", Unit.wu), + ...fromBlockSize(blocks.size.blockVbytes, "vbytes", Unit.vb), + ], + }, + ], + }, + + // Transaction + { + name: "Transaction", + tree: [ + { + name: "Count", + title: "Transaction Count", + bottom: fromBitcoin( + transactions.count.txCount, + "Count", + Unit.count, + ), + }, + { + name: "Volume", + title: "Transaction Volume", + bottom: [ + s({ + metric: mergeMetricPatterns( + transactions.volume.sentSum.sats.base, + transactions.volume.sentSum.sats.rest, + ), + name: "Sent", + unit: Unit.sats, + }), + s({ + metric: transactions.volume.sentSum.bitcoin, + name: "Sent", + unit: Unit.btc, + }), + s({ + metric: mergeMetricPatterns( + transactions.volume.sentSum.dollars.base, + transactions.volume.sentSum.dollars.rest, + ), + name: "Sent", + unit: Unit.usd, + }), + s({ + metric: transactions.volume.annualizedVolume, + name: "annualized", + color: colors.red, + unit: Unit.sats, + defaultActive: false, + }), + s({ + metric: transactions.volume.annualizedVolumeBtc, + name: "annualized", + color: colors.red, + unit: Unit.btc, + defaultActive: false, + }), + s({ + metric: transactions.volume.annualizedVolumeUsd, + name: "annualized", + color: colors.lime, + unit: Unit.usd, + defaultActive: false, + }), + ], + }, + { + name: "Size", + title: "Transaction Size", + bottom: [ + ...fromBlockInterval( + transactions.size.txWeight, + "weight", + Unit.wu, + ), + ...fromBlockInterval(transactions.size.txVsize, "vsize", Unit.vb), + ], + }, + { + name: "Versions", + title: "Transaction Versions", + bottom: [ + ...fromBlockCount( + transactions.versions.txV1, + "v1", + Unit.count, + colors.orange, + colors.red, + ), + ...fromBlockCount( + transactions.versions.txV2, + "v2", + Unit.count, + colors.cyan, + colors.blue, + ), + ...fromBlockCount( + transactions.versions.txV3, + "v3", + Unit.count, + colors.lime, + colors.green, + ), + ], + }, + { + name: "Velocity", + title: "Transactions Velocity", + bottom: [ + s({ + metric: brk.mergeMetricPatterns( + supply.velocity.btc.dateindex, + supply.velocity.btc.rest, + ), + name: "bitcoin", + unit: Unit.ratio, + }), + s({ + metric: brk.mergeMetricPatterns( + supply.velocity.usd.dateindex, + supply.velocity.usd.rest, + ), + name: "dollars", + color: colors.emerald, + unit: Unit.ratio, + }), + ], + }, + { + name: "Speed", + title: "Transactions Per Second", + bottom: [ + s({ + metric: transactions.volume.txPerSec, + name: "Transactions", + unit: Unit.perSec, + }), + ], + }, + ], + }, + + // Input + { + name: "Input", + tree: [ + { + name: "Count", + title: "Transaction Input Count", + bottom: [ + ...fromCountPattern2(inputs.count.count, "Input", Unit.count), + ], + }, + { + name: "Speed", + title: "Inputs Per Second", + bottom: [ + s({ + metric: transactions.volume.inputsPerSec, + name: "Inputs", + unit: Unit.perSec, + }), + ], + }, + ], + }, + + // Output + { + name: "Output", + tree: [ + { + name: "Count", + title: "Transaction Output Count", + bottom: [ + ...fromCountPattern2(outputs.count.count, "Output", Unit.count), + ], + }, + { + name: "Speed", + title: "Outputs Per Second", + bottom: [ + s({ + metric: transactions.volume.outputsPerSec, + name: "Outputs", + unit: Unit.perSec, + }), + ], + }, + ], + }, + + // UTXO + { + name: "UTXO", + tree: [ + { + name: "Count", + title: "UTXO Count", + bottom: [ + s({ + metric: mergeMetricPatterns( + outputs.count.utxoCount.base, + outputs.count.utxoCount.sum, + ), + name: "Count", + unit: Unit.count, + }), + ], + }, + ], + }, + + // Coinbase + { + name: "Coinbase", + title: "Coinbase Rewards", + bottom: fromCoinbase( + blocks.rewards.coinbase, + "Coinbase", + colors.orange, + colors.red, + ), + }, + + // Subsidy + { + name: "Subsidy", + title: "Block Subsidy", + bottom: [ + ...fromCoinbase( + blocks.rewards.subsidy, + "Subsidy", + colors.lime, + colors.emerald, + ), + s({ + metric: blocks.rewards.subsidyDominance, + name: "Dominance", + color: colors.purple, + unit: Unit.percentage, + defaultActive: false, + }), + ], + }, + + // Fee + { + name: "Fee", + tree: [ + { + name: "Total", + title: "Transaction Fees", + bottom: [ + s({ + metric: transactions.fees.fee.sats.sum, + name: "Sum", + unit: Unit.sats, + }), + s({ + metric: transactions.fees.fee.sats.cumulative, + name: "Cumulative", + color: colors.blue, + unit: Unit.sats, + defaultActive: false, + }), + s({ + metric: transactions.fees.fee.bitcoin.sum, + name: "Sum", + unit: Unit.btc, + }), + s({ + metric: transactions.fees.fee.bitcoin.cumulative, + name: "Cumulative", + color: colors.blue, + unit: Unit.btc, + defaultActive: false, + }), + s({ + metric: transactions.fees.fee.dollars.sum, + name: "Sum", + unit: Unit.usd, + }), + s({ + metric: transactions.fees.fee.dollars.cumulative, + name: "Cumulative", + color: colors.blue, + unit: Unit.usd, + defaultActive: false, + }), + s({ + metric: blocks.rewards.feeDominance, + name: "Dominance", + color: colors.purple, + unit: Unit.percentage, + defaultActive: false, + }), + ], + }, + { + name: "Rate", + title: "Fee Rate", + bottom: [ + s({ + metric: transactions.fees.feeRate.base, + name: "Rate", + unit: Unit.feeRate, + }), + s({ + metric: transactions.fees.feeRate.average, + name: "Average", + color: colors.blue, + unit: Unit.feeRate, + }), + s({ + metric: transactions.fees.feeRate.percentiles.median, + name: "Median", + color: colors.purple, + unit: Unit.feeRate, + }), + s({ + metric: transactions.fees.feeRate.min, + name: "Min", + color: colors.red, + unit: Unit.feeRate, + defaultActive: false, + }), + s({ + metric: transactions.fees.feeRate.max, + name: "Max", + color: colors.green, + unit: Unit.feeRate, + defaultActive: false, + }), + s({ + metric: transactions.fees.feeRate.percentiles.pct10, + name: "pct10", + color: colors.rose, + unit: Unit.feeRate, + defaultActive: false, + }), + s({ + metric: transactions.fees.feeRate.percentiles.pct25, + name: "pct25", + color: colors.pink, + unit: Unit.feeRate, + defaultActive: false, + }), + s({ + metric: transactions.fees.feeRate.percentiles.pct75, + name: "pct75", + color: colors.violet, + unit: Unit.feeRate, + defaultActive: false, + }), + s({ + metric: transactions.fees.feeRate.percentiles.pct90, + name: "pct90", + color: colors.fuchsia, + unit: Unit.feeRate, + defaultActive: false, + }), + ], + }, + ], + }, + + // Mining + { + name: "Mining", + tree: [ + { + name: "Hashrate", + title: "Network Hashrate", + bottom: [ + s({ + metric: blocks.mining.hashRate, + name: "Hashrate", + unit: Unit.hashRate, + }), + s({ + metric: blocks.mining.hashRate1wSma, + name: "1w SMA", + color: colors.red, + unit: Unit.hashRate, + defaultActive: false, + }), + s({ + metric: blocks.mining.hashRate1mSma, + name: "1m SMA", + color: colors.orange, + unit: Unit.hashRate, + defaultActive: false, + }), + s({ + metric: blocks.mining.hashRate2mSma, + name: "2m SMA", + color: colors.yellow, + unit: Unit.hashRate, + defaultActive: false, + }), + s({ + metric: blocks.mining.hashRate1ySma, + name: "1y SMA", + color: colors.lime, + unit: Unit.hashRate, + defaultActive: false, + }), + ], + }, + { + name: "Difficulty", + title: "Network Difficulty", + bottom: [ + s({ + metric: blocks.mining.difficulty, + name: "Difficulty", + unit: Unit.difficulty, + }), + s({ + metric: mergeMetricPatterns( + blocks.mining.difficultyAdjustment.base, + blocks.mining.difficultyAdjustment.rest, + ), + name: "Adjustment", + color: colors.orange, + unit: Unit.percentage, + defaultActive: false, + }), + s({ + metric: blocks.mining.difficultyAsHash, + name: "As hash", + color: colors.default, + unit: Unit.hashRate, + defaultActive: false, + options: { lineStyle: 1 }, + }), + s({ + metric: blocks.difficulty.blocksBeforeNextDifficultyAdjustment, + name: "Blocks until adj.", + color: colors.indigo, + unit: Unit.blocks, + defaultActive: false, + }), + s({ + metric: blocks.difficulty.daysBeforeNextDifficultyAdjustment, + name: "Days until adj.", + color: colors.purple, + unit: Unit.days, + defaultActive: false, + }), + ], + }, + { + name: "Hash Price", + title: "Hash Price", + bottom: [ + s({ + metric: blocks.mining.hashPriceThs, + name: "TH/s", + color: colors.emerald, + unit: Unit.usdPerThsPerDay, + }), + s({ + metric: blocks.mining.hashPricePhs, + name: "PH/s", + color: colors.emerald, + unit: Unit.usdPerPhsPerDay, + }), + s({ + metric: blocks.mining.hashPriceRebound, + name: "Rebound", + color: colors.yellow, + unit: Unit.percentage, + }), + s({ + metric: blocks.mining.hashPriceThsMin, + name: "TH/s Min", + color: colors.red, + unit: Unit.usdPerThsPerDay, + options: { lineStyle: 1 }, + }), + s({ + metric: blocks.mining.hashPricePhsMin, + name: "PH/s Min", + color: colors.red, + unit: Unit.usdPerPhsPerDay, + options: { lineStyle: 1 }, + }), + ], + }, + { + name: "Hash Value", + title: "Hash Value", + bottom: [ + s({ + metric: blocks.mining.hashValueThs, + name: "TH/s", + color: colors.orange, + unit: Unit.satsPerThsPerDay, + }), + s({ + metric: blocks.mining.hashValuePhs, + name: "PH/s", + color: colors.orange, + unit: Unit.satsPerPhsPerDay, + }), + s({ + metric: blocks.mining.hashValueRebound, + name: "Rebound", + color: colors.yellow, + unit: Unit.percentage, + }), + s({ + metric: blocks.mining.hashValueThsMin, + name: "TH/s Min", + color: colors.red, + unit: Unit.satsPerThsPerDay, + options: { lineStyle: 1 }, + }), + s({ + metric: blocks.mining.hashValuePhsMin, + name: "PH/s Min", + color: colors.red, + unit: Unit.satsPerPhsPerDay, + options: { lineStyle: 1 }, + }), + ], + }, + { + name: "Halving", + title: "Halving Info", + bottom: [ + s({ + metric: blocks.halving.blocksBeforeNextHalving, + name: "Blocks until halving", + unit: Unit.blocks, + }), + s({ + metric: blocks.halving.daysBeforeNextHalving, + name: "Days until halving", + color: colors.orange, + unit: Unit.days, + }), + s({ + metric: blocks.halving.halvingepoch, + name: "Halving epoch", + color: colors.purple, + unit: Unit.epoch, + defaultActive: false, + }), + ], + }, + { + name: "Puell Multiple", + title: "Puell Multiple", + bottom: [ + s({ + metric: market.indicators.puellMultiple, + name: "Puell Multiple", + unit: Unit.ratio, + }), + createPriceLine({ unit: Unit.ratio, number: 1 }), + ], + }, + ], + }, + + // Pools + { + name: "Pools", + tree: poolsTree, + }, + + // Unspendable + { + name: "Unspendable", + tree: [ + { + name: "OP_RETURN", + tree: [ + { + name: "Outputs", + title: "OP_RETURN Outputs", + bottom: fromBitcoin( + scripts.count.opreturnCount, + "Count", + Unit.count, + ), + }, + ], + }, + ], + }, + + // Inflation + { + name: "Inflation", + title: "Inflation Rate", + bottom: [ + s({ + metric: mergeMetricPatterns( + supply.inflation.indexes.dateindex, + supply.inflation.indexes.rest, + ), + name: "Rate", + unit: Unit.percentage, + }), + ], + }, + ], + }; +} diff --git a/websites/bitview/scripts/options/partial/cohorts/address.js b/websites/bitview/scripts/options/cohorts/address.js similarity index 68% rename from websites/bitview/scripts/options/partial/cohorts/address.js rename to websites/bitview/scripts/options/cohorts/address.js index 71a71ebd9..a4ac23a86 100644 --- a/websites/bitview/scripts/options/partial/cohorts/address.js +++ b/websites/bitview/scripts/options/cohorts/address.js @@ -4,6 +4,7 @@ * Address cohorts use _0satsPattern which has CostBasisPattern (no percentiles) */ +import { Unit } from "../../utils/units.js"; import { createSingleSupplySeries, createGroupedSupplyTotalSeries, @@ -37,7 +38,10 @@ export function createAddressCohortFolder(ctx, args) { ? { name: "supply", title: `Supply ${title}`, - bottom: createSingleSupplySeries(ctx, /** @type {AddressCohortObject} */ (args), title), + bottom: createSingleSupplySeries( + ctx, + /** @type {AddressCohortObject} */ (args), + ), } : { name: "supply", @@ -91,13 +95,23 @@ export function createAddressCohortFolder(ctx, args) { bottom: createRealizedPriceRatioSeries(ctx, list), }, ] - : createRealizedPriceOptions(ctx, /** @type {AddressCohortObject} */ (args), title)), + : createRealizedPriceOptions( + ctx, + /** @type {AddressCohortObject} */ (args), + title, + )), { name: "capitalization", title: `Realized Capitalization ${title}`, - bottom: createRealizedCapWithExtras(ctx, list, args, useGroupName, title), + bottom: createRealizedCapWithExtras(ctx, list, args, useGroupName), }, - ...(!useGroupName ? createRealizedPnlSection(ctx, /** @type {AddressCohortObject} */ (args), title) : []), + ...(!useGroupName + ? createRealizedPnlSection( + ctx, + /** @type {AddressCohortObject} */ (args), + title, + ) + : []), ], }, @@ -128,7 +142,14 @@ function createRealizedPriceOptions(ctx, args, title) { { name: "price", title: `Realized Price ${title}`, - top: [s({ metric: tree.realized.realizedPrice, name: "realized", color })], + top: [ + s({ + metric: tree.realized.realizedPrice, + name: "Realized", + color, + unit: Unit.usd, + }), + ], }, ]; } @@ -139,24 +160,29 @@ function createRealizedPriceOptions(ctx, args, title) { * @param {readonly AddressCohortObject[]} list * @param {AddressCohortObject | AddressCohortGroupObject} args * @param {boolean} useGroupName - * @param {string} title * @returns {AnyFetchedSeriesBlueprint[]} */ -function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { - const { colors, s, createPriceLine } = ctx; +function createRealizedCapWithExtras(ctx, list, args, useGroupName) { + const { s, createPriceLine } = ctx; const isSingle = !("list" in args); return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.realized.realizedCap, name: useGroupName ? name : "Capitalization", color }), + s({ + metric: tree.realized.realizedCap, + name: useGroupName ? name : "Capitalization", + color, + unit: Unit.usd, + }), ...(isSingle ? [ /** @type {AnyFetchedSeriesBlueprint} */ ({ type: "Baseline", metric: tree.realized.realizedCap30dDelta, - title: "30d change", + title: "30d Change", + unit: Unit.usd, defaultActive: false, }), - createPriceLine({ unit: "usd", defaultActive: false }), + createPriceLine({ unit: Unit.usd, defaultActive: false }), ] : []), // RealizedPattern (address cohorts) doesn't have realizedCapRelToOwnMarketCap @@ -172,18 +198,50 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { */ function createRealizedPnlSection(ctx, args, title) { const { colors, s } = ctx; - const { tree } = args; + const { mergeMetricPatterns } = ctx.brk; + const { realized } = args.tree; return [ { name: "pnl", title: `Realized Profit And Loss ${title}`, bottom: [ - s({ metric: tree.realized.realizedProfit.base, name: "Profit", color: colors.green }), - s({ metric: tree.realized.realizedLoss.base, name: "Loss", color: colors.red, defaultActive: false }), + s({ + metric: mergeMetricPatterns( + realized.realizedProfit.base, + realized.realizedProfit.sum, + ), + name: "Profit", + color: colors.green, + unit: Unit.usd, + }), + s({ + metric: mergeMetricPatterns( + realized.realizedLoss.base, + realized.realizedLoss.sum, + ), + name: "Loss", + color: colors.red, + unit: Unit.usd, + defaultActive: false, + }), // RealizedPattern (address cohorts) doesn't have realizedProfitToLossRatio - s({ metric: tree.realized.totalRealizedPnl.base, name: "Total", color: colors.default, defaultActive: false }), - s({ metric: tree.realized.negRealizedLoss.base, name: "Negative Loss", color: colors.red }), + s({ + metric: realized.totalRealizedPnl, + name: "Total", + color: colors.default, + defaultActive: false, + unit: Unit.usd, + }), + s({ + metric: mergeMetricPatterns( + realized.negRealizedLoss.base, + realized.negRealizedLoss.sum, + ), + name: "Negative Loss", + color: colors.red, + unit: Unit.usd, + }), ], }, ]; @@ -212,7 +270,9 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { type: "Baseline", metric: tree.unrealized.netUnrealizedPnl, title: useGroupName ? name : "NUPL", - colors: [colors.red, colors.green], + color: useGroupName ? color : undefined, + colors: useGroupName ? undefined : [colors.red, colors.green], + unit: Unit.ratio, options: { baseValue: { price: 0 } }, }), ]), @@ -221,14 +281,24 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { name: "profit", title: `Unrealized Profit ${title}`, bottom: list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.unrealized.unrealizedProfit, name: useGroupName ? name : "Profit", color }), + s({ + metric: tree.unrealized.unrealizedProfit, + name: useGroupName ? name : "Profit", + color, + unit: Unit.usd, + }), ]), }, { name: "loss", title: `Unrealized Loss ${title}`, bottom: list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.unrealized.unrealizedLoss, name: useGroupName ? name : "Loss", color }), + s({ + metric: tree.unrealized.unrealizedLoss, + name: useGroupName ? name : "Loss", + color, + unit: Unit.usd, + }), ]), }, ], @@ -255,14 +325,24 @@ function createCostBasisSection(ctx, list, useGroupName, title) { name: "min", title: `Min Cost Basis ${title}`, top: list.map(({ color, name, tree }) => - s({ metric: tree.costBasis.minCostBasis, name: useGroupName ? name : "Min", color }), + s({ + metric: tree.costBasis.minCostBasis, + name: useGroupName ? name : "Min", + color, + unit: Unit.usd, + }), ), }, { name: "max", title: `Max Cost Basis ${title}`, top: list.map(({ color, name, tree }) => - s({ metric: tree.costBasis.maxCostBasis, name: useGroupName ? name : "Max", color }), + s({ + metric: tree.costBasis.maxCostBasis, + name: useGroupName ? name : "Max", + color, + unit: Unit.usd, + }), ), }, ], @@ -279,7 +359,8 @@ function createCostBasisSection(ctx, list, useGroupName, title) { * @returns {PartialOptionsTree} */ function createActivitySection(ctx, list, useGroupName, title) { - const { s } = ctx; + const { s, brk } = ctx; + const { mergeMetricPatterns } = brk; return [ { @@ -290,9 +371,13 @@ function createActivitySection(ctx, list, useGroupName, title) { title: `Coinblocks Destroyed ${title}`, bottom: list.flatMap(({ color, name, tree }) => [ s({ - metric: tree.activity.coinblocksDestroyed.base, + metric: mergeMetricPatterns( + tree.activity.coinblocksDestroyed.base, + tree.activity.coinblocksDestroyed.sum, + ), name: useGroupName ? name : "Coinblocks", color, + unit: Unit.coinblocks, }), ]), }, @@ -301,9 +386,13 @@ function createActivitySection(ctx, list, useGroupName, title) { title: `Coindays Destroyed ${title}`, bottom: list.flatMap(({ color, name, tree }) => [ s({ - metric: tree.activity.coindaysDestroyed.base, + metric: mergeMetricPatterns( + tree.activity.coindaysDestroyed.base, + tree.activity.coindaysDestroyed.sum, + ), name: useGroupName ? name : "Coindays", color, + unit: Unit.coindays, }), ]), }, diff --git a/websites/bitview/scripts/options/partial/cohorts/data.js b/websites/bitview/scripts/options/cohorts/data.js similarity index 100% rename from websites/bitview/scripts/options/partial/cohorts/data.js rename to websites/bitview/scripts/options/cohorts/data.js diff --git a/websites/bitview/scripts/options/partial/cohorts/index.js b/websites/bitview/scripts/options/cohorts/index.js similarity index 100% rename from websites/bitview/scripts/options/partial/cohorts/index.js rename to websites/bitview/scripts/options/cohorts/index.js diff --git a/websites/bitview/scripts/options/partial/cohorts/shared.js b/websites/bitview/scripts/options/cohorts/shared.js similarity index 72% rename from websites/bitview/scripts/options/partial/cohorts/shared.js rename to websites/bitview/scripts/options/cohorts/shared.js index 93ec09a42..7e09a2c9d 100644 --- a/websites/bitview/scripts/options/partial/cohorts/shared.js +++ b/websites/bitview/scripts/options/cohorts/shared.js @@ -1,42 +1,43 @@ /** Shared cohort chart section builders */ +import { Unit } from "../../utils/units.js"; + /** * Create supply section for a single cohort * @param {PartialContext} ctx * @param {CohortObject} cohort - * @param {string} title * @returns {AnyFetchedSeriesBlueprint[]} */ -export function createSingleSupplySeries(ctx, cohort, title) { +export function createSingleSupplySeries(ctx, cohort) { const { colors, s, createPriceLine } = ctx; - const { tree, color, name } = cohort; + const { tree } = cohort; return [ - s({ metric: tree.supply.supply.sats, name: "Supply", color: colors.default }), - s({ metric: tree.supply.supply.bitcoin, name: "Supply", color: colors.default }), - s({ metric: tree.supply.supply.dollars, name: "Supply", color: colors.default }), + s({ metric: tree.supply.supply.sats, name: "Supply", color: colors.default, unit: Unit.sats }), + s({ metric: tree.supply.supply.bitcoin, name: "Supply", color: colors.default, unit: Unit.btc }), + s({ metric: tree.supply.supply.dollars, name: "Supply", color: colors.default, unit: Unit.usd }), ...("supplyRelToCirculatingSupply" in tree.relative - ? [s({ metric: tree.relative.supplyRelToCirculatingSupply, name: "Supply", color: colors.default })] + ? [s({ metric: tree.relative.supplyRelToCirculatingSupply, name: "Supply", color: colors.default, unit: Unit.pctSupply })] : []), - s({ metric: tree.unrealized.supplyInProfit.sats, name: "In Profit", color: colors.green }), - s({ metric: tree.unrealized.supplyInProfit.bitcoin, name: "In Profit", color: colors.green }), - s({ metric: tree.unrealized.supplyInProfit.dollars, name: "In Profit", color: colors.green }), - s({ metric: tree.unrealized.supplyInLoss.sats, name: "In Loss", color: colors.red }), - s({ metric: tree.unrealized.supplyInLoss.bitcoin, name: "In Loss", color: colors.red }), - s({ metric: tree.unrealized.supplyInLoss.dollars, name: "In Loss", color: colors.red }), - s({ metric: tree.supply.supplyHalf.sats, name: "half", color: colors.gray, options: { lineStyle: 4 } }), - s({ metric: tree.supply.supplyHalf.bitcoin, name: "half", color: colors.gray, options: { lineStyle: 4 } }), - s({ metric: tree.supply.supplyHalf.dollars, name: "half", color: colors.gray, options: { lineStyle: 4 } }), + s({ metric: tree.unrealized.supplyInProfit.sats, name: "In Profit", color: colors.green, unit: Unit.sats }), + s({ metric: tree.unrealized.supplyInProfit.bitcoin, name: "In Profit", color: colors.green, unit: Unit.btc }), + s({ metric: tree.unrealized.supplyInProfit.dollars, name: "In Profit", color: colors.green, unit: Unit.usd }), + s({ metric: tree.unrealized.supplyInLoss.sats, name: "In Loss", color: colors.red, unit: Unit.sats }), + s({ metric: tree.unrealized.supplyInLoss.bitcoin, name: "In Loss", color: colors.red, unit: Unit.btc }), + s({ metric: tree.unrealized.supplyInLoss.dollars, name: "In Loss", color: colors.red, unit: Unit.usd }), + s({ metric: tree.supply.supplyHalf.sats, name: "half", color: colors.gray, unit: Unit.sats, options: { lineStyle: 4 } }), + s({ metric: tree.supply.supplyHalf.bitcoin, name: "half", color: colors.gray, unit: Unit.btc, options: { lineStyle: 4 } }), + s({ metric: tree.supply.supplyHalf.dollars, name: "half", color: colors.gray, unit: Unit.usd, options: { lineStyle: 4 } }), ...("supplyInProfitRelToCirculatingSupply" in tree.relative ? [ - s({ metric: tree.relative.supplyInProfitRelToCirculatingSupply, name: "In Profit", color: colors.green }), - s({ metric: tree.relative.supplyInLossRelToCirculatingSupply, name: "In Loss", color: colors.red }), + s({ metric: tree.relative.supplyInProfitRelToCirculatingSupply, name: "In Profit", color: colors.green, unit: Unit.pctSupply }), + s({ metric: tree.relative.supplyInLossRelToCirculatingSupply, name: "In Loss", color: colors.red, unit: Unit.pctSupply }), ] : []), - s({ metric: tree.relative.supplyInProfitRelToOwnSupply, name: "In Profit", color: colors.green }), - s({ metric: tree.relative.supplyInLossRelToOwnSupply, name: "In Loss", color: colors.red }), - createPriceLine({ unit: "%self", number: 100, lineStyle: 0, color: colors.default }), - createPriceLine({ unit: "%self", number: 50 }), + s({ metric: tree.relative.supplyInProfitRelToOwnSupply, name: "In Profit", color: colors.green, unit: Unit.pctOwn }), + s({ metric: tree.relative.supplyInLossRelToOwnSupply, name: "In Loss", color: colors.red, unit: Unit.pctOwn }), + createPriceLine({ unit: Unit.pctOwn, number: 100, lineStyle: 0, color: colors.default }), + createPriceLine({ unit: Unit.pctOwn, number: 50 }), ]; } @@ -51,12 +52,12 @@ export function createGroupedSupplyTotalSeries(ctx, list) { const constant100 = brk.tree.computed.constants.constant100; return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.supply.supply.sats, name, color }), - s({ metric: tree.supply.supply.bitcoin, name, color }), - s({ metric: tree.supply.supply.dollars, name, color }), + s({ metric: tree.supply.supply.sats, name, color, unit: Unit.sats }), + s({ metric: tree.supply.supply.bitcoin, name, color, unit: Unit.btc }), + s({ metric: tree.supply.supply.dollars, name, color, unit: Unit.usd }), "supplyRelToCirculatingSupply" in tree.relative - ? s({ metric: tree.relative.supplyRelToCirculatingSupply, name, color }) - : s({ unit: "%all", metric: constant100, name, color }), + ? s({ metric: tree.relative.supplyRelToCirculatingSupply, name, color, unit: Unit.pctSupply }) + : s({ metric: constant100, name, color, unit: Unit.pctSupply }), ]); } @@ -70,11 +71,11 @@ export function createGroupedSupplyInProfitSeries(ctx, list) { const { s } = ctx; return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.unrealized.supplyInProfit.sats, name, color }), - s({ metric: tree.unrealized.supplyInProfit.bitcoin, name, color }), - s({ metric: tree.unrealized.supplyInProfit.dollars, name, color }), + s({ metric: tree.unrealized.supplyInProfit.sats, name, color, unit: Unit.sats }), + s({ metric: tree.unrealized.supplyInProfit.bitcoin, name, color, unit: Unit.btc }), + s({ metric: tree.unrealized.supplyInProfit.dollars, name, color, unit: Unit.usd }), ...("supplyInProfitRelToCirculatingSupply" in tree.relative - ? [s({ metric: tree.relative.supplyInProfitRelToCirculatingSupply, name, color })] + ? [s({ metric: tree.relative.supplyInProfitRelToCirculatingSupply, name, color, unit: Unit.pctSupply })] : []), ]); } @@ -89,11 +90,11 @@ export function createGroupedSupplyInLossSeries(ctx, list) { const { s } = ctx; return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.unrealized.supplyInLoss.sats, name, color }), - s({ metric: tree.unrealized.supplyInLoss.bitcoin, name, color }), - s({ metric: tree.unrealized.supplyInLoss.dollars, name, color }), + s({ metric: tree.unrealized.supplyInLoss.sats, name, color, unit: Unit.sats }), + s({ metric: tree.unrealized.supplyInLoss.bitcoin, name, color, unit: Unit.btc }), + s({ metric: tree.unrealized.supplyInLoss.dollars, name, color, unit: Unit.usd }), ...("supplyInLossRelToCirculatingSupply" in tree.relative - ? [s({ metric: tree.relative.supplyInLossRelToCirculatingSupply, name, color })] + ? [s({ metric: tree.relative.supplyInLossRelToCirculatingSupply, name, color, unit: Unit.pctSupply })] : []), ]); } @@ -109,7 +110,7 @@ export function createUtxoCountSeries(ctx, list, useGroupName) { const { s } = ctx; return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.supply.utxoCount, name: useGroupName ? name : "Count", color }), + s({ metric: tree.supply.utxoCount, name: useGroupName ? name : "Count", color, unit: Unit.count }), ]); } @@ -128,6 +129,7 @@ export function createAddressCountSeries(ctx, list, useGroupName) { metric: tree.addrCount, name: useGroupName ? name : "Count", color: useGroupName ? color : colors.orange, + unit: Unit.count, }), ]); } @@ -142,7 +144,7 @@ export function createRealizedPriceSeries(ctx, list) { const { s } = ctx; return list.map(({ color, name, tree }) => - s({ metric: tree.realized.realizedPrice, name, color }), + s({ metric: tree.realized.realizedPrice, name, color, unit: Unit.usd }), ); } @@ -157,9 +159,9 @@ export function createRealizedPriceRatioSeries(ctx, list) { return [ ...list.map(({ color, name, tree }) => - s({ metric: tree.realized.realizedPriceExtra.ratio, name, color }), + s({ metric: tree.realized.realizedPriceExtra.ratio, name, color, unit: Unit.ratio }), ), - createPriceLine({ unit: "ratio", number: 1 }), + createPriceLine({ unit: Unit.ratio, number: 1 }), ]; } @@ -174,7 +176,7 @@ export function createRealizedCapSeries(ctx, list, useGroupName) { const { s } = ctx; return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.realized.realizedCap, name: useGroupName ? name : "Capitalization", color }), + s({ metric: tree.realized.realizedCap, name: useGroupName ? name : "Capitalization", color, unit: Unit.usd }), ]); } @@ -189,8 +191,8 @@ export function createCostBasisMinMaxSeries(ctx, list, useGroupName) { const { s } = ctx; return list.flatMap(({ color, name, tree }) => [ - s({ metric: tree.costBasis.minCostBasis, name: useGroupName ? `${name} min` : "Min", color }), - s({ metric: tree.costBasis.maxCostBasis, name: useGroupName ? `${name} max` : "Max", color }), + s({ metric: tree.costBasis.minCostBasis, name: useGroupName ? `${name} min` : "Min", color, unit: Unit.usd }), + s({ metric: tree.costBasis.maxCostBasis, name: useGroupName ? `${name} max` : "Max", color, unit: Unit.usd }), ]); } @@ -202,16 +204,16 @@ export function createCostBasisMinMaxSeries(ctx, list, useGroupName) { * @returns {AnyFetchedSeriesBlueprint[]} */ export function createCostBasisPercentilesSeries(ctx, list, useGroupName) { - const { s, colors } = ctx; + const { s } = ctx; return list.flatMap(({ color, name, tree }) => { const percentiles = tree.costBasis.percentiles; return [ - s({ metric: percentiles.costBasisPct10, name: useGroupName ? `${name} p10` : "p10", color, defaultActive: false }), - s({ metric: percentiles.costBasisPct25, name: useGroupName ? `${name} p25` : "p25", color, defaultActive: false }), - s({ metric: percentiles.costBasisPct50, name: useGroupName ? `${name} p50` : "p50", color }), - s({ metric: percentiles.costBasisPct75, name: useGroupName ? `${name} p75` : "p75", color, defaultActive: false }), - s({ metric: percentiles.costBasisPct90, name: useGroupName ? `${name} p90` : "p90", color, defaultActive: false }), + s({ metric: percentiles.costBasisPct10, name: useGroupName ? `${name} p10` : "p10", color, unit: Unit.usd, defaultActive: false }), + s({ metric: percentiles.costBasisPct25, name: useGroupName ? `${name} p25` : "p25", color, unit: Unit.usd, defaultActive: false }), + s({ metric: percentiles.costBasisPct50, name: useGroupName ? `${name} p50` : "p50", color, unit: Unit.usd }), + s({ metric: percentiles.costBasisPct75, name: useGroupName ? `${name} p75` : "p75", color, unit: Unit.usd, defaultActive: false }), + s({ metric: percentiles.costBasisPct90, name: useGroupName ? `${name} p90` : "p90", color, unit: Unit.usd, defaultActive: false }), ]; }); } diff --git a/websites/bitview/scripts/options/partial/cohorts/types.js b/websites/bitview/scripts/options/cohorts/types.js similarity index 100% rename from websites/bitview/scripts/options/partial/cohorts/types.js rename to websites/bitview/scripts/options/cohorts/types.js diff --git a/websites/bitview/scripts/options/partial/cohorts/utxo.js b/websites/bitview/scripts/options/cohorts/utxo.js similarity index 84% rename from websites/bitview/scripts/options/partial/cohorts/utxo.js rename to websites/bitview/scripts/options/cohorts/utxo.js index 90c790718..fba34a345 100644 --- a/websites/bitview/scripts/options/partial/cohorts/utxo.js +++ b/websites/bitview/scripts/options/cohorts/utxo.js @@ -17,6 +17,7 @@ import { createRealizedPriceRatioSeries, createCostBasisPercentilesSeries, } from "./shared.js"; +import { Unit } from "../../utils/units.js"; /** * Create a cohort folder for age-based UTXO cohorts (term, maxAge, minAge, ageRange, epoch) @@ -28,15 +29,14 @@ import { export function createAgeCohortFolder(ctx, args) { const list = "list" in args ? args.list : [args]; const useGroupName = "list" in args; - const isSingle = !("list" in args); const title = args.title ? `${useGroupName ? "by" : "of"} ${args.title}` : ""; return { name: args.name || "all", tree: [ - ...createSupplySection(ctx, list, args, useGroupName, isSingle, title), + ...createSupplySection(ctx, list, args, useGroupName, title), createUtxoCountSection(ctx, list, useGroupName, title), - createRealizedSection(ctx, list, args, useGroupName, isSingle, title), + createRealizedSection(ctx, list, args, useGroupName, title), ...createUnrealizedSection(ctx, list, useGroupName, title), ...createCostBasisSectionWithPercentiles(ctx, list, useGroupName, title), ...createActivitySection(ctx, list, useGroupName, title), @@ -54,15 +54,14 @@ export function createAgeCohortFolder(ctx, args) { export function createAmountCohortFolder(ctx, args) { const list = "list" in args ? args.list : [args]; const useGroupName = "list" in args; - const isSingle = !("list" in args); const title = args.title ? `${useGroupName ? "by" : "of"} ${args.title}` : ""; return { name: args.name || "all", tree: [ - ...createSupplySection(ctx, list, args, useGroupName, isSingle, title), + ...createSupplySection(ctx, list, args, useGroupName, title), createUtxoCountSection(ctx, list, useGroupName, title), - createRealizedSection(ctx, list, args, useGroupName, isSingle, title), + createRealizedSection(ctx, list, args, useGroupName, title), ...createUnrealizedSection(ctx, list, useGroupName, title), ...createCostBasisSectionBasic(ctx, list, useGroupName, title), ...createActivitySection(ctx, list, useGroupName, title), @@ -81,7 +80,6 @@ export function createAmountCohortFolder(ctx, args) { export function createUtxoCohortFolder(ctx, args) { const list = "list" in args ? args.list : [args]; const useGroupName = "list" in args; - const isSingle = !("list" in args); const title = args.title ? `${useGroupName ? "by" : "of"} ${args.title}` : ""; // Runtime check for percentiles @@ -90,9 +88,9 @@ export function createUtxoCohortFolder(ctx, args) { return { name: args.name || "all", tree: [ - ...createSupplySection(ctx, list, args, useGroupName, isSingle, title), + ...createSupplySection(ctx, list, args, useGroupName, title), createUtxoCountSection(ctx, list, useGroupName, title), - createRealizedSection(ctx, list, args, useGroupName, isSingle, title), + createRealizedSection(ctx, list, args, useGroupName, title), ...createUnrealizedSection(ctx, list, useGroupName, title), ...(hasPercentiles ? createCostBasisSectionWithPercentiles( @@ -113,11 +111,11 @@ export function createUtxoCohortFolder(ctx, args) { * @param {readonly UtxoCohortObject[]} list * @param {UtxoCohortObject | UtxoCohortGroupObject} args * @param {boolean} useGroupName - * @param {boolean} isSingle * @param {string} title * @returns {PartialOptionsTree} */ -function createSupplySection(ctx, list, args, useGroupName, isSingle, title) { +function createSupplySection(ctx, list, args, useGroupName, title) { + const isSingle = !useGroupName; return [ isSingle ? { @@ -126,7 +124,6 @@ function createSupplySection(ctx, list, args, useGroupName, isSingle, title) { bottom: createSingleSupplySeries( ctx, /** @type {UtxoCohortObject} */ (args), - title, ), } : { @@ -174,11 +171,10 @@ function createUtxoCountSection(ctx, list, useGroupName, title) { * @param {readonly UtxoCohortObject[]} list * @param {UtxoCohortObject | UtxoCohortGroupObject} args * @param {boolean} useGroupName - * @param {boolean} isSingle * @param {string} title * @returns {PartialOptionsGroup} */ -function createRealizedSection(ctx, list, args, useGroupName, isSingle, title) { +function createRealizedSection(ctx, list, args, useGroupName, title) { return { name: "Realized", tree: [ @@ -203,13 +199,7 @@ function createRealizedSection(ctx, list, args, useGroupName, isSingle, title) { { name: "capitalization", title: `Realized Capitalization ${title}`, - bottom: createRealizedCapWithExtras( - ctx, - list, - args, - useGroupName, - title, - ), + bottom: createRealizedCapWithExtras(ctx, list, args, useGroupName), }, ...(!useGroupName ? createRealizedPnlSection( @@ -238,7 +228,7 @@ function createRealizedPriceOptions(ctx, args, title) { name: "price", title: `Realized Price ${title}`, top: [ - s({ metric: tree.realized.realizedPrice, name: "realized", color }), + s({ metric: tree.realized.realizedPrice, name: "realized", color, unit: Unit.usd }), ], }, ]; @@ -250,10 +240,9 @@ function createRealizedPriceOptions(ctx, args, title) { * @param {readonly UtxoCohortObject[]} list * @param {UtxoCohortObject | UtxoCohortGroupObject} args * @param {boolean} useGroupName - * @param {string} title * @returns {AnyFetchedSeriesBlueprint[]} */ -function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { +function createRealizedCapWithExtras(ctx, list, args, useGroupName) { const { colors, s, createPriceLine } = ctx; const isSingle = !("list" in args); @@ -262,6 +251,7 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { metric: tree.realized.realizedCap, name: useGroupName ? name : "Capitalization", color, + unit: Unit.usd, }), ...(isSingle ? [ @@ -269,9 +259,10 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { type: "Baseline", metric: tree.realized.realizedCap30dDelta, title: "30d change", + unit: Unit.usd, defaultActive: false, }), - createPriceLine({ unit: "usd", defaultActive: false }), + createPriceLine({ unit: Unit.usd, defaultActive: false }), ] : []), ...(isSingle && "realizedCapRelToOwnMarketCap" in tree.realized @@ -280,10 +271,11 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { type: "Baseline", metric: tree.realized.realizedCapRelToOwnMarketCap, title: "ratio", + unit: Unit.pctOwnMcap, options: { baseValue: { price: 100 } }, colors: [colors.red, colors.green], }), - createPriceLine({ unit: "%cmcap", defaultActive: true, number: 100 }), + createPriceLine({ unit: Unit.pctOwnMcap, defaultActive: true, number: 100 }), ] : []), ]); @@ -297,7 +289,8 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName, title) { * @returns {PartialOptionsTree} */ function createRealizedPnlSection(ctx, args, title) { - const { colors, s } = ctx; + const { colors, s, brk } = ctx; + const { mergeMetricPatterns } = brk; const { tree } = args; return [ @@ -306,35 +299,49 @@ function createRealizedPnlSection(ctx, args, title) { title: `Realized Profit And Loss ${title}`, bottom: [ s({ - metric: tree.realized.realizedProfit.base, + metric: mergeMetricPatterns( + tree.realized.realizedProfit.base, + tree.realized.realizedProfit.sum, + ), name: "Profit", color: colors.green, + unit: Unit.usd, }), s({ - metric: tree.realized.realizedLoss.base, + metric: mergeMetricPatterns( + tree.realized.realizedLoss.base, + tree.realized.realizedLoss.sum, + ), name: "Loss", color: colors.red, defaultActive: false, + unit: Unit.usd, }), ...("realizedProfitToLossRatio" in tree.realized ? [ s({ metric: tree.realized.realizedProfitToLossRatio, - name: "profit / loss", + name: "Profit / Loss", color: colors.yellow, + unit: Unit.ratio, }), ] : []), s({ - metric: tree.realized.totalRealizedPnl.base, + metric: tree.realized.totalRealizedPnl, name: "Total", color: colors.default, defaultActive: false, + unit: Unit.usd, }), s({ - metric: tree.realized.negRealizedLoss.base, + metric: mergeMetricPatterns( + tree.realized.negRealizedLoss.base, + tree.realized.negRealizedLoss.sum, + ), name: "Negative Loss", color: colors.red, + unit: Unit.usd, }), ], }, @@ -350,7 +357,7 @@ function createRealizedPnlSection(ctx, args, title) { * @returns {PartialOptionsTree} */ function createUnrealizedSection(ctx, list, useGroupName, title) { - const { colors, s, createPriceLine } = ctx; + const { colors, s } = ctx; return [ { @@ -359,12 +366,13 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { { name: "nupl", title: `Net Unrealized Profit/Loss ${title}`, - bottom: list.flatMap(({ color, name, tree }) => [ + bottom: list.flatMap(({ name, tree }) => [ /** @type {AnyFetchedSeriesBlueprint} */ ({ type: "Baseline", metric: tree.unrealized.netUnrealizedPnl, title: useGroupName ? name : "NUPL", colors: [colors.red, colors.green], + unit: Unit.ratio, options: { baseValue: { price: 0 } }, }), ]), @@ -377,6 +385,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { metric: tree.unrealized.unrealizedProfit, name: useGroupName ? name : "Profit", color, + unit: Unit.usd, }), ]), }, @@ -388,6 +397,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { metric: tree.unrealized.unrealizedLoss, name: useGroupName ? name : "Loss", color, + unit: Unit.usd, }), ]), }, @@ -419,6 +429,7 @@ function createCostBasisSectionWithPercentiles(ctx, list, useGroupName, title) { metric: tree.costBasis.minCostBasis, name: useGroupName ? name : "Min", color, + unit: Unit.usd, }), ), }, @@ -430,6 +441,7 @@ function createCostBasisSectionWithPercentiles(ctx, list, useGroupName, title) { metric: tree.costBasis.maxCostBasis, name: useGroupName ? name : "Max", color, + unit: Unit.usd, }), ), }, @@ -466,6 +478,7 @@ function createCostBasisSectionBasic(ctx, list, useGroupName, title) { metric: tree.costBasis.minCostBasis, name: useGroupName ? name : "Min", color, + unit: Unit.usd, }), ), }, @@ -477,6 +490,7 @@ function createCostBasisSectionBasic(ctx, list, useGroupName, title) { metric: tree.costBasis.maxCostBasis, name: useGroupName ? name : "Max", color, + unit: Unit.usd, }), ), }, @@ -494,7 +508,8 @@ function createCostBasisSectionBasic(ctx, list, useGroupName, title) { * @returns {PartialOptionsTree} */ function createActivitySection(ctx, list, useGroupName, title) { - const { s } = ctx; + const { s, brk } = ctx; + const { mergeMetricPatterns } = brk; return [ { @@ -505,9 +520,13 @@ function createActivitySection(ctx, list, useGroupName, title) { title: `Coinblocks Destroyed ${title}`, bottom: list.flatMap(({ color, name, tree }) => [ s({ - metric: tree.activity.coinblocksDestroyed.base, + metric: mergeMetricPatterns( + tree.activity.coinblocksDestroyed.base, + tree.activity.coinblocksDestroyed.sum, + ), name: useGroupName ? name : "Coinblocks", color, + unit: Unit.coinblocks, }), ]), }, @@ -516,9 +535,13 @@ function createActivitySection(ctx, list, useGroupName, title) { title: `Coindays Destroyed ${title}`, bottom: list.flatMap(({ color, name, tree }) => [ s({ - metric: tree.activity.coindaysDestroyed.base, + metric: mergeMetricPatterns( + tree.activity.coindaysDestroyed.base, + tree.activity.coindaysDestroyed.sum, + ), name: useGroupName ? name : "Coindays", color, + unit: Unit.coindays, }), ]), }, diff --git a/websites/bitview/scripts/options/cointime.js b/websites/bitview/scripts/options/cointime.js new file mode 100644 index 000000000..eacde4ff5 --- /dev/null +++ b/websites/bitview/scripts/options/cointime.js @@ -0,0 +1,502 @@ +/** Cointime section builder - typed tree-based patterns */ + +import { Unit } from "../utils/units.js"; + +/** + * Create price with ratio options for cointime prices + * @param {PartialContext} ctx + * @param {Object} args + * @param {string} args.title + * @param {string} args.legend + * @param {AnyMetricPattern} args.price + * @param {ActivePriceRatioPattern} args.ratio + * @param {Color} [args.color] + * @returns {PartialOptionsTree} + */ +function createCointimePriceWithRatioOptions( + ctx, + { title, legend, price, ratio, color }, +) { + const { s, colors, createPriceLine } = ctx; + + // Percentile USD mappings + const percentileUsdMap = [ + { name: "pct99", prop: ratio.ratioPct99Usd, color: colors.rose }, + { name: "pct98", prop: ratio.ratioPct98Usd, color: colors.pink }, + { name: "pct95", prop: ratio.ratioPct95Usd, color: colors.fuchsia }, + { name: "pct5", prop: ratio.ratioPct5Usd, color: colors.cyan }, + { name: "pct2", prop: ratio.ratioPct2Usd, color: colors.sky }, + { name: "pct1", prop: ratio.ratioPct1Usd, color: colors.blue }, + ]; + + // Percentile ratio mappings + const percentileMap = [ + { name: "pct99", prop: ratio.ratioPct99, color: colors.rose }, + { name: "pct98", prop: ratio.ratioPct98, color: colors.pink }, + { name: "pct95", prop: ratio.ratioPct95, color: colors.fuchsia }, + { name: "pct5", prop: ratio.ratioPct5, color: colors.cyan }, + { name: "pct2", prop: ratio.ratioPct2, color: colors.sky }, + { name: "pct1", prop: ratio.ratioPct1, color: colors.blue }, + ]; + + // SD patterns by window + const sdPatterns = [ + { nameAddon: "all", titleAddon: "", sd: ratio.ratioSd }, + { nameAddon: "4y", titleAddon: "4y", sd: ratio.ratio4ySd }, + { nameAddon: "2y", titleAddon: "2y", sd: ratio.ratio2ySd }, + { nameAddon: "1y", titleAddon: "1y", sd: ratio.ratio1ySd }, + ]; + + /** @param {Ratio1ySdPattern} sd */ + const getSdBands = (sd) => [ + { name: "0σ", prop: sd._0sdUsd, color: colors.lime }, + { name: "+0.5σ", prop: sd.p05sdUsd, color: colors.yellow }, + { name: "+1σ", prop: sd.p1sdUsd, color: colors.amber }, + { name: "+1.5σ", prop: sd.p15sdUsd, color: colors.orange }, + { name: "+2σ", prop: sd.p2sdUsd, color: colors.red }, + { name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose }, + { name: "+3σ", prop: sd.p3sd, color: colors.pink }, + { name: "−0.5σ", prop: sd.m05sdUsd, color: colors.teal }, + { name: "−1σ", prop: sd.m1sdUsd, color: colors.cyan }, + { name: "−1.5σ", prop: sd.m15sdUsd, color: colors.sky }, + { name: "−2σ", prop: sd.m2sdUsd, color: colors.blue }, + { name: "−2.5σ", prop: sd.m25sdUsd, color: colors.indigo }, + { name: "−3σ", prop: sd.m3sd, color: colors.violet }, + ]; + + return [ + { + name: "price", + title, + top: [s({ metric: price, name: legend, color, unit: Unit.usd })], + }, + { + name: "Ratio", + title: `${title} Ratio`, + top: [ + s({ metric: price, name: legend, color, unit: Unit.usd }), + ...percentileUsdMap.map(({ name: pctName, prop, color: pctColor }) => + s({ + metric: prop, + name: pctName, + color: pctColor, + defaultActive: false, + unit: Unit.usd, + options: { lineStyle: 1 }, + }), + ), + ], + bottom: [ + s({ metric: ratio.ratio, name: "Ratio", color, unit: Unit.ratio }), + s({ + metric: ratio.ratio1wSma, + name: "1w SMA", + color: colors.lime, + unit: Unit.ratio, + }), + s({ + metric: ratio.ratio1mSma, + name: "1m SMA", + color: colors.teal, + unit: Unit.ratio, + }), + s({ + metric: ratio.ratio1ySd.sma, + name: "1y SMA", + color: colors.sky, + unit: Unit.ratio, + }), + s({ + metric: ratio.ratio2ySd.sma, + name: "2y SMA", + color: colors.indigo, + unit: Unit.ratio, + }), + s({ + metric: ratio.ratio4ySd.sma, + name: "4y SMA", + color: colors.purple, + unit: Unit.ratio, + }), + s({ + metric: ratio.ratioSd.sma, + name: "All SMA", + color: colors.rose, + unit: Unit.ratio, + }), + ...percentileMap.map(({ name: pctName, prop, color: pctColor }) => + s({ + metric: prop, + name: pctName, + color: pctColor, + defaultActive: false, + unit: Unit.ratio, + options: { lineStyle: 1 }, + }), + ), + createPriceLine({ unit: Unit.ratio, number: 1 }), + ], + }, + { + name: "ZScores", + tree: sdPatterns.map(({ nameAddon, titleAddon, sd }) => ({ + name: nameAddon, + title: `${title} ${titleAddon} Z-Score`, + top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) => + s({ metric: prop, name: bandName, color: bandColor, unit: Unit.usd }), + ), + bottom: [ + s({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }), + createPriceLine({ unit: Unit.sd, number: 3 }), + createPriceLine({ unit: Unit.sd, number: 2 }), + createPriceLine({ unit: Unit.sd, number: 1 }), + createPriceLine({ unit: Unit.sd, number: 0 }), + createPriceLine({ unit: Unit.sd, number: -1 }), + createPriceLine({ unit: Unit.sd, number: -2 }), + createPriceLine({ unit: Unit.sd, number: -3 }), + ], + })), + }, + ]; +} + +/** + * Create Cointime section + * @param {PartialContext} ctx + * @returns {PartialOptionsGroup} + */ +export function createCointimeSection(ctx) { + const { colors, brk, s } = ctx; + const { mergeMetricPatterns } = brk; + const { cointime, distribution, supply } = brk.tree.computed; + const { pricing, cap, activity, supply: cointimeSupply, adjusted } = cointime; + const { all } = distribution.utxoCohorts; + + // Cointime prices data + const cointimePrices = [ + { + price: pricing.trueMarketMean, + ratio: pricing.trueMarketMeanRatio, + name: "True market mean", + title: "true market mean", + color: colors.blue, + }, + { + price: pricing.vaultedPrice, + ratio: pricing.vaultedPriceRatio, + name: "Vaulted", + title: "vaulted price", + color: colors.lime, + }, + { + price: pricing.activePrice, + ratio: pricing.activePriceRatio, + name: "Active", + title: "active price", + color: colors.rose, + }, + { + price: pricing.cointimePrice, + ratio: pricing.cointimePriceRatio, + name: "cointime", + title: "cointime price", + color: colors.yellow, + }, + ]; + + // Cointime capitalizations data + const cointimeCapitalizations = [ + { + metric: cap.vaultedCap, + name: "vaulted", + title: "vaulted Capitalization", + color: colors.lime, + }, + { + metric: cap.activeCap, + name: "active", + title: "active Capitalization", + color: colors.rose, + }, + { + metric: cap.cointimeCap, + name: "cointime", + title: "cointime Capitalization", + color: colors.yellow, + }, + { + metric: cap.investorCap, + name: "investor", + title: "investor Capitalization", + color: colors.fuchsia, + }, + { + metric: cap.thermoCap, + name: "thermo", + title: "thermo Capitalization", + color: colors.emerald, + }, + ]; + + return { + name: "Cointime", + tree: [ + // Prices + { + name: "Prices", + tree: [ + { + name: "Compare", + title: "Compare Cointime Prices", + top: cointimePrices.map(({ price, name, color }) => + s({ metric: price, name, color, unit: Unit.usd }), + ), + }, + ...cointimePrices.map(({ price, ratio, name, color, title }) => ({ + name, + tree: createCointimePriceWithRatioOptions(ctx, { + price, + ratio, + legend: name, + color, + title, + }), + })), + ], + }, + + // Capitalization + { + name: "Capitalization", + tree: [ + { + name: "Compare", + title: "Compare Cointime Capitalizations", + bottom: [ + s({ + metric: supply.marketCap.height, + name: "Market", + color: colors.default, + unit: Unit.usd, + }), + s({ + metric: all.realized.realizedCap, + name: "Realized", + color: colors.orange, + unit: Unit.usd, + }), + ...cointimeCapitalizations.map(({ metric, name, color }) => + s({ metric, name, color, unit: Unit.usd }), + ), + ], + }, + ...cointimeCapitalizations.map(({ metric, name, color, title }) => ({ + name, + title, + bottom: [ + s({ metric, name, color, unit: Unit.usd }), + s({ + metric: supply.marketCap.height, + name: "Market", + color: colors.default, + unit: Unit.usd, + }), + s({ + metric: all.realized.realizedCap, + name: "Realized", + color: colors.orange, + unit: Unit.usd, + }), + ], + })), + ], + }, + + // Supply + { + name: "Supply", + title: "Cointime Supply", + bottom: [ + // All supply (different pattern structure) + s({ + metric: all.supply.supply.sats, + name: "All", + color: colors.orange, + unit: Unit.sats, + }), + s({ + metric: all.supply.supply.bitcoin, + name: "All", + color: colors.orange, + unit: Unit.btc, + }), + s({ + metric: all.supply.supply.dollars, + name: "All", + color: colors.orange, + unit: Unit.usd, + }), + // Cointime supplies (ActiveSupplyPattern) + .../** @type {const} */ ([ + [cointimeSupply.vaultedSupply, "Vaulted", colors.lime], + [cointimeSupply.activeSupply, "Active", colors.rose], + ]).flatMap(([supplyItem, name, color]) => [ + s({ metric: supplyItem.sats, name, color, unit: Unit.sats }), + s({ metric: supplyItem.bitcoin, name, color, unit: Unit.btc }), + s({ metric: supplyItem.dollars, name, color, unit: Unit.usd }), + ]), + ], + }, + + // Liveliness & Vaultedness + { + name: "Liveliness & Vaultedness", + title: "Liveliness & Vaultedness", + bottom: [ + s({ + metric: activity.liveliness, + name: "Liveliness", + color: colors.rose, + unit: Unit.ratio, + }), + s({ + metric: activity.vaultedness, + name: "Vaultedness", + color: colors.lime, + unit: Unit.ratio, + }), + s({ + metric: activity.activityToVaultednessRatio, + name: "Liveliness / Vaultedness", + color: colors.purple, + unit: Unit.ratio, + }), + ], + }, + + // Coinblocks + { + name: "Coinblocks", + title: "Coinblocks", + bottom: [ + // Destroyed comes from the all cohort's activity + s({ + metric: mergeMetricPatterns( + all.activity.coinblocksDestroyed.base, + all.activity.coinblocksDestroyed.sum, + ), + name: "Destroyed", + color: colors.red, + unit: Unit.coinblocks, + }), + s({ + metric: all.activity.coinblocksDestroyed.cumulative, + name: "Cumulative Destroyed", + color: colors.red, + defaultActive: false, + unit: Unit.coinblocks, + }), + // Created and stored from cointime + s({ + metric: mergeMetricPatterns( + activity.coinblocksCreated.base, + activity.coinblocksCreated.sum, + ), + name: "Created", + color: colors.orange, + unit: Unit.coinblocks, + }), + s({ + metric: activity.coinblocksCreated.cumulative, + name: "Cumulative Created", + color: colors.orange, + defaultActive: false, + unit: Unit.coinblocks, + }), + s({ + metric: mergeMetricPatterns( + activity.coinblocksStored.base, + activity.coinblocksStored.sum, + ), + name: "Stored", + color: colors.green, + unit: Unit.coinblocks, + }), + s({ + metric: activity.coinblocksStored.cumulative, + name: "Cumulative Stored", + color: colors.green, + defaultActive: false, + unit: Unit.coinblocks, + }), + ], + }, + + // Adjusted metrics + { + name: "Adjusted", + tree: [ + // Inflation + { + name: "Inflation", + title: "Cointime-Adjusted Inflation Rate", + bottom: [ + s({ + metric: mergeMetricPatterns( + supply.inflation.indexes.dateindex, + supply.inflation.indexes.rest, + ), + name: "Base", + color: colors.orange, + unit: Unit.percentage, + }), + s({ + metric: adjusted.cointimeAdjInflationRate, + name: "Adjusted", + color: colors.purple, + unit: Unit.percentage, + }), + ], + }, + // Velocity + { + name: "Velocity", + title: "Cointime-Adjusted Transactions Velocity", + bottom: [ + s({ + metric: mergeMetricPatterns( + supply.velocity.btc.dateindex, + supply.velocity.btc.rest, + ), + name: "BTC", + color: colors.orange, + unit: Unit.ratio, + }), + s({ + metric: adjusted.cointimeAdjTxBtcVelocity, + name: "Adj. BTC", + color: colors.red, + unit: Unit.ratio, + }), + s({ + metric: mergeMetricPatterns( + supply.velocity.usd.dateindex, + supply.velocity.usd.rest, + ), + name: "USD", + color: colors.emerald, + unit: Unit.ratio, + }), + s({ + metric: adjusted.cointimeAdjTxUsdVelocity, + name: "Adj. USD", + color: colors.lime, + unit: Unit.ratio, + }), + ], + }, + ], + }, + ], + }; +} diff --git a/websites/bitview/scripts/options/partial/colors/cohorts.js b/websites/bitview/scripts/options/colors/cohorts.js similarity index 100% rename from websites/bitview/scripts/options/partial/colors/cohorts.js rename to websites/bitview/scripts/options/colors/cohorts.js diff --git a/websites/bitview/scripts/options/partial/colors/index.js b/websites/bitview/scripts/options/colors/index.js similarity index 100% rename from websites/bitview/scripts/options/partial/colors/index.js rename to websites/bitview/scripts/options/colors/index.js diff --git a/websites/bitview/scripts/options/partial/colors/misc.js b/websites/bitview/scripts/options/colors/misc.js similarity index 100% rename from websites/bitview/scripts/options/partial/colors/misc.js rename to websites/bitview/scripts/options/colors/misc.js diff --git a/websites/bitview/scripts/options/partial/constants.js b/websites/bitview/scripts/options/constants.js similarity index 100% rename from websites/bitview/scripts/options/partial/constants.js rename to websites/bitview/scripts/options/constants.js diff --git a/websites/bitview/scripts/options/partial/context.js b/websites/bitview/scripts/options/context.js similarity index 100% rename from websites/bitview/scripts/options/partial/context.js rename to websites/bitview/scripts/options/context.js diff --git a/websites/bitview/scripts/options/full.js b/websites/bitview/scripts/options/full.js index c718c7a62..54d99b1f1 100644 --- a/websites/bitview/scripts/options/full.js +++ b/websites/bitview/scripts/options/full.js @@ -1,13 +1,12 @@ -import { createPartialOptions } from "./partial/index.js"; +import { createPartialOptions } from "./partial.js"; import { createButtonElement, createAnchorElement, insertElementAtIndex, -} from "../utils/dom"; -import { serdeUnit } from "../utils/serde"; -import { pushHistory, resetParams } from "../utils/url"; -import { readStored, writeToStorage } from "../utils/storage"; -import { stringToId } from "../utils/format"; +} from "../utils/dom.js"; +import { pushHistory, resetParams } from "../utils/url.js"; +import { readStored, writeToStorage } from "../utils/storage.js"; +import { stringToId } from "../utils/format.js"; import { collect, markUsed, logUnused } from "./unused.js"; /** @@ -47,21 +46,28 @@ export function initOptions({ colors, signals, brk, qrcode }) { /** * @param {AnyFetchedSeriesBlueprint[]} [arr] */ - function arrayToRecord(arr = []) { - return [...(arr || [])].reduce((record, blueprint) => { + function arrayToMap(arr = []) { + /** @type {Map} */ + const map = new Map(); + for (const blueprint of arr || []) { if (!blueprint.metric) { throw new Error( `Blueprint missing metric: ${JSON.stringify(blueprint)}`, ); } + if (!blueprint.unit) { + throw new Error( + `Blueprint missing unit: ${blueprint.title}`, + ); + } markUsed(blueprint.metric); - // Use any index's path - unit is the same regardless of index (e.g., supply is "sats" for both height and dateindex) - const unit = - blueprint.unit ?? serdeUnit.deserialize(blueprint.metric.name); - record[unit] ??= []; - record[unit].push(blueprint); - return record; - }, /** @type {Record} */ ({})); + const unit = blueprint.unit; + if (!map.has(unit)) { + map.set(unit, []); + } + map.get(unit)?.push(blueprint); + } + return map; } /** @@ -77,11 +83,10 @@ export function initOptions({ colors, signals, brk, qrcode }) { /** * @param {Object} args * @param {Option} args.option - * @param {string} args.frame * @param {Signal} args.qrcode * @param {string} [args.name] */ - function createOptionElement({ option, frame, name, qrcode }) { + function createOptionElement({ option, name, qrcode }) { const title = option.title; if (option.kind === "url") { const href = option.url(); @@ -299,8 +304,8 @@ export function initOptions({ colors, signals, brk, qrcode }) { name, title, path, - top: arrayToRecord(anyPartial.top), - bottom: arrayToRecord(anyPartial.bottom), + top: arrayToMap(anyPartial.top), + bottom: arrayToMap(anyPartial.bottom), }), ); } @@ -338,7 +343,6 @@ export function initOptions({ colors, signals, brk, qrcode }) { const element = createOptionElement({ option, - frame: "nav", qrcode, }); diff --git a/websites/bitview/scripts/options/partial/market/averages.js b/websites/bitview/scripts/options/market/averages.js similarity index 79% rename from websites/bitview/scripts/options/partial/market/averages.js rename to websites/bitview/scripts/options/market/averages.js index b640f4a80..6c8855ccb 100644 --- a/websites/bitview/scripts/options/partial/market/averages.js +++ b/websites/bitview/scripts/options/market/averages.js @@ -1,5 +1,6 @@ /** Moving averages section */ +import { Unit } from "../../utils/units.js"; import { periodIdToName } from "./utils.js"; /** @@ -93,29 +94,29 @@ export function createPriceWithRatioOptions(ctx, { title, legend, ratio, color } { name: "price", title, - top: [s({ metric: priceMetric, name: legend, color, unit: "usd" })], + top: [s({ metric: priceMetric, name: legend, color, unit: Unit.usd })], }, { name: "Ratio", title: `${title} Ratio`, top: [ - s({ metric: priceMetric, name: legend, color, unit: "usd" }), + s({ metric: priceMetric, name: legend, color, unit: Unit.usd }), ...percentileUsdMap.map(({ name: pctName, prop, color: pctColor }) => - s({ metric: prop, name: pctName, color: pctColor, defaultActive: false, unit: "usd", options: { lineStyle: 1 } }), + s({ metric: prop, name: pctName, color: pctColor, defaultActive: false, unit: Unit.usd, options: { lineStyle: 1 } }), ), ], bottom: [ - s({ metric: ratio.ratio, name: "ratio", color, unit: "ratio" }), - s({ metric: ratio.ratio1wSma, name: "1w sma", color: colors.lime, unit: "ratio" }), - s({ metric: ratio.ratio1mSma, name: "1m sma", color: colors.teal, unit: "ratio" }), - s({ metric: ratio.ratio1ySd.sma, name: "1y sma", color: colors.sky, unit: "ratio" }), - s({ metric: ratio.ratio2ySd.sma, name: "2y sma", color: colors.indigo, unit: "ratio" }), - s({ metric: ratio.ratio4ySd.sma, name: "4y sma", color: colors.purple, unit: "ratio" }), - s({ metric: ratio.ratioSd.sma, name: "all sma", color: colors.rose, unit: "ratio" }), + s({ metric: ratio.ratio, name: "Ratio", color, unit: Unit.ratio }), + s({ metric: ratio.ratio1wSma, name: "1w SMA", color: colors.lime, unit: Unit.ratio }), + s({ metric: ratio.ratio1mSma, name: "1m SMA", color: colors.teal, unit: Unit.ratio }), + s({ metric: ratio.ratio1ySd.sma, name: "1y SMA", color: colors.sky, unit: Unit.ratio }), + s({ metric: ratio.ratio2ySd.sma, name: "2y SMA", color: colors.indigo, unit: Unit.ratio }), + s({ metric: ratio.ratio4ySd.sma, name: "4y SMA", color: colors.purple, unit: Unit.ratio }), + s({ metric: ratio.ratioSd.sma, name: "All SMA", color: colors.rose, unit: Unit.ratio }), ...percentileMap.map(({ name: pctName, prop, color: pctColor }) => - s({ metric: prop, name: pctName, color: pctColor, defaultActive: false, unit: "ratio", options: { lineStyle: 1 } }), + s({ metric: prop, name: pctName, color: pctColor, defaultActive: false, unit: Unit.ratio, options: { lineStyle: 1 } }), ), - createPriceLine({ unit: "ratio", number: 1 }), + createPriceLine({ unit: Unit.ratio, number: 1 }), ], }, { @@ -124,17 +125,17 @@ export function createPriceWithRatioOptions(ctx, { title, legend, ratio, color } name: nameAddon, title: `${title} ${titleAddon} Z-Score`, top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) => - s({ metric: prop, name: bandName, color: bandColor, unit: "usd" }), + s({ metric: prop, name: bandName, color: bandColor, unit: Unit.usd }), ), bottom: [ - s({ metric: sd.zscore, name: "zscore", color, unit: "sd" }), - createPriceLine({ unit: "sd", number: 3 }), - createPriceLine({ unit: "sd", number: 2 }), - createPriceLine({ unit: "sd", number: 1 }), - createPriceLine({ unit: "sd", number: 0 }), - createPriceLine({ unit: "sd", number: -1 }), - createPriceLine({ unit: "sd", number: -2 }), - createPriceLine({ unit: "sd", number: -3 }), + s({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }), + createPriceLine({ unit: Unit.sd, number: 3 }), + createPriceLine({ unit: Unit.sd, number: 2 }), + createPriceLine({ unit: Unit.sd, number: 1 }), + createPriceLine({ unit: Unit.sd, number: 0 }), + createPriceLine({ unit: Unit.sd, number: -1 }), + createPriceLine({ unit: Unit.sd, number: -2 }), + createPriceLine({ unit: Unit.sd, number: -3 }), ], })), }, @@ -161,7 +162,7 @@ export function createAveragesSection(ctx, averages) { name: "Compare", title: `Market Price ${nameAddon} Moving Averages`, top: averages.map(({ id, color, sma, ema }) => - s({ metric: (metricAddon === "sma" ? sma : ema).price, name: id, color, unit: "usd" }), + s({ metric: (metricAddon === "sma" ? sma : ema).price, name: id, color, unit: Unit.usd }), ), }, ...averages.map(({ name, color, sma, ema }) => ({ diff --git a/websites/bitview/scripts/options/market/index.js b/websites/bitview/scripts/options/market/index.js new file mode 100644 index 000000000..9a747a66f --- /dev/null +++ b/websites/bitview/scripts/options/market/index.js @@ -0,0 +1,106 @@ +/** Market section - Main entry point */ + +import { Unit } from "../../utils/units.js"; +import { buildAverages, createAveragesSection } from "./averages.js"; +import { createPerformanceSection } from "./performance.js"; +import { createIndicatorsSection } from "./indicators/index.js"; +import { createInvestingSection } from "./investing.js"; + +/** + * Create Market section + * @param {PartialContext} ctx + * @returns {PartialOptionsGroup} + */ +export function createMarketSection(ctx) { + const { colors, brk, s } = ctx; + const { market, supply } = brk.tree.computed; + const { + movingAverage, + ath, + returns, + volatility, + range, + dca, + lookback, + indicators, + } = market; + + const averages = buildAverages(colors, movingAverage); + + return { + name: "Market", + tree: [ + // Price + { + name: "Price", + title: "Bitcoin Price", + }, + + // Capitalization + { + name: "Capitalization", + title: "Market Capitalization", + bottom: [ + s({ + metric: brk.mergeMetricPatterns( + supply.marketCap.height, + supply.marketCap.indexes, + ), + name: "Capitalization", + unit: Unit.usd, + }), + ], + }, + + // All Time High + { + name: "All Time High", + title: "All Time High", + top: [s({ metric: ath.priceAth, name: "ATH", unit: Unit.usd })], + bottom: [ + s({ + metric: ath.priceDrawdown, + name: "Drawdown", + color: colors.red, + unit: Unit.percentage, + }), + s({ metric: ath.daysSincePriceAth, name: "Since", unit: Unit.days }), + s({ + metric: ath.yearsSincePriceAth, + name: "Since", + unit: Unit.years, + }), + s({ + metric: ath.maxDaysBetweenPriceAths, + name: "Max", + color: colors.red, + unit: Unit.days, + }), + s({ + metric: ath.maxYearsBetweenPriceAths, + name: "Max", + color: colors.red, + unit: Unit.years, + }), + ], + }, + + // Averages + createAveragesSection(ctx, averages), + + // Performance + createPerformanceSection(ctx, returns), + + // Indicators + createIndicatorsSection(ctx, { + volatility, + range, + movingAverage, + indicators, + }), + + // Investing + createInvestingSection(ctx, { dca, lookback, returns }), + ], + }; +} diff --git a/websites/bitview/scripts/options/market/indicators/bands.js b/websites/bitview/scripts/options/market/indicators/bands.js new file mode 100644 index 000000000..7ddca93e7 --- /dev/null +++ b/websites/bitview/scripts/options/market/indicators/bands.js @@ -0,0 +1,85 @@ +/** Bands indicators (MinMax, Mayer Multiple) */ + +import { Unit } from "../../../utils/units.js"; + +/** + * Create Bands section + * @param {PartialContext} ctx + * @param {Object} args + * @param {Market["range"]} args.range + * @param {Market["movingAverage"]} args.movingAverage + */ +export function createBandsSection(ctx, { range, movingAverage }) { + const { s, colors } = ctx; + + return { + name: "Bands", + tree: [ + { + name: "MinMax", + tree: [ + { + id: "1w", + title: "1 Week", + min: range.price1wMin, + max: range.price1wMax, + }, + { + id: "2w", + title: "2 Week", + min: range.price2wMin, + max: range.price2wMax, + }, + { + id: "1m", + title: "1 Month", + min: range.price1mMin, + max: range.price1mMax, + }, + { + id: "1y", + title: "1 Year", + min: range.price1yMin, + max: range.price1yMax, + }, + ].map(({ id, title, min, max }) => ({ + name: id, + title: `Bitcoin Price ${title} MinMax Bands`, + top: [ + s({ metric: min, name: "Min", color: colors.red, unit: Unit.usd }), + s({ + metric: max, + name: "Max", + color: colors.green, + unit: Unit.usd, + }), + ], + })), + }, + { + name: "Mayer Multiple", + title: "Mayer Multiple", + top: [ + s({ + metric: movingAverage.price200dSma.price, + name: "200d SMA", + color: colors.yellow, + unit: Unit.usd, + }), + s({ + metric: movingAverage.price200dSmaX24, + name: "200d SMA x2.4", + color: colors.green, + unit: Unit.usd, + }), + s({ + metric: movingAverage.price200dSmaX08, + name: "200d SMA x0.8", + color: colors.red, + unit: Unit.usd, + }), + ], + }, + ], + }; +} diff --git a/websites/bitview/scripts/options/partial/market/indicators/index.js b/websites/bitview/scripts/options/market/indicators/index.js similarity index 100% rename from websites/bitview/scripts/options/partial/market/indicators/index.js rename to websites/bitview/scripts/options/market/indicators/index.js diff --git a/websites/bitview/scripts/options/partial/market/indicators/momentum.js b/websites/bitview/scripts/options/market/indicators/momentum.js similarity index 71% rename from websites/bitview/scripts/options/partial/market/indicators/momentum.js rename to websites/bitview/scripts/options/market/indicators/momentum.js index c96f03208..94a0786f2 100644 --- a/websites/bitview/scripts/options/partial/market/indicators/momentum.js +++ b/websites/bitview/scripts/options/market/indicators/momentum.js @@ -1,5 +1,7 @@ /** Momentum indicators (RSI, StochRSI, Stochastic, MACD) */ +import { Unit } from "../../../utils/units.js"; + /** * Create Momentum section * @param {PartialContext} ctx @@ -19,25 +21,25 @@ export function createMomentumSection(ctx, indicators) { metric: indicators.rsi14d, name: "RSI", color: colors.indigo, - unit: "index", + unit: Unit.index, }), s({ metric: indicators.rsi14dMin, name: "Min", color: colors.red, defaultActive: false, - unit: "index", + unit: Unit.index, }), s({ metric: indicators.rsi14dMax, name: "Max", color: colors.green, defaultActive: false, - unit: "index", + unit: Unit.index, }), - createPriceLine({ unit: "index", number: 70 }), - createPriceLine({ unit: "index", number: 50, defaultActive: false }), - createPriceLine({ unit: "index", number: 30 }), + createPriceLine({ unit: Unit.index, number: 70 }), + createPriceLine({ unit: Unit.index, number: 50, defaultActive: false }), + createPriceLine({ unit: Unit.index, number: 30 }), ], }, { @@ -48,32 +50,32 @@ export function createMomentumSection(ctx, indicators) { // metric: indicators.stochRsi, // name: "Stoch RSI", // color: colors.purple, - // unit: "index", + // unit: Unit.index, // }), s({ metric: indicators.stochRsiK, name: "K", color: colors.blue, - unit: "index", + unit: Unit.index, }), s({ metric: indicators.stochRsiD, name: "D", color: colors.orange, - unit: "index", + unit: Unit.index, }), - createPriceLine({ unit: "index", number: 80 }), - createPriceLine({ unit: "index", number: 20 }), + createPriceLine({ unit: Unit.index, number: 80 }), + createPriceLine({ unit: Unit.index, number: 20 }), ], }, // { // name: "Stochastic", // title: "Stochastic Oscillator", // bottom: [ - // s({ metric: indicators.stochK, name: "K", color: colors.blue, unit: "index" }), - // s({ metric: indicators.stochD, name: "D", color: colors.orange, unit: "index" }), - // createPriceLine({ unit: "index", number: 80 }), - // createPriceLine({ unit: "index", number: 20 }), + // s({ metric: indicators.stochK, name: "K", color: colors.blue, unit: Unit.index }), + // s({ metric: indicators.stochD, name: "D", color: colors.orange, unit: Unit.index }), + // createPriceLine({ unit: Unit.index, number: 80 }), + // createPriceLine({ unit: Unit.index, number: 20 }), // ], // }, { @@ -84,21 +86,21 @@ export function createMomentumSection(ctx, indicators) { metric: indicators.macdLine, name: "MACD", color: colors.blue, - unit: "usd", + unit: Unit.usd, }), s({ metric: indicators.macdSignal, name: "Signal", color: colors.orange, - unit: "usd", + unit: Unit.usd, }), /** @type {FetchedHistogramSeriesBlueprint} */ ({ metric: indicators.macdHistogram, title: "Histogram", type: "Histogram", - unit: "usd", + unit: Unit.usd, }), - createPriceLine({ unit: "usd" }), + createPriceLine({ unit: Unit.usd }), ], }, ], diff --git a/websites/bitview/scripts/options/partial/market/indicators/onchain.js b/websites/bitview/scripts/options/market/indicators/onchain.js similarity index 85% rename from websites/bitview/scripts/options/partial/market/indicators/onchain.js rename to websites/bitview/scripts/options/market/indicators/onchain.js index eda97cae4..6e60f7568 100644 --- a/websites/bitview/scripts/options/partial/market/indicators/onchain.js +++ b/websites/bitview/scripts/options/market/indicators/onchain.js @@ -1,5 +1,7 @@ /** On-chain indicators (Pi Cycle, Puell, NVT, Gini) */ +import { Unit } from "../../../utils/units.js"; + /** * Create On-chain section * @param {PartialContext} ctx @@ -21,13 +23,13 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) { metric: movingAverage.price111dSma.price, name: "111d SMA", color: colors.green, - unit: "usd", + unit: Unit.usd, }), s({ metric: movingAverage.price350dSmaX2, name: "350d SMA x2", color: colors.red, - unit: "usd", + unit: Unit.usd, }), ], bottom: [ @@ -35,9 +37,9 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) { metric: indicators.piCycle, name: "Pi Cycle", color: colors.purple, - unit: "ratio", + unit: Unit.ratio, }), - createPriceLine({ unit: "ratio", number: 1 }), + createPriceLine({ unit: Unit.ratio, number: 1 }), ], }, { @@ -48,7 +50,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) { metric: indicators.puellMultiple, name: "Puell", color: colors.green, - unit: "ratio", + unit: Unit.ratio, }), ], }, @@ -60,7 +62,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) { metric: indicators.nvt, name: "NVT", color: colors.orange, - unit: "ratio", + unit: Unit.ratio, }), ], }, @@ -72,7 +74,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) { metric: indicators.gini, name: "Gini", color: colors.red, - unit: "ratio", + unit: Unit.ratio, }), ], }, diff --git a/websites/bitview/scripts/options/partial/market/indicators/volatility.js b/websites/bitview/scripts/options/market/indicators/volatility.js similarity index 68% rename from websites/bitview/scripts/options/partial/market/indicators/volatility.js rename to websites/bitview/scripts/options/market/indicators/volatility.js index 89574c83e..05126bf70 100644 --- a/websites/bitview/scripts/options/partial/market/indicators/volatility.js +++ b/websites/bitview/scripts/options/market/indicators/volatility.js @@ -1,5 +1,7 @@ /** Volatility indicators (Index, True Range, Choppiness, Sharpe, Sortino) */ +import { Unit } from "../../../utils/units.js"; + /** * Create Volatility section * @param {PartialContext} ctx @@ -17,43 +19,43 @@ export function createVolatilitySection(ctx, { volatility, range }) { name: "Index", title: "Bitcoin Price Volatility Index", bottom: [ - s({ metric: volatility.price1wVolatility, name: "1w", color: colors.red, unit: "percentage" }), - s({ metric: volatility.price1mVolatility, name: "1m", color: colors.orange, unit: "percentage" }), - s({ metric: volatility.price1yVolatility, name: "1y", color: colors.lime, unit: "percentage" }), + s({ metric: volatility.price1wVolatility, name: "1w", color: colors.red, unit: Unit.percentage }), + s({ metric: volatility.price1mVolatility, name: "1m", color: colors.orange, unit: Unit.percentage }), + s({ metric: volatility.price1yVolatility, name: "1y", color: colors.lime, unit: Unit.percentage }), ], }, { name: "True Range", title: "Bitcoin Price True Range", - bottom: [s({ metric: range.priceTrueRange, name: "value", color: colors.yellow, unit: "usd" })], + bottom: [s({ metric: range.priceTrueRange, name: "Value", color: colors.yellow, unit: Unit.usd })], }, { name: "Choppiness", title: "Bitcoin Price Choppiness Index", bottom: [ - s({ metric: range.price2wChoppinessIndex, name: "2w", color: colors.red, unit: "index" }), - createPriceLine({ unit: "index", number: 61.8 }), - createPriceLine({ unit: "index", number: 38.2 }), + s({ metric: range.price2wChoppinessIndex, name: "2w", color: colors.red, unit: Unit.index }), + createPriceLine({ unit: Unit.index, number: 61.8 }), + createPriceLine({ unit: Unit.index, number: 38.2 }), ], }, { name: "Sharpe Ratio", title: "Sharpe Ratio", bottom: [ - s({ metric: volatility.sharpe1w, name: "1w", color: colors.red, unit: "ratio" }), - s({ metric: volatility.sharpe1m, name: "1m", color: colors.orange, unit: "ratio" }), - s({ metric: volatility.sharpe1y, name: "1y", color: colors.lime, unit: "ratio" }), - createPriceLine({ unit: "ratio" }), + s({ metric: volatility.sharpe1w, name: "1w", color: colors.red, unit: Unit.ratio }), + s({ metric: volatility.sharpe1m, name: "1m", color: colors.orange, unit: Unit.ratio }), + s({ metric: volatility.sharpe1y, name: "1y", color: colors.lime, unit: Unit.ratio }), + createPriceLine({ unit: Unit.ratio }), ], }, { name: "Sortino Ratio", title: "Sortino Ratio", bottom: [ - s({ metric: volatility.sortino1w, name: "1w", color: colors.red, unit: "ratio" }), - s({ metric: volatility.sortino1m, name: "1m", color: colors.orange, unit: "ratio" }), - s({ metric: volatility.sortino1y, name: "1y", color: colors.lime, unit: "ratio" }), - createPriceLine({ unit: "ratio" }), + s({ metric: volatility.sortino1w, name: "1w", color: colors.red, unit: Unit.ratio }), + s({ metric: volatility.sortino1m, name: "1m", color: colors.orange, unit: Unit.ratio }), + s({ metric: volatility.sortino1y, name: "1y", color: colors.lime, unit: Unit.ratio }), + createPriceLine({ unit: Unit.ratio }), ], }, ], diff --git a/websites/bitview/scripts/options/partial/market/investing.js b/websites/bitview/scripts/options/market/investing.js similarity index 51% rename from websites/bitview/scripts/options/partial/market/investing.js rename to websites/bitview/scripts/options/market/investing.js index ef64b551d..0b6671fd6 100644 --- a/websites/bitview/scripts/options/partial/market/investing.js +++ b/websites/bitview/scripts/options/market/investing.js @@ -1,5 +1,6 @@ /** Investing section (DCA) */ +import { Unit } from "../../utils/units.js"; import { periodIdToName } from "./utils.js"; /** @@ -24,7 +25,7 @@ export function buildDcaClasses(colors, dca) { year, color: colors[colorKey], defaultActive, - costBasis: dca.classAvgPrice[`_${year}`], + costBasis: dca.classAveragePrice[`_${year}`], returns: dca.classReturns[`_${year}`], stack: dca.classStack[`_${year}`], })); @@ -65,7 +66,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { const name = periodIdToName(id, true); const priceAgo = lookback.priceAgo[key]; const priceReturns = returns.priceReturns[key]; - const dcaCostBasis = dca.periodAvgPrice[key]; + const dcaCostBasis = dca.periodAveragePrice[key]; const dcaReturns = dca.periodReturns[key]; const dcaStack = dca.periodStack[key]; const lumpSumStack = dca.periodLumpSumStack[key]; @@ -76,8 +77,18 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { name: "Cost basis", title: `${name} DCA vs Lump Sum (Cost Basis)`, top: [ - s({ metric: dcaCostBasis, name: "DCA", color: colors.green, unit: "usd" }), - s({ metric: priceAgo, name: "Lump sum", color: colors.orange, unit: "usd" }), + s({ + metric: dcaCostBasis, + name: "DCA", + color: colors.green, + unit: Unit.usd, + }), + s({ + metric: priceAgo, + name: "Lump sum", + color: colors.orange, + unit: Unit.usd, + }), ], }, { @@ -88,28 +99,58 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { metric: dcaReturns, title: "DCA", type: "Baseline", - unit: "percentage", + unit: Unit.percentage, }), /** @type {AnyFetchedSeriesBlueprint} */ ({ metric: priceReturns, title: "Lump sum", type: "Baseline", colors: [colors.lime, colors.red], - unit: "percentage", + unit: Unit.percentage, }), - createPriceLine({ unit: "percentage" }), + createPriceLine({ unit: Unit.percentage }), ], }, { name: "Stack", title: `${name} DCA vs Lump Sum Stack ($100/day)`, bottom: [ - s({ metric: dcaStack.sats, name: "DCA", color: colors.green, unit: "sats" }), - s({ metric: dcaStack.bitcoin, name: "DCA", color: colors.green, unit: "btc" }), - s({ metric: dcaStack.dollars, name: "DCA", color: colors.green, unit: "usd" }), - s({ metric: lumpSumStack.sats, name: "Lump sum", color: colors.orange, unit: "sats" }), - s({ metric: lumpSumStack.bitcoin, name: "Lump sum", color: colors.orange, unit: "btc" }), - s({ metric: lumpSumStack.dollars, name: "Lump sum", color: colors.orange, unit: "usd" }), + s({ + metric: dcaStack.sats, + name: "DCA", + color: colors.green, + unit: Unit.sats, + }), + s({ + metric: dcaStack.bitcoin, + name: "DCA", + color: colors.green, + unit: Unit.btc, + }), + s({ + metric: dcaStack.dollars, + name: "DCA", + color: colors.green, + unit: Unit.usd, + }), + s({ + metric: lumpSumStack.sats, + name: "Lump sum", + color: colors.orange, + unit: Unit.sats, + }), + s({ + metric: lumpSumStack.bitcoin, + name: "Lump sum", + color: colors.orange, + unit: Unit.btc, + }), + s({ + metric: lumpSumStack.dollars, + name: "Lump sum", + color: colors.orange, + unit: Unit.usd, + }), ], }, ], @@ -128,32 +169,60 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { { name: "Cost basis", title: "DCA Cost Basis by Year", - top: dcaClasses.map(({ year, color, defaultActive, costBasis }) => - s({ metric: costBasis, name: `${year}`, color, defaultActive, unit: "usd" }), + top: dcaClasses.map( + ({ year, color, defaultActive, costBasis }) => + s({ + metric: costBasis, + name: `${year}`, + color, + defaultActive, + unit: Unit.usd, + }), ), }, { name: "Returns", title: "DCA Returns by Year", - bottom: dcaClasses.map(({ year, color, defaultActive, returns }) => - /** @type {AnyFetchedSeriesBlueprint} */ ({ - metric: returns, - title: `${year}`, - type: "Baseline", - color, - defaultActive, - unit: "percentage", - }), + bottom: dcaClasses.map( + ({ year, color, defaultActive, returns }) => + /** @type {AnyFetchedSeriesBlueprint} */ ({ + metric: returns, + title: `${year}`, + type: "Baseline", + color, + defaultActive, + unit: Unit.percentage, + }), ), }, { name: "Stack", title: "DCA Stack by Year ($100/day)", - bottom: dcaClasses.flatMap(({ year, color, defaultActive, stack }) => [ - s({ metric: stack.sats, name: `${year}`, color, defaultActive, unit: "sats" }), - s({ metric: stack.bitcoin, name: `${year}`, color, defaultActive, unit: "btc" }), - s({ metric: stack.dollars, name: `${year}`, color, defaultActive, unit: "usd" }), - ]), + bottom: dcaClasses.flatMap( + ({ year, color, defaultActive, stack }) => [ + s({ + metric: stack.sats, + name: `${year}`, + color, + defaultActive, + unit: Unit.sats, + }), + s({ + metric: stack.bitcoin, + name: `${year}`, + color, + defaultActive, + unit: Unit.btc, + }), + s({ + metric: stack.dollars, + name: `${year}`, + color, + defaultActive, + unit: Unit.usd, + }), + ], + ), }, ], }, @@ -164,7 +233,14 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { { name: "Cost basis", title: `DCA Class ${year} Cost Basis`, - top: [s({ metric: costBasis, name: "Cost basis", color, unit: "usd" })], + top: [ + s({ + metric: costBasis, + name: "Cost basis", + color, + unit: Unit.usd, + }), + ], }, { name: "Returns", @@ -175,7 +251,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { title: "Returns", type: "Baseline", color, - unit: "percentage", + unit: Unit.percentage, }), ], }, @@ -183,9 +259,24 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { name: "Stack", title: `DCA Class ${year} Stack ($100/day)`, bottom: [ - s({ metric: stack.sats, name: "Stack", color, unit: "sats" }), - s({ metric: stack.bitcoin, name: "Stack", color, unit: "btc" }), - s({ metric: stack.dollars, name: "Stack", color, unit: "usd" }), + s({ + metric: stack.sats, + name: "Stack", + color, + unit: Unit.sats, + }), + s({ + metric: stack.bitcoin, + name: "Stack", + color, + unit: Unit.btc, + }), + s({ + metric: stack.dollars, + name: "Stack", + color, + unit: Unit.usd, + }), ], }, ], diff --git a/websites/bitview/scripts/options/partial/market/performance.js b/websites/bitview/scripts/options/market/performance.js similarity index 86% rename from websites/bitview/scripts/options/partial/market/performance.js rename to websites/bitview/scripts/options/market/performance.js index 8713da05b..b38f34c6b 100644 --- a/websites/bitview/scripts/options/partial/market/performance.js +++ b/websites/bitview/scripts/options/market/performance.js @@ -1,5 +1,6 @@ /** Performance section */ +import { Unit } from "../../utils/units.js"; import { periodIdToName } from "./utils.js"; /** @@ -36,22 +37,22 @@ export function createPerformanceSection(ctx, returns) { bottom: [ /** @type {AnyFetchedSeriesBlueprint} */ ({ metric: priceReturns, - title: "total", + title: "Total", type: "Baseline", - unit: "percentage", + unit: Unit.percentage, }), ...(cagr ? [ /** @type {AnyFetchedSeriesBlueprint} */ ({ metric: cagr, - title: "cagr", + title: "CAGR", type: "Baseline", colors: [colors.lime, colors.pink], - unit: "percentage", + unit: Unit.percentage, }), ] : []), - createPriceLine({ unit: "percentage" }), + createPriceLine({ unit: Unit.percentage }), ], }; }), diff --git a/websites/bitview/scripts/options/partial/market/utils.js b/websites/bitview/scripts/options/market/utils.js similarity index 100% rename from websites/bitview/scripts/options/partial/market/utils.js rename to websites/bitview/scripts/options/market/utils.js diff --git a/websites/bitview/scripts/options/partial/index.js b/websites/bitview/scripts/options/partial.js similarity index 99% rename from websites/bitview/scripts/options/partial/index.js rename to websites/bitview/scripts/options/partial.js index fc2e55b06..97f2c795f 100644 --- a/websites/bitview/scripts/options/partial/index.js +++ b/websites/bitview/scripts/options/partial.js @@ -1,6 +1,6 @@ /** Partial options - Main entry point */ -import { localhost } from "../../utils/env.js"; +import { localhost } from "../utils/env.js"; import { createContext } from "./context.js"; import { buildCohortData, diff --git a/websites/bitview/scripts/options/partial/chain.js b/websites/bitview/scripts/options/partial/chain.js deleted file mode 100644 index 38379b1cf..000000000 --- a/websites/bitview/scripts/options/partial/chain.js +++ /dev/null @@ -1,485 +0,0 @@ -/** Chain section builder - typed tree-based patterns */ - -/** - * Create Chain section - * @param {PartialContext} ctx - * @returns {PartialOptionsGroup} - */ -export function createChainSection(ctx) { - const { colors, brk, s, createPriceLine } = ctx; - const { blocks, transactions, pools, inputs, outputs, market, scripts, supply } = brk.tree.computed; - const { indexed } = brk.tree; - - /** - * Create sum/cumulative series from a BlockCountPattern - * @template T - * @param {BlockCountPattern} pattern - * @param {string} name - * @param {Color} [sumColor] - * @param {Color} [cumulativeColor] - * @param {Unit} unit - */ - const fromBlockCount = (pattern, name, unit, sumColor, cumulativeColor) => [ - s({ metric: pattern.base, name: `${name} sum`, color: sumColor, unit }), - s({ metric: pattern.cumulative, name: `${name} cumulative`, color: cumulativeColor ?? colors.blue, unit, defaultActive: false }), - ]; - - /** - * Create series from BlockSizePattern (has average, min, max, percentiles) - * @template T - * @param {BlockSizePattern} pattern - * @param {string} name - * @param {Unit} unit - */ - const fromBlockSize = (pattern, name, unit) => [ - s({ metric: pattern.average, name: `${name} avg`, unit }), - s({ metric: pattern.sum, name: `${name} sum`, color: colors.blue, unit, defaultActive: false }), - s({ metric: pattern.cumulative, name: `${name} cumulative`, color: colors.indigo, unit, defaultActive: false }), - s({ metric: pattern.min, name: `${name} min`, color: colors.red, unit, defaultActive: false }), - s({ metric: pattern.max, name: `${name} max`, color: colors.green, unit, defaultActive: false }), - s({ metric: pattern.pct10, name: `${name} pct10`, color: colors.rose, unit, defaultActive: false }), - s({ metric: pattern.pct25, name: `${name} pct25`, color: colors.pink, unit, defaultActive: false }), - s({ metric: pattern.median, name: `${name} median`, color: colors.purple, unit, defaultActive: false }), - s({ metric: pattern.pct75, name: `${name} pct75`, color: colors.violet, unit, defaultActive: false }), - s({ metric: pattern.pct90, name: `${name} pct90`, color: colors.fuchsia, unit, defaultActive: false }), - ]; - - /** - * Create series from BlockIntervalPattern (has average, min, max, percentiles) - * @template T - * @param {BlockIntervalPattern} pattern - * @param {string} name - * @param {Unit} unit - */ - const fromBlockInterval = (pattern, name, unit) => [ - s({ metric: pattern.average, name: `${name} avg`, unit }), - s({ metric: pattern.min, name: `${name} min`, color: colors.red, unit, defaultActive: false }), - s({ metric: pattern.max, name: `${name} max`, color: colors.green, unit, defaultActive: false }), - s({ metric: pattern.pct10, name: `${name} pct10`, color: colors.rose, unit, defaultActive: false }), - s({ metric: pattern.pct25, name: `${name} pct25`, color: colors.pink, unit, defaultActive: false }), - s({ metric: pattern.median, name: `${name} median`, color: colors.purple, unit, defaultActive: false }), - s({ metric: pattern.pct75, name: `${name} pct75`, color: colors.violet, unit, defaultActive: false }), - s({ metric: pattern.pct90, name: `${name} pct90`, color: colors.fuchsia, unit, defaultActive: false }), - ]; - - /** - * Create series from BitcoinPattern (has base, cumulative) - * @template T - * @param {BitcoinPattern} pattern - * @param {string} name - * @param {Unit} unit - * @param {Color} [sumColor] - * @param {Color} [cumulativeColor] - */ - const fromBitcoin = (pattern, name, unit, sumColor, cumulativeColor) => [ - s({ metric: pattern.base, name: `${name}`, color: sumColor, unit }), - s({ metric: pattern.cumulative, name: `${name} cumulative`, color: cumulativeColor ?? colors.blue, unit, defaultActive: false }), - ]; - - /** - * Create series from CoinbasePattern (has sats, bitcoin, dollars as BitcoinPattern) - * BitcoinPattern has .base and .cumulative (no .sum) - * @param {CoinbasePattern} pattern - * @param {string} name - * @param {Color} sumColor - * @param {Color} cumulativeColor - */ - const fromCoinbase = (pattern, name, sumColor, cumulativeColor) => [ - s({ metric: pattern.sats.base, name: `${name}`, color: sumColor, unit: "sats" }), - s({ metric: pattern.sats.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "sats", defaultActive: false }), - s({ metric: pattern.bitcoin.base, name: `${name}`, color: sumColor, unit: "btc" }), - s({ metric: pattern.bitcoin.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "btc", defaultActive: false }), - s({ metric: pattern.dollars.base, name: `${name}`, color: sumColor, unit: "usd" }), - s({ metric: pattern.dollars.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "usd", defaultActive: false }), - ]; - - /** - * Create series from ValuePattern (has sats, bitcoin, dollars as BlockCountPattern) - * BlockCountPattern has .base, .sum, and .cumulative - * @param {ValuePattern} pattern - * @param {string} name - * @param {Color} sumColor - * @param {Color} cumulativeColor - */ - const fromValuePattern = (pattern, name, sumColor, cumulativeColor) => [ - s({ metric: pattern.sats.base, name: `${name}`, color: sumColor, unit: "sats" }), - s({ metric: pattern.sats.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "sats", defaultActive: false }), - s({ metric: pattern.bitcoin.base, name: `${name}`, color: sumColor, unit: "btc" }), - s({ metric: pattern.bitcoin.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "btc", defaultActive: false }), - s({ metric: pattern.dollars.base, name: `${name}`, color: sumColor, unit: "usd" }), - s({ metric: pattern.dollars.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "usd", defaultActive: false }), - ]; - - /** - * Create series from RewardPattern (has .base as Indexes2, plus bitcoin/dollars as BlockCountPattern, sats as SatsPattern) - * Note: SatsPattern only has cumulative and sum, so we use pattern.base for raw sats - * @param {RewardPattern} pattern - * @param {string} name - * @param {Color} sumColor - * @param {Color} cumulativeColor - */ - const fromRewardPattern = (pattern, name, sumColor, cumulativeColor) => [ - s({ metric: pattern.base, name: `${name}`, color: sumColor, unit: "sats" }), - s({ metric: pattern.sats.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "sats", defaultActive: false }), - s({ metric: pattern.bitcoin.base, name: `${name}`, color: sumColor, unit: "btc" }), - s({ metric: pattern.bitcoin.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "btc", defaultActive: false }), - s({ metric: pattern.dollars.base, name: `${name}`, color: sumColor, unit: "usd" }), - s({ metric: pattern.dollars.cumulative, name: `${name} cumulative`, color: cumulativeColor, unit: "usd", defaultActive: false }), - ]; - - // Build pools tree dynamically - const poolEntries = Object.entries(pools.vecs); - const poolsTree = poolEntries.map(([key, pool]) => { - const poolName = brk.POOL_ID_TO_POOL_NAME[/** @type {keyof typeof brk.POOL_ID_TO_POOL_NAME} */ (key.toLowerCase())] || key; - return { - name: poolName, - tree: [ - { - name: "Dominance", - title: `Mining Dominance of ${poolName}`, - bottom: [ - s({ metric: pool._1dDominance.base, name: "1d", color: colors.rose, unit: "percentage", defaultActive: false }), - s({ metric: pool._1wDominance, name: "1w", color: colors.red, unit: "percentage", defaultActive: false }), - s({ metric: pool._1mDominance, name: "1m", unit: "percentage" }), - s({ metric: pool._1yDominance, name: "1y", color: colors.lime, unit: "percentage", defaultActive: false }), - s({ metric: pool.dominance.base, name: "all time", color: colors.teal, unit: "percentage", defaultActive: false }), - ], - }, - { - name: "Blocks mined", - title: `Blocks mined by ${poolName}`, - bottom: [ - s({ metric: pool.blocksMined.base, name: "Sum", unit: "count" }), - s({ metric: pool.blocksMined.cumulative, name: "Cumulative", color: colors.blue, unit: "count" }), - s({ metric: pool._1wBlocksMined, name: "1w Sum", color: colors.red, unit: "count", defaultActive: false }), - s({ metric: pool._1mBlocksMined, name: "1m Sum", color: colors.pink, unit: "count", defaultActive: false }), - s({ metric: pool._1yBlocksMined, name: "1y Sum", color: colors.purple, unit: "count", defaultActive: false }), - ], - }, - { - name: "Rewards", - title: `Rewards collected by ${poolName}`, - bottom: [ - ...fromValuePattern(pool.coinbase, "coinbase", colors.orange, colors.red), - ...fromRewardPattern(pool.subsidy, "subsidy", colors.lime, colors.emerald), - ...fromRewardPattern(pool.fee, "fee", colors.cyan, colors.indigo), - ], - }, - { - name: "Days since block", - title: `Days since ${poolName} mined a block`, - bottom: [ - s({ metric: pool.daysSinceBlock, name: "Since block", unit: "days" }), - ], - }, - ], - }; - }); - - return { - name: "Chain", - tree: [ - // Block - { - name: "Block", - tree: [ - { - name: "Count", - title: "Block Count", - bottom: [ - ...fromBlockCount(blocks.count.blockCount, "Block", "count"), - s({ metric: blocks.count.blockCountTarget, name: "Target", color: colors.gray, unit: "count", options: { lineStyle: 4 } }), - s({ metric: blocks.count._1wBlockCount, name: "1w sum", color: colors.red, unit: "count", defaultActive: false }), - s({ metric: blocks.count._1mBlockCount, name: "1m sum", color: colors.pink, unit: "count", defaultActive: false }), - s({ metric: blocks.count._1yBlockCount, name: "1y sum", color: colors.purple, unit: "count", defaultActive: false }), - ], - }, - { - name: "Interval", - title: "Block Interval", - bottom: [ - s({ metric: blocks.interval.interval, name: "Interval", unit: "secs" }), - ...fromBlockInterval(blocks.interval.blockInterval, "Interval", "secs"), - createPriceLine({ unit: "secs", name: "Target", number: 600 }), - ], - }, - { - name: "Size", - title: "Block Size", - bottom: [ - s({ metric: blocks.size.vbytes, name: "vbytes raw", unit: "vb" }), - s({ metric: indexed.block.weight, name: "weight raw", unit: "wu" }), - ...fromBlockSize(blocks.size.blockSize, "size", "bytes"), - ...fromBlockSize(blocks.weight.blockWeight, "weight", "wu"), - ...fromBlockSize(blocks.size.blockVbytes, "vbytes", "vb"), - ], - }, - ], - }, - - // Transaction - { - name: "Transaction", - tree: [ - { - name: "Count", - title: "Transaction Count", - bottom: fromBitcoin(transactions.count.txCount, "Count", "count"), - }, - { - name: "Volume", - title: "Transaction Volume", - bottom: [ - s({ metric: transactions.volume.sentSum.sats, name: "Sent", unit: "sats" }), - s({ metric: transactions.volume.sentSum.bitcoin.base, name: "Sent", unit: "btc" }), - s({ metric: transactions.volume.sentSum.dollars, name: "Sent", unit: "usd" }), - s({ metric: transactions.volume.annualizedVolume, name: "annualized", color: colors.red, unit: "sats", defaultActive: false }), - s({ metric: transactions.volume.annualizedVolumeBtc, name: "annualized", color: colors.red, unit: "btc", defaultActive: false }), - s({ metric: transactions.volume.annualizedVolumeUsd, name: "annualized", color: colors.lime, unit: "usd", defaultActive: false }), - ], - }, - { - name: "Size", - title: "Transaction Size", - bottom: [ - ...fromBlockInterval(transactions.size.txWeight, "weight", "wu"), - ...fromBlockInterval(transactions.size.txVsize, "vsize", "vb"), - ], - }, - { - name: "Versions", - title: "Transaction Versions", - bottom: [ - ...fromBlockCount(transactions.versions.txV1, "v1", "count", colors.orange, colors.red), - ...fromBlockCount(transactions.versions.txV2, "v2", "count", colors.cyan, colors.blue), - ...fromBlockCount(transactions.versions.txV3, "v3", "count", colors.lime, colors.green), - ], - }, - { - name: "Velocity", - title: "Transactions Velocity", - bottom: [ - s({ metric: supply.velocity.btc, name: "bitcoin", unit: "ratio" }), - s({ metric: supply.velocity.usd, name: "dollars", color: colors.emerald, unit: "ratio" }), - ], - }, - { - name: "Speed", - title: "Transactions Per Second", - bottom: [ - s({ metric: transactions.volume.txPerSec, name: "Transactions", unit: "/sec" }), - ], - }, - ], - }, - - // Input - { - name: "Input", - tree: [ - { - name: "Count", - title: "Transaction Input Count", - bottom: [ - ...fromBlockSize(inputs.count.count, "Input", "count"), - ], - }, - { - name: "Speed", - title: "Inputs Per Second", - bottom: [ - s({ metric: transactions.volume.inputsPerSec, name: "Inputs", unit: "/sec" }), - ], - }, - ], - }, - - // Output - { - name: "Output", - tree: [ - { - name: "Count", - title: "Transaction Output Count", - bottom: [ - ...fromBlockSize(outputs.count.count, "Output", "count"), - ], - }, - { - name: "Speed", - title: "Outputs Per Second", - bottom: [ - s({ metric: transactions.volume.outputsPerSec, name: "Outputs", unit: "/sec" }), - ], - }, - ], - }, - - // UTXO - { - name: "UTXO", - tree: [ - { - name: "Count", - title: "UTXO Count", - bottom: [ - s({ metric: outputs.count.utxoCount.base, name: "Count", unit: "count" }), - ], - }, - ], - }, - - // Coinbase - { - name: "Coinbase", - title: "Coinbase Rewards", - bottom: fromCoinbase(blocks.rewards.coinbase, "Coinbase", colors.orange, colors.red), - }, - - // Subsidy - { - name: "Subsidy", - title: "Block Subsidy", - bottom: [ - ...fromCoinbase(blocks.rewards.subsidy, "Subsidy", colors.lime, colors.emerald), - s({ metric: blocks.rewards.subsidyDominance, name: "Dominance", color: colors.purple, unit: "percentage", defaultActive: false }), - ], - }, - - // Fee - { - name: "Fee", - tree: [ - { - name: "Total", - title: "Transaction Fees", - bottom: [ - s({ metric: transactions.fees.fee.sats.sum, name: "Sum", unit: "sats" }), - s({ metric: transactions.fees.fee.sats.cumulative, name: "Cumulative", color: colors.blue, unit: "sats", defaultActive: false }), - s({ metric: transactions.fees.fee.bitcoin.sum, name: "Sum", unit: "btc" }), - s({ metric: transactions.fees.fee.bitcoin.cumulative, name: "Cumulative", color: colors.blue, unit: "btc", defaultActive: false }), - s({ metric: transactions.fees.fee.dollars.sum, name: "Sum", unit: "usd" }), - s({ metric: transactions.fees.fee.dollars.cumulative, name: "Cumulative", color: colors.blue, unit: "usd", defaultActive: false }), - s({ metric: blocks.rewards.feeDominance, name: "Dominance", color: colors.purple, unit: "percentage", defaultActive: false }), - ], - }, - { - name: "Rate", - title: "Fee Rate", - bottom: [ - s({ metric: transactions.fees.feeRate.base, name: "Rate", unit: "sat/vb" }), - s({ metric: transactions.fees.feeRate.average, name: "Average", color: colors.blue, unit: "sat/vb" }), - s({ metric: transactions.fees.feeRate.median, name: "Median", color: colors.purple, unit: "sat/vb" }), - s({ metric: transactions.fees.feeRate.min, name: "Min", color: colors.red, unit: "sat/vb", defaultActive: false }), - s({ metric: transactions.fees.feeRate.max, name: "Max", color: colors.green, unit: "sat/vb", defaultActive: false }), - s({ metric: transactions.fees.feeRate.pct10, name: "pct10", color: colors.rose, unit: "sat/vb", defaultActive: false }), - s({ metric: transactions.fees.feeRate.pct25, name: "pct25", color: colors.pink, unit: "sat/vb", defaultActive: false }), - s({ metric: transactions.fees.feeRate.pct75, name: "pct75", color: colors.violet, unit: "sat/vb", defaultActive: false }), - s({ metric: transactions.fees.feeRate.pct90, name: "pct90", color: colors.fuchsia, unit: "sat/vb", defaultActive: false }), - ], - }, - ], - }, - - // Mining - { - name: "Mining", - tree: [ - { - name: "Hashrate", - title: "Network Hashrate", - bottom: [ - s({ metric: blocks.mining.hashRate, name: "Hashrate", unit: "h/s" }), - s({ metric: blocks.mining.hashRate1wSma, name: "1w SMA", color: colors.red, unit: "h/s", defaultActive: false }), - s({ metric: blocks.mining.hashRate1mSma, name: "1m SMA", color: colors.orange, unit: "h/s", defaultActive: false }), - s({ metric: blocks.mining.hashRate2mSma, name: "2m SMA", color: colors.yellow, unit: "h/s", defaultActive: false }), - s({ metric: blocks.mining.hashRate1ySma, name: "1y SMA", color: colors.lime, unit: "h/s", defaultActive: false }), - ], - }, - { - name: "Difficulty", - title: "Network Difficulty", - bottom: [ - s({ metric: blocks.mining.difficulty, name: "Difficulty", unit: "difficulty" }), - s({ metric: blocks.mining.difficultyAdjustment, name: "Adjustment", color: colors.orange, unit: "percentage", defaultActive: false }), - s({ metric: blocks.mining.difficultyAsHash, name: "As hash", color: colors.default, unit: "h/s", defaultActive: false, options: { lineStyle: 1 } }), - s({ metric: blocks.difficulty.blocksBeforeNextDifficultyAdjustment, name: "Blocks until adj.", color: colors.indigo, unit: "blocks", defaultActive: false }), - s({ metric: blocks.difficulty.daysBeforeNextDifficultyAdjustment, name: "Days until adj.", color: colors.purple, unit: "days", defaultActive: false }), - ], - }, - { - name: "Hash Price", - title: "Hash Price", - bottom: [ - s({ metric: blocks.mining.hashPriceThs, name: "TH/s", color: colors.emerald, unit: "usd/(th/s)/day" }), - s({ metric: blocks.mining.hashPricePhs, name: "PH/s", color: colors.emerald, unit: "usd/(ph/s)/day" }), - s({ metric: blocks.mining.hashPriceRebound, name: "Rebound", color: colors.yellow, unit: "percentage" }), - s({ metric: blocks.mining.hashPriceThsMin, name: "TH/s Min", color: colors.red, unit: "usd/(th/s)/day", options: { lineStyle: 1 } }), - s({ metric: blocks.mining.hashPricePhsMin, name: "PH/s Min", color: colors.red, unit: "usd/(ph/s)/day", options: { lineStyle: 1 } }), - ], - }, - { - name: "Hash Value", - title: "Hash Value", - bottom: [ - s({ metric: blocks.mining.hashValueThs, name: "TH/s", color: colors.orange, unit: "sats/(th/s)/day" }), - s({ metric: blocks.mining.hashValuePhs, name: "PH/s", color: colors.orange, unit: "sats/(ph/s)/day" }), - s({ metric: blocks.mining.hashValueRebound, name: "Rebound", color: colors.yellow, unit: "percentage" }), - s({ metric: blocks.mining.hashValueThsMin, name: "TH/s Min", color: colors.red, unit: "sats/(th/s)/day", options: { lineStyle: 1 } }), - s({ metric: blocks.mining.hashValuePhsMin, name: "PH/s Min", color: colors.red, unit: "sats/(ph/s)/day", options: { lineStyle: 1 } }), - ], - }, - { - name: "Halving", - title: "Halving Info", - bottom: [ - s({ metric: blocks.halving.blocksBeforeNextHalving, name: "Blocks until halving", unit: "blocks" }), - s({ metric: blocks.halving.daysBeforeNextHalving, name: "Days until halving", color: colors.orange, unit: "days" }), - s({ metric: blocks.halving.halvingepoch, name: "Halving epoch", color: colors.purple, unit: "epoch", defaultActive: false }), - ], - }, - { - name: "Puell Multiple", - title: "Puell Multiple", - bottom: [ - s({ metric: market.indicators.puellMultiple, name: "Puell Multiple", unit: "ratio" }), - createPriceLine({ unit: "ratio", number: 1 }), - ], - }, - ], - }, - - // Pools - { - name: "Pools", - tree: poolsTree, - }, - - // Unspendable - { - name: "Unspendable", - tree: [ - { - name: "OP_RETURN", - tree: [ - { - name: "Outputs", - title: "OP_RETURN Outputs", - bottom: fromBitcoin(scripts.count.opreturnCount, "Count", "count"), - }, - ], - }, - ], - }, - - // Inflation - { - name: "Inflation", - title: "Inflation Rate", - bottom: [ - s({ metric: supply.inflation.indexes, name: "Rate", unit: "percentage" }), - ], - }, - ], - }; -} diff --git a/websites/bitview/scripts/options/partial/cointime.js b/websites/bitview/scripts/options/partial/cointime.js deleted file mode 100644 index ffaa46a77..000000000 --- a/websites/bitview/scripts/options/partial/cointime.js +++ /dev/null @@ -1,306 +0,0 @@ -/** Cointime section builder - typed tree-based patterns */ - -/** - * Create price with ratio options for cointime prices - * @param {PartialContext} ctx - * @param {Object} args - * @param {string} args.name - * @param {string} args.title - * @param {string} args.legend - * @param {AnyMetricPattern} args.price - * @param {ActivePriceRatioPattern} args.ratio - * @param {Color} [args.color] - * @returns {PartialOptionsTree} - */ -function createCointimePriceWithRatioOptions(ctx, { name, title, legend, price, ratio, color }) { - const { s, colors, createPriceLine } = ctx; - - // Percentile USD mappings - const percentileUsdMap = [ - { name: "pct99", prop: ratio.ratioPct99Usd, color: colors.rose }, - { name: "pct98", prop: ratio.ratioPct98Usd, color: colors.pink }, - { name: "pct95", prop: ratio.ratioPct95Usd, color: colors.fuchsia }, - { name: "pct5", prop: ratio.ratioPct5Usd, color: colors.cyan }, - { name: "pct2", prop: ratio.ratioPct2Usd, color: colors.sky }, - { name: "pct1", prop: ratio.ratioPct1Usd, color: colors.blue }, - ]; - - // Percentile ratio mappings - const percentileMap = [ - { name: "pct99", prop: ratio.ratioPct99, color: colors.rose }, - { name: "pct98", prop: ratio.ratioPct98, color: colors.pink }, - { name: "pct95", prop: ratio.ratioPct95, color: colors.fuchsia }, - { name: "pct5", prop: ratio.ratioPct5, color: colors.cyan }, - { name: "pct2", prop: ratio.ratioPct2, color: colors.sky }, - { name: "pct1", prop: ratio.ratioPct1, color: colors.blue }, - ]; - - // SD patterns by window - const sdPatterns = [ - { nameAddon: "all", titleAddon: "", sd: ratio.ratioSd }, - { nameAddon: "4y", titleAddon: "4y", sd: ratio.ratio4ySd }, - { nameAddon: "2y", titleAddon: "2y", sd: ratio.ratio2ySd }, - { nameAddon: "1y", titleAddon: "1y", sd: ratio.ratio1ySd }, - ]; - - /** @param {Ratio1ySdPattern} sd */ - const getSdBands = (sd) => [ - { name: "0σ", prop: sd._0sdUsd, color: colors.lime }, - { name: "+0.5σ", prop: sd.p05sdUsd, color: colors.yellow }, - { name: "+1σ", prop: sd.p1sdUsd, color: colors.amber }, - { name: "+1.5σ", prop: sd.p15sdUsd, color: colors.orange }, - { name: "+2σ", prop: sd.p2sdUsd, color: colors.red }, - { name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose }, - { name: "+3σ", prop: sd.p3sd, color: colors.pink }, - { name: "−0.5σ", prop: sd.m05sdUsd, color: colors.teal }, - { name: "−1σ", prop: sd.m1sdUsd, color: colors.cyan }, - { name: "−1.5σ", prop: sd.m15sdUsd, color: colors.sky }, - { name: "−2σ", prop: sd.m2sdUsd, color: colors.blue }, - { name: "−2.5σ", prop: sd.m25sdUsd, color: colors.indigo }, - { name: "−3σ", prop: sd.m3sd, color: colors.violet }, - ]; - - return [ - { - name: "price", - title, - top: [s({ metric: price, name: legend, color, unit: "usd" })], - }, - { - name: "Ratio", - title: `${title} Ratio`, - top: [ - s({ metric: price, name: legend, color, unit: "usd" }), - ...percentileUsdMap.map(({ name: pctName, prop, color: pctColor }) => - s({ - metric: prop, - name: pctName, - color: pctColor, - defaultActive: false, - unit: "usd", - options: { lineStyle: 1 }, - }), - ), - ], - bottom: [ - s({ metric: ratio.ratio, name: "ratio", color, unit: "ratio" }), - s({ metric: ratio.ratio1wSma, name: "1w sma", color: colors.lime, unit: "ratio" }), - s({ metric: ratio.ratio1mSma, name: "1m sma", color: colors.teal, unit: "ratio" }), - s({ metric: ratio.ratio1ySd.sma, name: "1y sma", color: colors.sky, unit: "ratio" }), - s({ metric: ratio.ratio2ySd.sma, name: "2y sma", color: colors.indigo, unit: "ratio" }), - s({ metric: ratio.ratio4ySd.sma, name: "4y sma", color: colors.purple, unit: "ratio" }), - s({ metric: ratio.ratioSd.sma, name: "all sma", color: colors.rose, unit: "ratio" }), - ...percentileMap.map(({ name: pctName, prop, color: pctColor }) => - s({ - metric: prop, - name: pctName, - color: pctColor, - defaultActive: false, - unit: "ratio", - options: { lineStyle: 1 }, - }), - ), - createPriceLine({ unit: "ratio", number: 1 }), - ], - }, - { - name: "ZScores", - tree: sdPatterns.map(({ nameAddon, titleAddon, sd }) => ({ - name: nameAddon, - title: `${title} ${titleAddon} Z-Score`, - top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) => - s({ metric: prop, name: bandName, color: bandColor, unit: "usd" }), - ), - bottom: [ - s({ metric: sd.zscore, name: "zscore", color, unit: "sd" }), - createPriceLine({ unit: "sd", number: 3 }), - createPriceLine({ unit: "sd", number: 2 }), - createPriceLine({ unit: "sd", number: 1 }), - createPriceLine({ unit: "sd", number: 0 }), - createPriceLine({ unit: "sd", number: -1 }), - createPriceLine({ unit: "sd", number: -2 }), - createPriceLine({ unit: "sd", number: -3 }), - ], - })), - }, - ]; -} - -/** - * Create Cointime section - * @param {PartialContext} ctx - * @returns {PartialOptionsGroup} - */ -export function createCointimeSection(ctx) { - const { colors, brk, s } = ctx; - const { cointime, distribution, supply } = brk.tree.computed; - const { pricing, cap, activity, supply: cointimeSupply, adjusted } = cointime; - const utxoCohorts = distribution.utxoCohorts; - - // Cointime prices data - const cointimePrices = [ - { - price: pricing.trueMarketMean, - ratio: pricing.trueMarketMeanRatio, - name: "True market mean", - title: "true market mean", - color: colors.blue, - }, - { - price: pricing.vaultedPrice, - ratio: pricing.vaultedPriceRatio, - name: "Vaulted", - title: "vaulted price", - color: colors.lime, - }, - { - price: pricing.activePrice, - ratio: pricing.activePriceRatio, - name: "Active", - title: "active price", - color: colors.rose, - }, - { - price: pricing.cointimePrice, - ratio: pricing.cointimePriceRatio, - name: "cointime", - title: "cointime price", - color: colors.yellow, - }, - ]; - - // Cointime capitalizations data - const cointimeCapitalizations = [ - { metric: cap.vaultedCap, name: "vaulted", title: "vaulted Capitalization", color: colors.lime }, - { metric: cap.activeCap, name: "active", title: "active Capitalization", color: colors.rose }, - { metric: cap.cointimeCap, name: "cointime", title: "cointime Capitalization", color: colors.yellow }, - { metric: cap.investorCap, name: "investor", title: "investor Capitalization", color: colors.fuchsia }, - { metric: cap.thermoCap, name: "thermo", title: "thermo Capitalization", color: colors.emerald }, - ]; - - return { - name: "Cointime", - tree: [ - // Prices - { - name: "Prices", - tree: [ - { - name: "Compare", - title: "Compare Cointime Prices", - top: cointimePrices.map(({ price, name, color }) => - s({ metric: price, name, color, unit: "usd" }), - ), - }, - ...cointimePrices.map(({ price, ratio, name, color, title }) => ({ - name, - tree: createCointimePriceWithRatioOptions(ctx, { - price, - ratio, - legend: name, - color, - name, - title, - }), - })), - ], - }, - - // Capitalization - { - name: "Capitalization", - tree: [ - { - name: "Compare", - title: "Compare Cointime Capitalizations", - bottom: [ - s({ metric: supply.marketCap.height, name: "Market", color: colors.default, unit: "usd" }), - s({ metric: utxoCohorts.all.realized.realizedCap, name: "Realized", color: colors.orange, unit: "usd" }), - ...cointimeCapitalizations.map(({ metric, name, color }) => - s({ metric, name, color, unit: "usd" }), - ), - ], - }, - ...cointimeCapitalizations.map(({ metric, name, color, title }) => ({ - name, - title, - bottom: [ - s({ metric, name, color, unit: "usd" }), - s({ metric: supply.marketCap.height, name: "Market", color: colors.default, unit: "usd" }), - s({ metric: utxoCohorts.all.realized.realizedCap, name: "Realized", color: colors.orange, unit: "usd" }), - ], - })), - ], - }, - - // Supply - { - name: "Supply", - title: "Cointime Supply", - bottom: /** @type {const} */ ([ - [utxoCohorts.all.supply.supply, "all", colors.orange], - [cointimeSupply.vaultedSupply, "vaulted", colors.lime], - [cointimeSupply.activeSupply, "active", colors.rose], - ]).flatMap(([supplyItem, name, color]) => [ - s({ metric: supplyItem.sats, name, color, unit: "sats" }), - s({ metric: supplyItem.bitcoin, name, color, unit: "btc" }), - s({ metric: supplyItem.dollars, name, color, unit: "usd" }), - ]), - }, - - // Liveliness & Vaultedness - { - name: "Liveliness & Vaultedness", - title: "Liveliness & Vaultedness", - bottom: [ - s({ metric: activity.liveliness, name: "Liveliness", color: colors.rose, unit: "ratio" }), - s({ metric: activity.vaultedness, name: "Vaultedness", color: colors.lime, unit: "ratio" }), - s({ metric: activity.activityToVaultednessRatio, name: "Liveliness / Vaultedness", color: colors.purple, unit: "ratio" }), - ], - }, - - // Coinblocks - { - name: "Coinblocks", - title: "Coinblocks", - bottom: [ - // Destroyed comes from the all cohort's activity - s({ metric: utxoCohorts.all.activity.coinblocksDestroyed.base, name: "Destroyed", color: colors.red, unit: "coinblocks" }), - s({ metric: utxoCohorts.all.activity.coinblocksDestroyed.cumulative, name: "Cumulative Destroyed", color: colors.red, defaultActive: false, unit: "coinblocks" }), - // Created and stored from cointime - s({ metric: activity.coinblocksCreated.base, name: "created", color: colors.orange, unit: "coinblocks" }), - s({ metric: activity.coinblocksCreated.cumulative, name: "Cumulative created", color: colors.orange, defaultActive: false, unit: "coinblocks" }), - s({ metric: activity.coinblocksStored.base, name: "stored", color: colors.green, unit: "coinblocks" }), - s({ metric: activity.coinblocksStored.cumulative, name: "Cumulative stored", color: colors.green, defaultActive: false, unit: "coinblocks" }), - ], - }, - - // Adjusted metrics - { - name: "Adjusted", - tree: [ - // Inflation - { - name: "inflation", - title: "Cointime-Adjusted inflation rate", - bottom: [ - s({ metric: supply.inflation.indexes, name: "base", color: colors.orange, unit: "percentage" }), - s({ metric: adjusted.cointimeAdjInflationRate, name: "adjusted", color: colors.purple, unit: "percentage" }), - ], - }, - // Velocity - { - name: "Velocity", - title: "Cointime-Adjusted transactions velocity", - bottom: [ - s({ metric: supply.velocity.btc, name: "btc", color: colors.orange, unit: "ratio" }), - s({ metric: adjusted.cointimeAdjTxBtcVelocity, name: "adj. btc", color: colors.red, unit: "ratio" }), - s({ metric: supply.velocity.usd, name: "usd", color: colors.emerald, unit: "ratio" }), - s({ metric: adjusted.cointimeAdjTxUsdVelocity, name: "adj. usd", color: colors.lime, unit: "ratio" }), - ], - }, - ], - }, - ], - }; -} diff --git a/websites/bitview/scripts/options/partial/market/index.js b/websites/bitview/scripts/options/partial/market/index.js deleted file mode 100644 index 403ecc84b..000000000 --- a/websites/bitview/scripts/options/partial/market/index.js +++ /dev/null @@ -1,62 +0,0 @@ -/** Market section - Main entry point */ - -import { buildAverages, createAveragesSection } from "./averages.js"; -import { createPerformanceSection } from "./performance.js"; -import { createIndicatorsSection } from "./indicators/index.js"; -import { createInvestingSection } from "./investing.js"; - -/** - * Create Market section - * @param {PartialContext} ctx - * @returns {PartialOptionsGroup} - */ -export function createMarketSection(ctx) { - const { colors, brk, s } = ctx; - const { market, supply } = brk.tree.computed; - const { movingAverage, ath, returns, volatility, range, dca, lookback, indicators } = market; - - const averages = buildAverages(colors, movingAverage); - - return { - name: "Market", - tree: [ - // Price - { - name: "Price", - title: "Bitcoin Price", - }, - - // Capitalization - { - name: "Capitalization", - title: "Market Capitalization", - bottom: [s({ metric: supply.marketCap.indexes, name: "Capitalization", unit: "usd" })], - }, - - // All Time High - { - name: "All Time High", - title: "All Time High", - top: [s({ metric: ath.priceAth, name: "ath", unit: "usd" })], - bottom: [ - s({ metric: ath.priceDrawdown, name: "Drawdown", color: colors.red, unit: "percentage" }), - s({ metric: ath.daysSincePriceAth, name: "since", unit: "days" }), - s({ metric: ath.maxDaysBetweenPriceAths, name: "Max", color: colors.red, unit: "days" }), - s({ metric: ath.maxYearsBetweenPriceAths, name: "Max", color: colors.red, unit: "years" }), - ], - }, - - // Averages - createAveragesSection(ctx, averages), - - // Performance - createPerformanceSection(ctx, returns), - - // Indicators - createIndicatorsSection(ctx, { volatility, range, movingAverage, indicators }), - - // Investing - createInvestingSection(ctx, { dca, lookback, returns }), - ], - }; -} diff --git a/websites/bitview/scripts/options/partial/market/indicators/bands.js b/websites/bitview/scripts/options/partial/market/indicators/bands.js deleted file mode 100644 index cde5d3331..000000000 --- a/websites/bitview/scripts/options/partial/market/indicators/bands.js +++ /dev/null @@ -1,43 +0,0 @@ -/** Bands indicators (MinMax, Mayer Multiple) */ - -/** - * Create Bands section - * @param {PartialContext} ctx - * @param {Object} args - * @param {Market["range"]} args.range - * @param {Market["movingAverage"]} args.movingAverage - */ -export function createBandsSection(ctx, { range, movingAverage }) { - const { s, colors } = ctx; - - return { - name: "Bands", - tree: [ - { - name: "MinMax", - tree: [ - { id: "1w", title: "1 Week", min: range.price1wMin, max: range.price1wMax }, - { id: "2w", title: "2 Week", min: range.price2wMin, max: range.price2wMax }, - { id: "1m", title: "1 Month", min: range.price1mMin, max: range.price1mMax }, - { id: "1y", title: "1 Year", min: range.price1yMin, max: range.price1yMax }, - ].map(({ id, title, min, max }) => ({ - name: id, - title: `Bitcoin Price ${title} MinMax Bands`, - top: [ - s({ metric: min, name: "min", color: colors.red, unit: "usd" }), - s({ metric: max, name: "max", color: colors.green, unit: "usd" }), - ], - })), - }, - { - name: "Mayer Multiple", - title: "Mayer Multiple", - top: [ - s({ metric: movingAverage.price200dSma.price, name: "200d sma", color: colors.yellow, unit: "usd" }), - s({ metric: movingAverage.price200dSmaX24, name: "200d sma x2.4", color: colors.green, unit: "usd" }), - s({ metric: movingAverage.price200dSmaX08, name: "200d sma x0.8", color: colors.red, unit: "usd" }), - ], - }, - ], - }; -} diff --git a/websites/bitview/scripts/options/partial/series.js b/websites/bitview/scripts/options/series.js similarity index 83% rename from websites/bitview/scripts/options/partial/series.js rename to websites/bitview/scripts/options/series.js index 8ea73f51d..c3418d903 100644 --- a/websites/bitview/scripts/options/partial/series.js +++ b/websites/bitview/scripts/options/series.js @@ -49,9 +49,9 @@ export function fromBlockCount(colors, pattern, title, color) { } /** - * Create series from a BitcoinPattern ({ base, sum, cumulative, average, min, max, median, pct* }) + * Create series from a DollarsPattern ({ base, sum, cumulative, average, min, max, percentiles.* }) * @param {Colors} colors - * @param {BitcoinPattern} pattern + * @param {DollarsPattern} pattern * @param {string} title * @param {Color} [color] * @returns {AnyFetchedSeriesBlueprint[]} @@ -85,31 +85,31 @@ export function fromBitcoin(colors, pattern, title, color) { defaultActive: false, }, { - metric: pattern.median, + metric: pattern.percentiles.median, title: "Median", color: colors.amber, defaultActive: false, }, { - metric: pattern.pct75, + metric: pattern.percentiles.pct75, title: "pct75", color: colors.red, defaultActive: false, }, { - metric: pattern.pct25, + metric: pattern.percentiles.pct25, title: "pct25", color: colors.yellow, defaultActive: false, }, { - metric: pattern.pct90, + metric: pattern.percentiles.pct90, title: "pct90", color: colors.rose, defaultActive: false, }, { - metric: pattern.pct10, + metric: pattern.percentiles.pct10, title: "pct10", color: colors.lime, defaultActive: false, @@ -118,7 +118,7 @@ export function fromBitcoin(colors, pattern, title, color) { } /** - * Create series from a BlockSizePattern ({ sum, cumulative, average, min, max, median, pct* }) + * Create series from a BlockSizePattern ({ sum, cumulative, avg, min, max, distribution.percentiles.* }) * @param {Colors} colors * @param {BlockSizePattern} pattern * @param {string} title @@ -148,31 +148,31 @@ export function fromBlockSize(colors, pattern, title, color) { defaultActive: false, }, { - metric: pattern.median, + metric: pattern.distribution.percentiles.median, title: "Median", color: colors.amber, defaultActive: false, }, { - metric: pattern.pct75, + metric: pattern.distribution.percentiles.pct75, title: "pct75", color: colors.red, defaultActive: false, }, { - metric: pattern.pct25, + metric: pattern.distribution.percentiles.pct25, title: "pct25", color: colors.yellow, defaultActive: false, }, { - metric: pattern.pct90, + metric: pattern.distribution.percentiles.pct90, title: "pct90", color: colors.rose, defaultActive: false, }, { - metric: pattern.pct10, + metric: pattern.distribution.percentiles.pct10, title: "pct10", color: colors.lime, defaultActive: false, diff --git a/websites/bitview/scripts/options/partial/types.js b/websites/bitview/scripts/options/types.js similarity index 94% rename from websites/bitview/scripts/options/partial/types.js rename to websites/bitview/scripts/options/types.js index 9a3dd1e68..c989ff289 100644 --- a/websites/bitview/scripts/options/partial/types.js +++ b/websites/bitview/scripts/options/types.js @@ -68,8 +68,8 @@ * @typedef {PartialOption & PartialChartOptionSpecific} PartialChartOption * * @typedef {Object} ProcessedChartOptionAddons - * @property {Record} top - * @property {Record} bottom + * @property {Map} top + * @property {Map} bottom * * @typedef {Required> & ProcessedChartOptionAddons & ProcessedOptionAddons} ChartOption * @@ -168,9 +168,9 @@ * @typedef {Object} PartialContext * @property {Colors} colors * @property {BrkClient} brk - * @property {(args: { metric: AnyMetricPattern, name: string, color?: Color, defaultActive?: boolean, unit?: Unit, options?: LineSeriesPartialOptions }) => AnyFetchedSeriesBlueprint} s + * @property {(args: { metric: AnyMetricPattern, name: string, unit: Unit, color?: Color, defaultActive?: boolean, options?: LineSeriesPartialOptions }) => AnyFetchedSeriesBlueprint} s * @property {(pattern: BlockCountPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCount - * @property {(pattern: BitcoinPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoin + * @property {(pattern: DollarsPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoin * @property {(pattern: BlockSizePattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockSize * @property {(args: { number?: number, name?: string, defaultActive?: boolean, lineStyle?: LineStyle, color?: Color, unit: Unit }) => FetchedLineSeriesBlueprint} createPriceLine * @property {(args: { numbers: number[], unit: Unit }) => FetchedLineSeriesBlueprint[]} createPriceLines diff --git a/websites/bitview/scripts/panes/chart/index.js b/websites/bitview/scripts/panes/chart/index.js index 20ea01f5a..074cffa56 100644 --- a/websites/bitview/scripts/panes/chart/index.js +++ b/websites/bitview/scripts/panes/chart/index.js @@ -2,11 +2,12 @@ import { createShadow, createHorizontalChoiceField, createHeader, -} from "../../utils/dom"; -import { chartElement } from "../../utils/elements"; -import { ios, canShare } from "../../utils/env"; -import { serdeChartableIndex, serdeOptNumber } from "../../utils/serde"; -import { throttle } from "../../utils/timing"; +} from "../../utils/dom.js"; +import { chartElement } from "../../utils/elements.js"; +import { ios, canShare } from "../../utils/env.js"; +import { serdeChartableIndex, serdeOptNumber } from "../../utils/serde.js"; +import { throttle } from "../../utils/timing.js"; +import { Unit } from "../../utils/units.js"; const keyPrefix = "chart"; const ONE_BTC_IN_SATS = 100_000_000; @@ -45,7 +46,6 @@ export function init({ const { index, fieldset } = createIndexSelector({ option, - brk, signals, }); @@ -169,13 +169,12 @@ export function init({ const { field: topUnitField, selected: topUnit } = createHorizontalChoiceField({ - defaultValue: "usd", + defaultValue: Unit.usd, keyPrefix, key: "unit-0", - choices: /** @type {const} */ ([ - /** @satisfies {Unit} */ ("usd"), - /** @satisfies {Unit} */ ("sats"), - ]), + choices: [Unit.usd, Unit.sats], + toKey: (u) => u.id, + toLabel: (u) => u.name, signals, sorted: true, }); @@ -205,7 +204,7 @@ export function init({ const latest = { ..._latest }; - if (unit === "sats") { + if (unit === Unit.sats) { latest.open = Math.floor(ONE_BTC_IN_SATS / latest.open); latest.high = Math.floor(ONE_BTC_IN_SATS / latest.high); latest.low = Math.floor(ONE_BTC_IN_SATS / latest.low); @@ -277,26 +276,30 @@ export function init({ signals.createEffect(option, (option) => { headingElement.innerHTML = option.title; - const bottomUnits = /** @type {readonly Unit[]} */ ( - Object.keys(option.bottom) - ); - const { field: bottomUnitField, selected: bottomUnit } = - createHorizontalChoiceField({ - defaultValue: bottomUnits.at(0) || "", + const bottomUnits = Array.from(option.bottom.keys()); + + /** @type {{ field: HTMLDivElement, selected: Accessor } | undefined} */ + let bottomUnitSelector; + + if (bottomUnits.length) { + bottomUnitSelector = createHorizontalChoiceField({ + defaultValue: bottomUnits[0], keyPrefix, key: "unit-1", choices: bottomUnits, + toKey: (u) => u.id, + toLabel: (u) => u.name, signals, sorted: true, }); - if (bottomUnits.length) { + const field = bottomUnitSelector.field; chart.addFieldsetIfNeeded({ id: "charts-unit-1", paneIndex: 1, position: "nw", createChild() { - return bottomUnitField; + return field; }, }); } @@ -323,7 +326,7 @@ export function init({ console.log({ topUnit, topSeriesType }); switch (topUnit) { - case "usd": { + case Unit.usd: { switch (topSeriesType) { case null: case CANDLE: { @@ -353,7 +356,7 @@ export function init({ } break; } - case "sats": { + case Unit.sats: { switch (topSeriesType) { case null: case CANDLE: { @@ -404,100 +407,117 @@ export function init({ }, ); - [ - { - blueprints: option.top, - paneIndex: 0, - unit: topUnit, - seriesList: seriesListTop, - orderStart: 1, - legend: chart.legendTop, - }, - { + /** + * @param {Object} args + * @param {Map} args.blueprints + * @param {number} args.paneIndex + * @param {Accessor} args.unit + * @param {Series[]} args.seriesList + * @param {number} args.orderStart + * @param {Legend} args.legend + */ + function processPane({ + blueprints, + paneIndex, + unit, + seriesList, + orderStart, + legend, + }) { + signals.createEffect(unit, (unit) => { + legend.removeFrom(orderStart); + + seriesList.splice(orderStart).forEach((series) => { + series.remove(); + }); + + blueprints.get(unit)?.forEach((blueprint, order) => { + order += orderStart; + + const options = blueprint.options; + + // Tree-first: metric is now an accessor with .by property + const indexes = Object.keys(blueprint.metric.by); + + if (indexes.includes(index)) { + switch (blueprint.type) { + case "Baseline": { + seriesList.push( + chart.addBaselineSeries({ + metric: blueprint.metric, + name: blueprint.title, + unit, + defaultActive: blueprint.defaultActive, + paneIndex, + options: { + ...options, + topLineColor: + blueprint.color?.() ?? blueprint.colors?.[0](), + bottomLineColor: + blueprint.color?.() ?? blueprint.colors?.[1](), + }, + order, + }), + ); + break; + } + case "Histogram": { + seriesList.push( + chart.addHistogramSeries({ + metric: blueprint.metric, + name: blueprint.title, + unit, + color: blueprint.color, + defaultActive: blueprint.defaultActive, + paneIndex, + options, + order, + }), + ); + break; + } + case "Candlestick": { + throw Error("TODO"); + } + case "Line": + case undefined: + seriesList.push( + chart.addLineSeries({ + metric: blueprint.metric, + color: blueprint.color, + name: blueprint.title, + unit, + defaultActive: blueprint.defaultActive, + paneIndex, + options, + order, + }), + ); + } + } + }); + }); + } + + processPane({ + blueprints: option.top, + paneIndex: 0, + unit: topUnit, + seriesList: seriesListTop, + orderStart: 1, + legend: chart.legendTop, + }); + + if (bottomUnitSelector) { + processPane({ blueprints: option.bottom, paneIndex: 1, - unit: bottomUnit, + unit: bottomUnitSelector.selected, seriesList: seriesListBottom, orderStart: 0, legend: chart.legendBottom, - }, - ].forEach( - ({ blueprints, paneIndex, unit, seriesList, orderStart, legend }) => { - signals.createEffect(unit, (unit) => { - legend.removeFrom(orderStart); - - seriesList.splice(orderStart).forEach((series) => { - series.remove(); - }); - - blueprints[unit]?.forEach((blueprint, order) => { - order += orderStart; - - const options = blueprint.options; - - // Tree-first: metric is now an accessor with .by property - const indexes = Object.keys(blueprint.metric.by); - - if (indexes.includes(index)) { - switch (blueprint.type) { - case "Baseline": { - seriesList.push( - chart.addBaselineSeries({ - metric: blueprint.metric, - name: blueprint.title, - unit, - defaultActive: blueprint.defaultActive, - paneIndex, - options: { - ...options, - topLineColor: - blueprint.color?.() ?? blueprint.colors?.[0](), - bottomLineColor: - blueprint.color?.() ?? blueprint.colors?.[1](), - }, - order, - }), - ); - break; - } - case "Histogram": { - seriesList.push( - chart.addHistogramSeries({ - metric: blueprint.metric, - name: blueprint.title, - unit, - color: blueprint.color, - defaultActive: blueprint.defaultActive, - paneIndex, - options, - order, - }), - ); - break; - } - case "Candlestick": { - throw Error("TODO"); - } - case "Line": - case undefined: - seriesList.push( - chart.addLineSeries({ - metric: blueprint.metric, - color: blueprint.color, - name: blueprint.title, - unit, - defaultActive: blueprint.defaultActive, - paneIndex, - options, - order, - }), - ); - } - } - }); - }); - }, - ); + }); + } firstRun = false; }); @@ -507,10 +527,9 @@ export function init({ /** * @param {Object} args * @param {Accessor} args.option - * @param {BrkClient} args.brk * @param {Signals} args.signals */ -function createIndexSelector({ option, brk, signals }) { +function createIndexSelector({ option, signals }) { const choices_ = /** @satisfies {ChartableIndexName[]} */ ([ "timestamp", "date", @@ -526,11 +545,11 @@ function createIndexSelector({ option, brk, signals }) { const choices = signals.createMemo(() => { const o = option(); - if (!Object.keys(o.top).length && !Object.keys(o.bottom).length) { + if (!o.top.size && !o.bottom.size) { return [...choices_]; } const rawIndexes = new Set( - [Object.values(o.top), Object.values(o.bottom)] + [Array.from(o.top.values()), Array.from(o.bottom.values())] .flat(2) .filter((blueprint) => { const path = Object.values(blueprint.metric.by)[0]?.path ?? ""; @@ -549,8 +568,10 @@ function createIndexSelector({ option, brk, signals }) { ); }); + /** @type {ChartableIndexName} */ + const defaultIndex = "date"; const { field, selected } = createHorizontalChoiceField({ - defaultValue: "date", + defaultValue: defaultIndex, keyPrefix, key: "index", choices, diff --git a/websites/bitview/scripts/panes/chart/screenshot.js b/websites/bitview/scripts/panes/chart/screenshot.js index 4de0bbd81..ae92989eb 100644 --- a/websites/bitview/scripts/panes/chart/screenshot.js +++ b/websites/bitview/scripts/panes/chart/screenshot.js @@ -1,4 +1,4 @@ -import { ios } from "../../utils/env"; +import { ios } from "../../utils/env.js"; import { domToBlob } from "../../modules/modern-screenshot/4.6.6/dist/index.mjs"; /** diff --git a/websites/bitview/scripts/panes/explorer.js b/websites/bitview/scripts/panes/explorer.js index 3ca0dfcf4..f21a5b2e9 100644 --- a/websites/bitview/scripts/panes/explorer.js +++ b/websites/bitview/scripts/panes/explorer.js @@ -1,5 +1,5 @@ -import { randomFromArray } from "../utils/array"; -import { explorerElement } from "../utils/elements"; +import { randomFromArray } from "../utils/array.js"; +import { explorerElement } from "../utils/elements.js"; /** * @param {Object} args @@ -12,13 +12,13 @@ import { explorerElement } from "../utils/elements"; * @param {BrkClient} args.brk */ export function init({ - colors, - createChartElement, - option, - signals, - webSockets, - resources, - brk, + colors: _colors, + createChartElement: _createChartElement, + option: _option, + signals: _signals, + webSockets: _webSockets, + resources: _resources, + brk: _brk, }) { const chain = window.document.createElement("div"); chain.id = "chain"; @@ -39,7 +39,7 @@ export function init({ ]; for (let i = 0; i <= 10; i++) { - const { name, color } = randomFromArray(miners); + const { name, color: _color } = randomFromArray(miners); const { cubeElement, leftFaceElement, rightFaceElement, topFaceElement } = createCube(); diff --git a/websites/bitview/scripts/panes/simulation.js b/websites/bitview/scripts/panes/simulation.js index f9934f6a4..d00c15b6e 100644 --- a/websites/bitview/scripts/panes/simulation.js +++ b/websites/bitview/scripts/panes/simulation.js @@ -4,20 +4,20 @@ import { createDateRange, dateToDateIndex, differenceBetweenDates, -} from "../utils/date"; +} from "../utils/date.js"; import { createButtonElement, createFieldElement, createHeader, createSelect, -} from "../utils/dom"; -import { simulationElement } from "../utils/elements"; +} from "../utils/dom.js"; +import { simulationElement } from "../utils/elements.js"; import { numberToDollars, numberToPercentage, numberToUSNumber, -} from "../utils/format"; -import { serdeDate, serdeOptDate, serdeOptNumber } from "../utils/serde"; +} from "../utils/format.js"; +import { serdeDate, serdeOptDate, serdeOptNumber } from "../utils/serde.js"; /** * @param {Object} args diff --git a/websites/bitview/scripts/panes/table.js b/websites/bitview/scripts/panes/table.js index 3de2e03c1..a5d3a7828 100644 --- a/websites/bitview/scripts/panes/table.js +++ b/websites/bitview/scripts/panes/table.js @@ -1,10 +1,10 @@ // @ts-nocheck -import { randomFromArray } from "../utils/array"; -import { createButtonElement, createHeader, createSelect } from "../utils/dom"; -import { tableElement } from "../utils/elements"; -import { serdeMetrics, serdeString, serdeUnit } from "../utils/serde"; -import { resetParams } from "../utils/url"; +import { randomFromArray } from "../utils/array.js"; +import { createButtonElement, createHeader, createSelect } from "../utils/dom.js"; +import { tableElement } from "../utils/elements.js"; +import { serdeMetrics, serdeString } from "../utils/serde.js"; +import { resetParams } from "../utils/url.js"; /** * @param {Object} args diff --git a/websites/bitview/scripts/resources.js b/websites/bitview/scripts/resources.js index d35d98f1d..eae8099fb 100644 --- a/websites/bitview/scripts/resources.js +++ b/websites/bitview/scripts/resources.js @@ -10,17 +10,19 @@ /** * @template T * @typedef {Object} RangeState - * @property {Signal} response + * @property {Signal | null>} response * @property {Signal} loading */ +/** @typedef {RangeState} AnyRangeState */ /** * @template T * @typedef {Object} MetricResource * @property {string} path * @property {(from?: number, to?: number) => RangeState} range - * @property {(from?: number, to?: number) => Promise} fetch + * @property {(from?: number, to?: number) => Promise | null>} fetch */ +/** @typedef {MetricResource} AnyMetricResource */ /** * @typedef {ReturnType} Resources @@ -57,7 +59,7 @@ export function createResources(signals) { error.set(null); try { const result = await fetcher(...args); - data.set(result); + data.set(() => result); return result; } catch (e) { error.set(e instanceof Error ? e : new Error(String(e))); @@ -71,12 +73,12 @@ export function createResources(signals) { } /** - * Create a reactive resource wrapper for a MetricNode with multi-range support + * Create a reactive resource wrapper for a MetricEndpoint with multi-range support * @template T - * @param {MetricNode} node + * @param {MetricEndpoint} endpoint * @returns {MetricResource} */ - function useMetricNode(node) { + function useMetricEndpoint(endpoint) { return signals.runWithOwner(owner, () => { /** @type {Map>} */ const ranges = new Map(); @@ -85,20 +87,24 @@ export function createResources(signals) { * Get or create range state * @param {number} [from=-10000] * @param {number} [to] + * @returns {RangeState} */ function range(from = -10000, to) { const key = `${from}-${to ?? ""}`; - if (!ranges.has(key)) { - ranges.set(key, { - response: signals.createSignal(/** @type {T | null} */ (null)), - loading: signals.createSignal(false), - }); - } - return /** @type {RangeState} */ (ranges.get(key)); + const existing = ranges.get(key); + if (existing) return existing; + + /** @type {RangeState} */ + const state = { + response: signals.createSignal(/** @type {MetricData | null} */ (null)), + loading: signals.createSignal(false), + }; + ranges.set(key, state); + return state; } return { - path: node.path, + path: endpoint.path, range, /** * Fetch data for a range @@ -109,7 +115,7 @@ export function createResources(signals) { const r = range(from, to); r.loading.set(true); try { - const result = await node.range(from, to, r.response.set); + const result = await endpoint.range(from, to, r.response.set); return result; } finally { r.loading.set(false); @@ -119,5 +125,5 @@ export function createResources(signals) { }); } - return { createResource, useMetricNode }; + return { createResource, useMetricEndpoint }; } diff --git a/websites/bitview/scripts/signals.js b/websites/bitview/scripts/signals.js index 3f1e6ffb0..15a6b1f8f 100644 --- a/websites/bitview/scripts/signals.js +++ b/websites/bitview/scripts/signals.js @@ -1,7 +1,7 @@ /** - * @import { SignalOptions } from "./modules/solidjs-signals/0.6.3/dist/types/core/core" - * @import { getOwner as GetOwner, onCleanup as OnCleanup } from "./modules/solidjs-signals/0.6.3/dist/types/core/owner" - * @import { createSignal as CreateSignal, createEffect as CreateEffect, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner, Setter } from "./modules/solidjs-signals/0.6.3/dist/types/signals"; + * @import { SignalOptions } from "./modules/solidjs-signals/0.6.3/dist/types/core/core.js" + * @import { getOwner as GetOwner, onCleanup as OnCleanup } from "./modules/solidjs-signals/0.6.3/dist/types/core/owner.js" + * @import { createSignal as CreateSignal, createEffect as CreateEffect, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner, Setter } from "./modules/solidjs-signals/0.6.3/dist/types/signals.js"; */ /** @@ -24,7 +24,7 @@ import { onCleanup, } from "./modules/solidjs-signals/0.6.3/dist/prod.js"; -let effectCount = 0; +// let effectCount = 0; const signals = { createSolidSignal: /** @type {typeof CreateSignal} */ (createSignal), @@ -95,8 +95,8 @@ const signals = { }-${paramKey}`, ); - /** @type { ((this: Window, ev: PopStateEvent) => any) | undefined} */ - let popstateCallback; + // /** @type { ((this: Window, ev: PopStateEvent) => any) | undefined} */ + // let popstateCallback; let serialized = /** @type {string | null} */ (null); if (options.save.serializeParam !== false) { diff --git a/websites/bitview/scripts/utils/dom.js b/websites/bitview/scripts/utils/dom.js index 2c49ab4cd..6343b5177 100644 --- a/websites/bitview/scripts/utils/dom.js +++ b/websites/bitview/scripts/utils/dom.js @@ -1,5 +1,3 @@ -import { serdeString } from "./serde"; - /** * @param {string} id * @returns {HTMLElement} @@ -215,15 +213,17 @@ export function importStyle(href) { } /** - * @template {Readonly} T + * @template T * @param {Object} args - * @param {T[number]} args.defaultValue + * @param {T} args.defaultValue * @param {string} [args.id] - * @param {T | Accessor} args.choices + * @param {readonly T[] | Accessor} args.choices * @param {string} [args.keyPrefix] * @param {string} args.key * @param {boolean} [args.sorted] * @param {Signals} args.signals + * @param {(choice: T) => string} [args.toKey] - Extract string key for storage (defaults to identity for strings) + * @param {(choice: T) => string} [args.toLabel] - Extract display label (defaults to identity for strings) */ export function createHorizontalChoiceField({ id, @@ -233,9 +233,13 @@ export function createHorizontalChoiceField({ key, signals, sorted, + toKey = /** @type {(choice: T) => string} */ ((/** @type {any} */ c) => c), + toLabel = /** @type {(choice: T) => string} */ ((/** @type {any} */ c) => c), }) { + const defaultKey = toKey(defaultValue); + const choices = signals.createMemo(() => { - /** @type {T} */ + /** @type {readonly T[]} */ let c; if (typeof unsortedChoices === "function") { c = unsortedChoices(); @@ -244,16 +248,28 @@ export function createHorizontalChoiceField({ } return sorted - ? /** @type {T} */ ( - /** @type {any} */ (c.toSorted((a, b) => a.localeCompare(b))) + ? /** @type {readonly T[]} */ ( + /** @type {any} */ ( + c.toSorted((a, b) => toLabel(a).localeCompare(toLabel(b))) + ) ) : c; }); - /** @type {Signal} */ + /** + * @param {string} storedKey + * @returns {T} + */ + function fromKey(storedKey) { + const found = choices().find((c) => toKey(c) === storedKey); + return found ?? defaultValue; + } + + /** @type {Signal} */ const selected = signals.createSignal(defaultValue, { save: { - ...serdeString, + serialize: (v) => toKey(v), + deserialize: (s) => fromKey(s), keyPrefix: keyPrefix ?? "", key, saveDefaultValue: true, @@ -268,8 +284,10 @@ export function createHorizontalChoiceField({ signals.createEffect(choices, (choices) => { const s = selected(); - if (!choices.includes(s)) { - if (choices.includes(defaultValue)) { + const sKey = toKey(s); + const keys = choices.map(toKey); + if (!keys.includes(sKey)) { + if (keys.includes(defaultKey)) { selected.set(() => defaultValue); } else if (choices.length) { selected.set(() => choices[0]); @@ -279,17 +297,18 @@ export function createHorizontalChoiceField({ div.innerHTML = ""; choices.forEach((choice) => { - const inputValue = choice; + const choiceKey = toKey(choice); + const choiceLabel = toLabel(choice); const { label } = createLabeledInput({ - inputId: `${id ?? key}-${choice.toLowerCase()}`, + inputId: `${id ?? key}-${choiceKey.toLowerCase()}`, inputName: id ?? key, - inputValue, - inputChecked: inputValue === selected(), - // title: choice, + inputValue: choiceKey, + inputChecked: choiceKey === sKey, + // title: choiceLabel, type: "radio", }); - const text = window.document.createTextNode(choice); + const text = window.document.createTextNode(choiceLabel); label.append(text); div.append(label); }); @@ -298,7 +317,7 @@ export function createHorizontalChoiceField({ field.addEventListener("change", (event) => { // @ts-ignore const value = event.target.value; - selected.set(value); + selected.set(() => fromKey(value)); }); return { field, selected }; diff --git a/websites/bitview/scripts/utils/elements.js b/websites/bitview/scripts/utils/elements.js index 4094b9323..10483a49d 100644 --- a/websites/bitview/scripts/utils/elements.js +++ b/websites/bitview/scripts/utils/elements.js @@ -1,4 +1,4 @@ -import { getElementById } from "./dom"; +import { getElementById } from "./dom.js"; export const style = getComputedStyle(window.document.documentElement); diff --git a/websites/bitview/scripts/utils/serde.js b/websites/bitview/scripts/utils/serde.js index 697f1e29f..cc1e6c2dd 100644 --- a/websites/bitview/scripts/utils/serde.js +++ b/websites/bitview/scripts/utils/serde.js @@ -141,7 +141,7 @@ export const serdeChartableIndex = { }, /** * @param {ChartableIndexName} v - * @returns {IndexName} + * @returns {ChartableIndex} */ deserialize(v) { switch (v) { @@ -223,309 +223,3 @@ export const serdeChartableIndex = { * "years" | * "" } Unit */ - -export const serdeUnit = { - /** - * @param {string} v - */ - deserialize(v) { - /** @type {Unit | undefined} */ - let unit; - - /** - * @param {Unit} u - */ - function setUnit(u) { - if (unit) - throw Error( - `Can't assign "${u}" to unit, "${unit}" is already assigned to "${v}"`, - ); - unit = u; - } - - if ( - (!unit || localhost) && - (v.includes("in_sats") || - v.endsWith("_sats") || - (v.endsWith("supply") && - !(v.endsWith("circulating_supply") || v.endsWith("_own_supply"))) || - v === "sent" || - v === "annualized_volume" || - v.endsWith("supply_half") || - v.endsWith("supply_in_profit") || - v.endsWith("supply_in_loss") || - v.endsWith("stack") || - (v.endsWith("value") && !v.includes("realized")) || - ((v.includes("coinbase") || - v.includes("fee") || - v.includes("subsidy") || - v.includes("rewards")) && - !( - v.startsWith("is_") || - v.includes("_btc") || - v.includes("_usd") || - v.includes("fee_rate") || - v.endsWith("dominance") - ))) - ) { - setUnit("sats"); - } - if ( - (!unit || localhost) && - !v.endsWith("velocity") && - ((v.includes("_btc") && - !(v.includes("0k_btc") || v.includes("1k_btc"))) || - v.endsWith("_btc")) - ) { - setUnit("btc"); - } - if ((!unit || localhost) && v === "chain") { - setUnit("block"); - } - if ((!unit || localhost) && v.startsWith("blocks_before")) { - setUnit("blocks"); - } - if ( - (!unit || localhost) && - (v === "emptyaddressdata" || v === "loadedaddressdata") - ) { - setUnit("address data"); - } - if ( - (!unit || localhost) && - (v === "price_high" || - v === "price_ohlc" || - v === "price_low" || - v === "price_close" || - v === "price_open" || - v === "price_ath" || - v === "market_cap" || - v.startsWith("price_true_range") || - (v.includes("_usd") && !v.endsWith("velocity")) || - v.includes("cointime_value") || - v.endsWith("_ago") || - v.includes("cost_basis") || - v.endsWith("_price") || - (v.startsWith("price") && (v.endsWith("min") || v.endsWith("max"))) || - (v.endsWith("_cap") && !v.includes("rel_to")) || - v.endsWith("value_created") || - v.endsWith("value_destroyed") || - ((v.includes("realized") || v.includes("true_market_mean")) && - !v.includes("unrealized") && - !v.includes("ratio") && - !v.includes("rel_to")) || - (v.includes("unrealized") && !v.includes("rel_to")) || - ((v.endsWith("sma") || v.includes("sma_x") || v.endsWith("ema")) && - !v.includes("ratio") && - !v.includes("sopr") && - !v.includes("hash_rate")) || - v === "ath") - ) { - setUnit("usd"); - } - if ((!unit || localhost) && v.endsWith("cents")) { - setUnit("cents"); - } - if ( - ((!unit || localhost) && - (v.endsWith("ratio") || - (v.includes("ratio") && - (v.endsWith("sma") || v.endsWith("ema") || v.endsWith("zscore"))) || - v.includes("sopr") || - v.endsWith("_5sd") || - v.endsWith("1sd") || - v.endsWith("2sd") || - v.endsWith("3sd") || - v.endsWith("pct1") || - v.endsWith("pct2") || - v.endsWith("pct5") || - v.endsWith("pct95") || - v.endsWith("pct98") || - v.endsWith("pct99"))) || - v.includes("liveliness") || - v.includes("vaultedness") || - v == "puell_multiple" || - v.endsWith("velocity") - ) { - setUnit("ratio"); - } - if ( - (!unit || localhost) && - (v === "price_drawdown" || - v === "difficulty_adjustment" || - v.endsWith("inflation_rate") || - v.endsWith("_oscillator") || - v.endsWith("_dominance") || - v.endsWith("_returns") || - v.endsWith("_rebound") || - v.endsWith("_volatility") || - v.endsWith("_cagr")) - ) { - setUnit("percentage"); - } - if ( - (!unit || localhost) && - (v.endsWith("count") || - v.includes("_count_") || - v.startsWith("block_count") || - v.includes("blocks_mined") || - (v.includes("tx_v") && !v.includes("vsize"))) - ) { - setUnit("count"); - } - if ( - (!unit || localhost) && - (v.startsWith("hash_rate") || v.endsWith("as_hash")) - ) { - setUnit("h/s"); - } - if ((!unit || localhost) && v === "pool") { - setUnit("id"); - } - if ((!unit || localhost) && v.includes("fee_rate")) { - setUnit("sat/vb"); - } - if ((!unit || localhost) && v.startsWith("is_")) { - setUnit("bool"); - } - if ((!unit || localhost) && v.endsWith("type")) { - setUnit("type"); - } - if ( - (!unit || localhost) && - (v === "interval" || v.startsWith("block_interval")) - ) { - setUnit("secs"); - } - if ((!unit || localhost) && v.endsWith("_per_sec")) { - setUnit("/sec"); - } - if ((!unit || localhost) && v.endsWith("locktime")) { - setUnit("locktime"); - } - - if ((!unit || localhost) && v.endsWith("version")) { - setUnit("version"); - } - if ( - (!unit || localhost) && - (v === "txid" || - (v.endsWith("bytes") && !v.endsWith("vbytes")) || - v.endsWith("base_size") || - v.endsWith("total_size") || - v.includes("block_size")) - ) { - setUnit("bytes"); - } - if ((!unit || localhost) && v.endsWith("_sd")) { - setUnit("sd"); - } - if ((!unit || localhost) && (v.includes("vsize") || v.includes("vbytes"))) { - setUnit("vb"); - } - if ((!unit || localhost) && v.includes("weight")) { - setUnit("wu"); - } - if ((!unit || localhost) && v.endsWith("index")) { - setUnit("index"); - } - if ((!unit || localhost) && (v === "date" || v === "date_fixed")) { - setUnit("date"); - } - if ( - (!unit || localhost) && - (v === "timestamp" || v === "timestamp_fixed") - ) { - setUnit("timestamp"); - } - if ((!unit || localhost) && v.includes("coinblocks")) { - setUnit("coinblocks"); - } - if ((!unit || localhost) && v.includes("coindays")) { - setUnit("coindays"); - } - if ((!unit || localhost) && v.includes("satblocks")) { - setUnit("satblocks"); - } - if ((!unit || localhost) && v.includes("satdays")) { - setUnit("satdays"); - } - if ((!unit || localhost) && v.endsWith("height")) { - setUnit("height"); - } - if ((!unit || localhost) && v.endsWith("rel_to_market_cap")) { - setUnit("%mcap"); - } - if ((!unit || localhost) && v.endsWith("rel_to_own_market_cap")) { - setUnit("%cmcap"); - } - if ((!unit || localhost) && v.endsWith("rel_to_own_total_unrealized_pnl")) { - setUnit("%cp+l"); - } - if ((!unit || localhost) && v.endsWith("rel_to_realized_cap")) { - setUnit("%rcap"); - } - if ((!unit || localhost) && v.endsWith("rel_to_circulating_supply")) { - setUnit("%all"); - } - if ( - (!unit || localhost) && - (v.includes("rel_to_realized_profit") || - v.includes("rel_to_realized_loss")) - ) { - setUnit("%pnl"); - } - if ((!unit || localhost) && v.endsWith("rel_to_own_supply")) { - setUnit("%self"); - } - if ((!unit || localhost) && v.endsWith("epoch")) { - setUnit("epoch"); - } - if ((!unit || localhost) && v === "difficulty") { - setUnit("difficulty"); - } - if ((!unit || localhost) && v === "blockhash") { - setUnit("hash"); - } - if ((!unit || localhost) && v.startsWith("hash_price_phs")) { - setUnit("usd/(ph/s)/day"); - } - if ((!unit || localhost) && v.startsWith("hash_price_ths")) { - setUnit("usd/(th/s)/day"); - } - if ((!unit || localhost) && v.startsWith("hash_value_phs")) { - setUnit("sats/(ph/s)/day"); - } - if ((!unit || localhost) && v.startsWith("hash_value_ths")) { - setUnit("sats/(th/s)/day"); - } - - if ( - (!unit || localhost) && - (v.includes("days_between") || - v.includes("days_since") || - v.startsWith("days_before")) - ) { - setUnit("days"); - } - if ((!unit || localhost) && v.includes("years_between")) { - setUnit("years"); - } - if ((!unit || localhost) && v == "len") { - setUnit("len"); - } - if ((!unit || localhost) && v == "position") { - setUnit("position"); - } - if ((!unit || localhost) && v.startsWith("constant")) { - setUnit("constant"); - } - - if (!unit) { - console.log(); - throw Error(`Unit not set for "${v}"`); - } - - return /** @type {Unit} */ (unit); - }, -}; diff --git a/websites/bitview/scripts/utils/units.js b/websites/bitview/scripts/utils/units.js new file mode 100644 index 000000000..1c3f66f34 --- /dev/null +++ b/websites/bitview/scripts/utils/units.js @@ -0,0 +1,62 @@ +/** Unit definitions for chart series */ + +/** + * Unit enum with id (for serialization) and name (for display) + */ +export const Unit = /** @type {const} */ ({ + // Value units + sats: { id: "sats", name: "Satoshis" }, + btc: { id: "btc", name: "Bitcoin" }, + usd: { id: "usd", name: "US Dollars" }, + + // Ratios & percentages + percentage: { id: "percentage", name: "Percentage" }, + ratio: { id: "ratio", name: "Ratio" }, + index: { id: "index", name: "Index" }, + sd: { id: "sd", name: "Std Dev" }, + + // Relative percentages + pctSupply: { id: "pct-supply", name: "% of Supply" }, + pctOwn: { id: "pct-own", name: "% of Own Supply" }, + pctMcap: { id: "pct-mcap", name: "% of Market Cap" }, + pctRcap: { id: "pct-rcap", name: "% of Realized Cap" }, + pctOwnMcap: { id: "pct-own-mcap", name: "% of Own Market Cap" }, + + // Time + days: { id: "days", name: "Days" }, + years: { id: "years", name: "Years" }, + secs: { id: "secs", name: "Seconds" }, + + // Counts + count: { id: "count", name: "Count" }, + blocks: { id: "blocks", name: "Blocks" }, + + // Size + bytes: { id: "bytes", name: "Bytes" }, + vb: { id: "vb", name: "Virtual Bytes" }, + wu: { id: "wu", name: "Weight Units" }, + + // Mining + hashRate: { id: "hashrate", name: "Hash Rate" }, + difficulty: { id: "difficulty", name: "Difficulty" }, + epoch: { id: "epoch", name: "Epoch" }, + + // Fees + feeRate: { id: "feerate", name: "Sats/vByte" }, + + // Rates + perSec: { id: "per-sec", name: "Per Second" }, + + // Cointime + coinblocks: { id: "coinblocks", name: "Coinblocks" }, + coindays: { id: "coindays", name: "Coindays" }, + + // Hash price/value + usdPerThsPerDay: { id: "usd-ths-day", name: "USD/TH/s/Day" }, + usdPerPhsPerDay: { id: "usd-phs-day", name: "USD/PH/s/Day" }, + satsPerThsPerDay: { id: "sats-ths-day", name: "Sats/TH/s/Day" }, + satsPerPhsPerDay: { id: "sats-phs-day", name: "Sats/PH/s/Day" }, +}); + +/** @typedef {keyof typeof Unit} UnitKey */ +/** @typedef {typeof Unit[UnitKey]} UnitObject */