clients: snapshot

This commit is contained in:
nym21
2026-01-14 01:20:25 +01:00
parent 3a836ab0f4
commit 25a0ebe51e
10 changed files with 7218 additions and 3920 deletions
+93 -8
View File
@@ -120,6 +120,9 @@ pub struct PatternBaseResult {
/// Whether an outlier child was excluded to find the pattern. /// Whether an outlier child was excluded to find the pattern.
/// If true, pattern factory should not be used. /// If true, pattern factory should not be used.
pub has_outlier: bool, pub has_outlier: bool,
/// Whether this instance uses suffix mode (common prefix) or prefix mode (common suffix).
/// Used to check compatibility with the pattern's mode.
pub is_suffix_mode: bool,
} }
/// Get the metric base for a pattern instance by analyzing direct children. /// Get the metric base for a pattern instance by analyzing direct children.
@@ -137,12 +140,17 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
return PatternBaseResult { return PatternBaseResult {
base: String::new(), base: String::new(),
has_outlier: false, has_outlier: false,
is_suffix_mode: true, // default
}; };
} }
// Try to find common base from leaf names // Try to find common base from leaf names
if let Some((base, has_outlier)) = try_find_base(&child_names, false) { if let Some(result) = try_find_base(&child_names, false) {
return PatternBaseResult { base, has_outlier }; return PatternBaseResult {
base: result.base,
has_outlier: result.has_outlier,
is_suffix_mode: result.is_suffix_mode,
};
} }
// If no common pattern found and we have enough children, try excluding outliers // If no common pattern found and we have enough children, try excluding outliers
@@ -155,10 +163,11 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
.map(|(_, v)| v.clone()) .map(|(_, v)| v.clone())
.collect(); .collect();
if let Some((base, _)) = try_find_base(&filtered, true) { if let Some(result) = try_find_base(&filtered, true) {
return PatternBaseResult { return PatternBaseResult {
base, base: result.base,
has_outlier: true, has_outlier: true,
is_suffix_mode: result.is_suffix_mode,
}; };
} }
} }
@@ -169,24 +178,40 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
PatternBaseResult { PatternBaseResult {
base: String::new(), base: String::new(),
has_outlier: false, has_outlier: false,
is_suffix_mode: true, // default
} }
} }
/// Result of try_find_base: base name, has_outlier flag, and is_suffix_mode flag.
struct FindBaseResult {
base: String,
has_outlier: bool,
is_suffix_mode: bool,
}
/// Try to find a common base from child names using prefix/suffix detection. /// Try to find a common base from child names using prefix/suffix detection.
/// Returns Some((base, has_outlier)) if found. /// Returns Some(FindBaseResult) if found.
fn try_find_base(child_names: &[(String, String)], is_outlier_attempt: bool) -> Option<(String, bool)> { fn try_find_base(child_names: &[(String, String)], is_outlier_attempt: bool) -> Option<FindBaseResult> {
let leaf_names: Vec<&str> = child_names.iter().map(|(_, n)| n.as_str()).collect(); let leaf_names: Vec<&str> = child_names.iter().map(|(_, n)| n.as_str()).collect();
// Try common prefix first (suffix mode) // Try common prefix first (suffix mode)
if let Some(prefix) = find_common_prefix(&leaf_names) { if let Some(prefix) = find_common_prefix(&leaf_names) {
let base = prefix.trim_end_matches('_').to_string(); let base = prefix.trim_end_matches('_').to_string();
return Some((base, is_outlier_attempt)); return Some(FindBaseResult {
base,
has_outlier: is_outlier_attempt,
is_suffix_mode: true,
});
} }
// Try common suffix (prefix mode) // Try common suffix (prefix mode)
if let Some(suffix) = find_common_suffix(&leaf_names) { if let Some(suffix) = find_common_suffix(&leaf_names) {
let base = suffix.trim_start_matches('_').to_string(); let base = suffix.trim_start_matches('_').to_string();
return Some((base, is_outlier_attempt)); return Some(FindBaseResult {
base,
has_outlier: is_outlier_attempt,
is_suffix_mode: false,
});
} }
None None
@@ -409,4 +434,64 @@ mod tests {
assert_eq!(result.base, "sopr"); assert_eq!(result.base, "sopr");
assert!(result.has_outlier); // Pattern factory should NOT be used (inline instead) assert!(result.has_outlier); // Pattern factory should NOT be used (inline instead)
} }
#[test]
fn test_get_pattern_instance_base_suffix_mode_price_ago() {
// Simulates price_ago pattern: price_1d_ago, price_1w_ago, price_10y_ago
// Common prefix is "price_", so this is suffix mode
let tree = make_branch(vec![
("_1d", make_leaf("price_1d_ago")),
("_1w", make_leaf("price_1w_ago")),
("_1m", make_leaf("price_1m_ago")),
("_10y", make_leaf("price_10y_ago")),
]);
let result = get_pattern_instance_base(&tree);
assert_eq!(result.base, "price");
assert!(result.is_suffix_mode); // Suffix mode: _m(base, "1d_ago")
assert!(!result.has_outlier);
}
#[test]
fn test_get_pattern_instance_base_prefix_mode_price_returns() {
// Simulates price_returns pattern: 1d_price_returns, 1w_price_returns, 10y_price_returns
// Common suffix is "_price_returns", so this is prefix mode
let tree = make_branch(vec![
("_1d", make_leaf("1d_price_returns")),
("_1w", make_leaf("1w_price_returns")),
("_1m", make_leaf("1m_price_returns")),
("_10y", make_leaf("10y_price_returns")),
]);
let result = get_pattern_instance_base(&tree);
assert_eq!(result.base, "price_returns");
assert!(!result.is_suffix_mode); // Prefix mode: _p("1d_", base)
assert!(!result.has_outlier);
}
#[test]
fn test_mode_detection_distinguishes_similar_structures() {
// Two patterns with identical structure but different naming conventions
// should have different modes detected
// Suffix mode pattern
let suffix_tree = make_branch(vec![
("_1y", make_leaf("lump_sum_1y")),
("_2y", make_leaf("lump_sum_2y")),
("_5y", make_leaf("lump_sum_5y")),
]);
let suffix_result = get_pattern_instance_base(&suffix_tree);
assert_eq!(suffix_result.base, "lump_sum");
assert!(suffix_result.is_suffix_mode);
// Prefix mode pattern (same structure, different naming)
let prefix_tree = make_branch(vec![
("_1y", make_leaf("1y_returns")),
("_2y", make_leaf("2y_returns")),
("_5y", make_leaf("5y_returns")),
]);
let prefix_result = get_pattern_instance_base(&prefix_tree);
assert_eq!(prefix_result.base, "returns");
assert!(!prefix_result.is_suffix_mode);
}
} }
+15 -3
View File
@@ -55,12 +55,17 @@ pub fn prepare_tree_node<'a>(
.map(|(f, _)| f.clone()) .map(|(f, _)| f.clone())
.collect(); .collect();
// Skip if this matches a parameterizable pattern AND has no outlier // Skip if this matches a parameterizable pattern AND has no outlier AND mode matches
let base_result = get_pattern_instance_base(node); let base_result = get_pattern_instance_base(node);
let mode_matches = pattern_lookup
.get(&fields)
.and_then(|name| metadata.find_pattern(name))
.is_none_or(|p| p.is_suffix_mode() == base_result.is_suffix_mode);
if let Some(pattern_name) = pattern_lookup.get(&fields) if let Some(pattern_name) = pattern_lookup.get(&fields)
&& pattern_name != name && pattern_name != name
&& metadata.is_parameterizable(pattern_name) && metadata.is_parameterizable(pattern_name)
&& !base_result.has_outlier && !base_result.has_outlier
&& mode_matches
{ {
return None; return None;
} }
@@ -84,9 +89,16 @@ pub fn prepare_tree_node<'a>(
.as_ref() .as_ref()
.is_some_and(|cf| metadata.matches_pattern(cf)); .is_some_and(|cf| metadata.matches_pattern(cf));
// Check if the pattern mode matches the instance mode
let mode_matches = child_fields
.as_ref()
.and_then(|cf| metadata.find_pattern_by_fields(cf))
.is_none_or(|p| p.is_suffix_mode() == base_result.is_suffix_mode);
// should_inline determines if we generate an inline struct type // should_inline determines if we generate an inline struct type
// We inline only if it's a branch AND doesn't match any pattern // We inline if: it's a branch AND (doesn't match any pattern OR mode doesn't match OR has outlier)
let should_inline = !is_leaf && !matches_any_pattern; let should_inline =
!is_leaf && (!matches_any_pattern || !mode_matches || base_result.has_outlier);
// Inline type name (only used when should_inline is true) // Inline type name (only used when should_inline is true)
let inline_type_name = if should_inline { let inline_type_name = if should_inline {
@@ -6,9 +6,8 @@ use std::fmt::Write;
use brk_types::TreeNode; use brk_types::TreeNode;
use crate::{ use crate::{
ClientMetadata, Endpoint, GenericSyntax, JavaScriptSyntax, PatternField, ClientMetadata, Endpoint, GenericSyntax, JavaScriptSyntax, PatternField, generate_leaf_field,
generate_leaf_field, get_first_leaf_name, get_node_fields, get_pattern_instance_base, prepare_tree_node, to_camel_case,
infer_accumulated_name, prepare_tree_node, to_camel_case,
}; };
use super::api::generate_api_methods; use super::api::generate_api_methods;
@@ -121,15 +120,36 @@ pub fn generate_main_client(
writeln!(output, " */").unwrap(); writeln!(output, " */").unwrap();
writeln!(output, " _buildTree(basePath) {{").unwrap(); writeln!(output, " _buildTree(basePath) {{").unwrap();
writeln!(output, " return {{").unwrap(); writeln!(output, " return {{").unwrap();
generate_tree_initializer(output, catalog, "", 3, &pattern_lookup, metadata); let mut generated = HashSet::new();
generate_tree_initializer(
output,
catalog,
"MetricsTree",
3,
&pattern_lookup,
metadata,
&mut generated,
);
writeln!(output, " }};").unwrap(); writeln!(output, " }};").unwrap();
writeln!(output, " }}\n").unwrap(); writeln!(output, " }}\n").unwrap();
writeln!(output, " /**").unwrap(); writeln!(output, " /**").unwrap();
writeln!(output, " * Create a dynamic metric endpoint builder for any metric/index combination.").unwrap(); writeln!(
output,
" * Create a dynamic metric endpoint builder for any metric/index combination."
)
.unwrap();
writeln!(output, " *").unwrap(); writeln!(output, " *").unwrap();
writeln!(output, " * Use this for programmatic access when the metric name is determined at runtime.").unwrap(); writeln!(
writeln!(output, " * For type-safe access, use the `metrics` tree instead.").unwrap(); output,
" * Use this for programmatic access when the metric name is determined at runtime."
)
.unwrap();
writeln!(
output,
" * For type-safe access, use the `metrics` tree instead."
)
.unwrap();
writeln!(output, " *").unwrap(); writeln!(output, " *").unwrap();
writeln!(output, " * @param {{string}} metric - The metric name").unwrap(); writeln!(output, " * @param {{string}} metric - The metric name").unwrap();
writeln!(output, " * @param {{Index}} index - The index name").unwrap(); writeln!(output, " * @param {{Index}} index - The index name").unwrap();
@@ -149,66 +169,55 @@ pub fn generate_main_client(
fn generate_tree_initializer( fn generate_tree_initializer(
output: &mut String, output: &mut String,
node: &TreeNode, node: &TreeNode,
accumulated_name: &str, name: &str,
indent: usize, indent: usize,
pattern_lookup: &std::collections::HashMap<Vec<PatternField>, String>, pattern_lookup: &std::collections::HashMap<Vec<PatternField>, String>,
metadata: &ClientMetadata, metadata: &ClientMetadata,
generated: &mut HashSet<String>,
) { ) {
let indent_str = " ".repeat(indent); let indent_str = " ".repeat(indent);
let Some(ctx) = prepare_tree_node(node, name, pattern_lookup, metadata, generated) else {
return;
};
let syntax = JavaScriptSyntax; let syntax = JavaScriptSyntax;
if let TreeNode::Branch(children) = node { for child in &ctx.children {
for (child_name, child_node) in children.iter() { let field_name = to_camel_case(child.name);
match child_node {
TreeNode::Leaf(leaf) => {
// Use shared helper for leaf fields
generate_leaf_field(
output,
&syntax,
"this",
child_name,
leaf,
metadata,
&indent_str,
);
}
TreeNode::Branch(grandchildren) => {
let field_name = to_camel_case(child_name);
let child_fields = get_node_fields(grandchildren, pattern_lookup);
// Use pattern factory if ANY pattern matches (not just parameterizable)
let pattern_name = pattern_lookup.get(&child_fields);
let base_result = get_pattern_instance_base(child_node); if child.is_leaf {
if let TreeNode::Leaf(leaf) = child.node {
// Use pattern factory only if no outlier was detected generate_leaf_field(
if let Some(pattern_name) = pattern_name.filter(|_| !base_result.has_outlier) { output,
writeln!( &syntax,
output, "this",
"{}{}: create{}(this, '{}'),", child.name,
indent_str, field_name, pattern_name, base_result.base leaf,
) metadata,
.unwrap(); &indent_str,
} else { );
let child_acc =
infer_child_accumulated_name(child_node, accumulated_name, child_name);
writeln!(output, "{}{}: {{", indent_str, field_name).unwrap();
generate_tree_initializer(
output,
child_node,
&child_acc,
indent + 1,
pattern_lookup,
metadata,
);
writeln!(output, "{}}},", indent_str).unwrap();
}
}
} }
} else if child.should_inline {
// Inline object
writeln!(output, "{}{}: {{", indent_str, field_name).unwrap();
generate_tree_initializer(
output,
child.node,
&child.inline_type_name,
indent + 1,
pattern_lookup,
metadata,
generated,
);
writeln!(output, "{}}},", indent_str).unwrap();
} else {
// Use pattern factory
writeln!(
output,
"{}{}: create{}(this, '{}'),",
indent_str, field_name, child.field.rust_type, child.base_result.base
)
.unwrap();
} }
} }
} }
fn infer_child_accumulated_name(node: &TreeNode, parent_acc: &str, field_name: &str) -> String {
let leaf_name = get_first_leaf_name(node).unwrap_or_default();
infer_accumulated_name(parent_acc, field_name, &leaf_name)
}
@@ -392,7 +392,12 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output, "impl<T: DeserializeOwned> {}<T> {{", by_name).unwrap(); writeln!(output, "impl<T: DeserializeOwned> {}<T> {{", by_name).unwrap();
for index in &pattern.indexes { for index in &pattern.indexes {
let method_name = index_to_field_name(index); let method_name = index_to_field_name(index);
writeln!(output, " pub fn {}(&self) -> MetricEndpointBuilder<T> {{", method_name).unwrap(); writeln!(
output,
" pub fn {}(&self) -> MetricEndpointBuilder<T> {{",
method_name
)
.unwrap();
writeln!( writeln!(
output, output,
" MetricEndpointBuilder::new(self.client.clone(), self.name.clone(), Index::{})", " MetricEndpointBuilder::new(self.client.clone(), self.name.clone(), Index::{})",
@@ -425,7 +430,12 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output, " let name: Arc<str> = name.into();").unwrap(); writeln!(output, " let name: Arc<str> = name.into();").unwrap();
writeln!(output, " Self {{").unwrap(); writeln!(output, " Self {{").unwrap();
writeln!(output, " name: name.clone(),").unwrap(); writeln!(output, " name: name.clone(),").unwrap();
writeln!(output, " by: {} {{ client, name, _marker: std::marker::PhantomData }}", by_name).unwrap(); writeln!(
output,
" by: {} {{ client, name, _marker: std::marker::PhantomData }}",
by_name
)
.unwrap();
writeln!(output, " }}").unwrap(); writeln!(output, " }}").unwrap();
writeln!(output, " }}").unwrap(); writeln!(output, " }}").unwrap();
writeln!(output).unwrap(); writeln!(output).unwrap();
@@ -436,7 +446,12 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output, "}}\n").unwrap(); writeln!(output, "}}\n").unwrap();
// Implement AnyMetricPattern trait // Implement AnyMetricPattern trait
writeln!(output, "impl<T> AnyMetricPattern for {}<T> {{", pattern.name).unwrap(); writeln!(
output,
"impl<T> AnyMetricPattern for {}<T> {{",
pattern.name
)
.unwrap();
writeln!(output, " fn name(&self) -> &str {{").unwrap(); writeln!(output, " fn name(&self) -> &str {{").unwrap();
writeln!(output, " &self.name").unwrap(); writeln!(output, " &self.name").unwrap();
writeln!(output, " }}").unwrap(); writeln!(output, " }}").unwrap();
@@ -451,12 +466,26 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
writeln!(output, "}}\n").unwrap(); writeln!(output, "}}\n").unwrap();
// Implement MetricPattern<T> trait // Implement MetricPattern<T> trait
writeln!(output, "impl<T: DeserializeOwned> MetricPattern<T> for {}<T> {{", pattern.name).unwrap(); writeln!(
writeln!(output, " fn get(&self, index: Index) -> Option<MetricEndpointBuilder<T>> {{").unwrap(); output,
"impl<T: DeserializeOwned> MetricPattern<T> for {}<T> {{",
pattern.name
)
.unwrap();
writeln!(
output,
" fn get(&self, index: Index) -> Option<MetricEndpointBuilder<T>> {{"
)
.unwrap();
writeln!(output, " match index {{").unwrap(); writeln!(output, " match index {{").unwrap();
for index in &pattern.indexes { for index in &pattern.indexes {
let method_name = index_to_field_name(index); let method_name = index_to_field_name(index);
writeln!(output, " Index::{} => Some(self.by.{}()),", index, method_name).unwrap(); writeln!(
output,
" Index::{} => Some(self.by.{}()),",
index, method_name
)
.unwrap();
} }
writeln!(output, " _ => None,").unwrap(); writeln!(output, " _ => None,").unwrap();
writeln!(output, " }}").unwrap(); writeln!(output, " }}").unwrap();
@@ -486,8 +515,12 @@ pub fn generate_pattern_structs(
for field in &pattern.fields { for field in &pattern.fields {
let field_name = to_snake_case(&field.name); let field_name = to_snake_case(&field.name);
let type_annotation = let type_annotation = metadata.field_type_annotation(
metadata.field_type_annotation(field, pattern.is_generic, None, GenericSyntax::RUST); field,
pattern.is_generic,
None,
GenericSyntax::RUST,
);
writeln!(output, " pub {}: {},", field_name, type_annotation).unwrap(); writeln!(output, " pub {}: {},", field_name, type_annotation).unwrap();
} }
+8
View File
@@ -95,6 +95,14 @@ impl ClientMetadata {
|| self.structural_patterns.iter().any(|p| p.fields == fields) || self.structural_patterns.iter().any(|p| p.fields == fields)
} }
/// Find a pattern by its fields.
pub fn find_pattern_by_fields(&self, fields: &[PatternField]) -> Option<&StructuralPattern> {
self.concrete_to_pattern
.get(fields)
.and_then(|name| self.find_pattern(name))
.or_else(|| self.structural_patterns.iter().find(|p| p.fields == fields))
}
/// Resolve the type name for a tree field. /// Resolve the type name for a tree field.
/// If the field matches ANY pattern (parameterizable or not), returns pattern type. /// If the field matches ANY pattern (parameterizable or not), returns pattern type.
/// Otherwise returns the inline type name (parent_child format). /// Otherwise returns the inline type name (parent_child format).
+8 -36
View File
@@ -52,40 +52,27 @@ fn main() -> brk_client::Result<()> {
println!("\nFound {} metrics", metrics.len()); println!("\nFound {} metrics", metrics.len());
let mut success = 0; let mut success = 0;
let mut failed = 0;
let mut errors: Vec<String> = Vec::new();
for metric in &metrics { for metric in &metrics {
for index in &metric.indexes { for index in &metric.indexes {
let index_str = index.serialize_long(); let index_str = index.serialize_long();
let full_path = format!("{}.by.{}", metric.path, index_str);
match client.get_metric( match client.get_metric(
metric.name.as_str().into(), metric.name.as_str().into(),
*index, *index,
None, None,
Some(0),
None, None,
Some("-3"),
None, None,
) { ) {
Ok(response) => { Ok(_) => {
let count = response.json().data.len(); success += 1;
if count != 3 { println!("OK: {}", full_path);
failed += 1;
let error_msg = format!(
"FAIL: {}.by.{} -> expected 3, got {}",
metric.path, index_str, count
);
errors.push(error_msg.clone());
println!("{}", error_msg);
} else {
success += 1;
println!("OK: {}.by.{} -> {} items", metric.path, index_str, count);
}
} }
Err(e) => { Err(e) => {
failed += 1; println!("FAIL: {} -> {}", full_path, e);
let error_msg = format!("FAIL: {}.by.{} -> {}", metric.path, index_str, e); return Err(e);
errors.push(error_msg.clone());
println!("{}", error_msg);
} }
} }
} }
@@ -93,21 +80,6 @@ fn main() -> brk_client::Result<()> {
println!("\n=== Results ==="); println!("\n=== Results ===");
println!("Success: {}", success); println!("Success: {}", success);
println!("Failed: {}", failed);
if !errors.is_empty() {
println!("\nErrors:");
for err in errors.iter().take(10) {
println!(" {}", err);
}
if errors.len() > 10 {
println!(" ... and {} more", errors.len() - 10);
}
}
if failed > 0 {
std::process::exit(1);
}
Ok(()) Ok(())
} }
+1968 -709
View File
File diff suppressed because it is too large Load Diff
+330 -290
View File
@@ -3155,7 +3155,7 @@ function createAaopoolPattern(client, acc) {
/** /**
* @template T * @template T
* @typedef {Object} PriceAgoPattern * @typedef {Object} LookbackPattern
* @property {MetricPattern4<T>} _10y * @property {MetricPattern4<T>} _10y
* @property {MetricPattern4<T>} _1d * @property {MetricPattern4<T>} _1d
* @property {MetricPattern4<T>} _1m * @property {MetricPattern4<T>} _1m
@@ -3172,13 +3172,13 @@ function createAaopoolPattern(client, acc) {
*/ */
/** /**
* Create a PriceAgoPattern pattern node * Create a LookbackPattern pattern node
* @template T * @template T
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name * @param {string} acc - Accumulated metric name
* @returns {PriceAgoPattern<T>} * @returns {LookbackPattern<T>}
*/ */
function createPriceAgoPattern(client, acc) { function createLookbackPattern(client, acc) {
return { return {
_10y: createMetricPattern4(client, _m(acc, "10y_ago")), _10y: createMetricPattern4(client, _m(acc, "10y_ago")),
_1d: createMetricPattern4(client, _m(acc, "1d_ago")), _1d: createMetricPattern4(client, _m(acc, "1d_ago")),
@@ -3338,17 +3338,17 @@ function createBitcoinPattern(client, acc) {
*/ */
function createClassAveragePricePattern(client, acc) { function createClassAveragePricePattern(client, acc) {
return { return {
_2015: createMetricPattern4(client, _m(acc, "2015_returns")), _2015: createMetricPattern4(client, _m(acc, "2015_average_price")),
_2016: createMetricPattern4(client, _m(acc, "2016_returns")), _2016: createMetricPattern4(client, _m(acc, "2016_average_price")),
_2017: createMetricPattern4(client, _m(acc, "2017_returns")), _2017: createMetricPattern4(client, _m(acc, "2017_average_price")),
_2018: createMetricPattern4(client, _m(acc, "2018_returns")), _2018: createMetricPattern4(client, _m(acc, "2018_average_price")),
_2019: createMetricPattern4(client, _m(acc, "2019_returns")), _2019: createMetricPattern4(client, _m(acc, "2019_average_price")),
_2020: createMetricPattern4(client, _m(acc, "2020_returns")), _2020: createMetricPattern4(client, _m(acc, "2020_average_price")),
_2021: createMetricPattern4(client, _m(acc, "2021_returns")), _2021: createMetricPattern4(client, _m(acc, "2021_average_price")),
_2022: createMetricPattern4(client, _m(acc, "2022_returns")), _2022: createMetricPattern4(client, _m(acc, "2022_average_price")),
_2023: createMetricPattern4(client, _m(acc, "2023_returns")), _2023: createMetricPattern4(client, _m(acc, "2023_average_price")),
_2024: createMetricPattern4(client, _m(acc, "2024_returns")), _2024: createMetricPattern4(client, _m(acc, "2024_average_price")),
_2025: createMetricPattern4(client, _m(acc, "2025_returns")), _2025: createMetricPattern4(client, _m(acc, "2025_average_price")),
}; };
} }
@@ -3391,68 +3391,6 @@ function createDollarsPattern(client, acc) {
}; };
} }
/**
* @typedef {Object} RelativePattern
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToMarketCap
* @property {MetricPattern1<StoredF32>} netUnrealizedPnlRelToMarketCap
* @property {MetricPattern1<StoredF32>} nupl
* @property {MetricPattern1<StoredF64>} supplyInLossRelToCirculatingSupply
* @property {MetricPattern1<StoredF64>} supplyInLossRelToOwnSupply
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToCirculatingSupply
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToOwnSupply
* @property {MetricPattern4<StoredF64>} supplyRelToCirculatingSupply
* @property {MetricPattern1<StoredF32>} unrealizedLossRelToMarketCap
* @property {MetricPattern1<StoredF32>} unrealizedProfitRelToMarketCap
*/
/**
* Create a RelativePattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {RelativePattern}
*/
function createRelativePattern(client, acc) {
return {
negUnrealizedLossRelToMarketCap: createMetricPattern1(
client,
_m(acc, "neg_unrealized_loss_rel_to_market_cap"),
),
netUnrealizedPnlRelToMarketCap: createMetricPattern1(
client,
_m(acc, "net_unrealized_pnl_rel_to_market_cap"),
),
nupl: createMetricPattern1(client, _m(acc, "nupl")),
supplyInLossRelToCirculatingSupply: createMetricPattern1(
client,
_m(acc, "supply_in_loss_rel_to_circulating_supply"),
),
supplyInLossRelToOwnSupply: createMetricPattern1(
client,
_m(acc, "supply_in_loss_rel_to_own_supply"),
),
supplyInProfitRelToCirculatingSupply: createMetricPattern1(
client,
_m(acc, "supply_in_profit_rel_to_circulating_supply"),
),
supplyInProfitRelToOwnSupply: createMetricPattern1(
client,
_m(acc, "supply_in_profit_rel_to_own_supply"),
),
supplyRelToCirculatingSupply: createMetricPattern4(
client,
_m(acc, "supply_rel_to_circulating_supply"),
),
unrealizedLossRelToMarketCap: createMetricPattern1(
client,
_m(acc, "unrealized_loss_rel_to_market_cap"),
),
unrealizedProfitRelToMarketCap: createMetricPattern1(
client,
_m(acc, "unrealized_profit_rel_to_market_cap"),
),
};
}
/** /**
* @typedef {Object} RelativePattern2 * @typedef {Object} RelativePattern2
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToOwnMarketCap * @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToOwnMarketCap
@@ -3518,6 +3456,68 @@ function createRelativePattern2(client, acc) {
}; };
} }
/**
* @typedef {Object} RelativePattern
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToMarketCap
* @property {MetricPattern1<StoredF32>} netUnrealizedPnlRelToMarketCap
* @property {MetricPattern1<StoredF32>} nupl
* @property {MetricPattern1<StoredF64>} supplyInLossRelToCirculatingSupply
* @property {MetricPattern1<StoredF64>} supplyInLossRelToOwnSupply
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToCirculatingSupply
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToOwnSupply
* @property {MetricPattern4<StoredF64>} supplyRelToCirculatingSupply
* @property {MetricPattern1<StoredF32>} unrealizedLossRelToMarketCap
* @property {MetricPattern1<StoredF32>} unrealizedProfitRelToMarketCap
*/
/**
* Create a RelativePattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {RelativePattern}
*/
function createRelativePattern(client, acc) {
return {
negUnrealizedLossRelToMarketCap: createMetricPattern1(
client,
_m(acc, "neg_unrealized_loss_rel_to_market_cap"),
),
netUnrealizedPnlRelToMarketCap: createMetricPattern1(
client,
_m(acc, "net_unrealized_pnl_rel_to_market_cap"),
),
nupl: createMetricPattern1(client, _m(acc, "nupl")),
supplyInLossRelToCirculatingSupply: createMetricPattern1(
client,
_m(acc, "supply_in_loss_rel_to_circulating_supply"),
),
supplyInLossRelToOwnSupply: createMetricPattern1(
client,
_m(acc, "supply_in_loss_rel_to_own_supply"),
),
supplyInProfitRelToCirculatingSupply: createMetricPattern1(
client,
_m(acc, "supply_in_profit_rel_to_circulating_supply"),
),
supplyInProfitRelToOwnSupply: createMetricPattern1(
client,
_m(acc, "supply_in_profit_rel_to_own_supply"),
),
supplyRelToCirculatingSupply: createMetricPattern4(
client,
_m(acc, "supply_rel_to_circulating_supply"),
),
unrealizedLossRelToMarketCap: createMetricPattern1(
client,
_m(acc, "unrealized_loss_rel_to_market_cap"),
),
unrealizedProfitRelToMarketCap: createMetricPattern1(
client,
_m(acc, "unrealized_profit_rel_to_market_cap"),
),
};
}
/** /**
* @template T * @template T
* @typedef {Object} CountPattern2 * @typedef {Object} CountPattern2
@@ -3588,41 +3588,6 @@ function createAddrCountPattern(client, acc) {
}; };
} }
/**
* @template T
* @typedef {Object} FeeRatePattern
* @property {MetricPattern1<T>} average
* @property {MetricPattern1<T>} max
* @property {MetricPattern11<T>} median
* @property {MetricPattern1<T>} min
* @property {MetricPattern11<T>} pct10
* @property {MetricPattern11<T>} pct25
* @property {MetricPattern11<T>} pct75
* @property {MetricPattern11<T>} pct90
* @property {MetricPattern27<T>} txindex
*/
/**
* Create a FeeRatePattern pattern node
* @template T
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {FeeRatePattern<T>}
*/
function createFeeRatePattern(client, acc) {
return {
average: createMetricPattern1(client, _m(acc, "average")),
max: createMetricPattern1(client, _m(acc, "max")),
median: createMetricPattern11(client, _m(acc, "median")),
min: createMetricPattern1(client, _m(acc, "min")),
pct10: createMetricPattern11(client, _m(acc, "pct10")),
pct25: createMetricPattern11(client, _m(acc, "pct25")),
pct75: createMetricPattern11(client, _m(acc, "pct75")),
pct90: createMetricPattern11(client, _m(acc, "pct90")),
txindex: createMetricPattern27(client, acc),
};
}
/** /**
* @template T * @template T
* @typedef {Object} FullnessPattern * @typedef {Object} FullnessPattern
@@ -3658,6 +3623,41 @@ function createFullnessPattern(client, acc) {
}; };
} }
/**
* @template T
* @typedef {Object} FeeRatePattern
* @property {MetricPattern1<T>} average
* @property {MetricPattern1<T>} max
* @property {MetricPattern11<T>} median
* @property {MetricPattern1<T>} min
* @property {MetricPattern11<T>} pct10
* @property {MetricPattern11<T>} pct25
* @property {MetricPattern11<T>} pct75
* @property {MetricPattern11<T>} pct90
* @property {MetricPattern27<T>} txindex
*/
/**
* Create a FeeRatePattern pattern node
* @template T
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {FeeRatePattern<T>}
*/
function createFeeRatePattern(client, acc) {
return {
average: createMetricPattern1(client, _m(acc, "average")),
max: createMetricPattern1(client, _m(acc, "max")),
median: createMetricPattern11(client, _m(acc, "median")),
min: createMetricPattern1(client, _m(acc, "min")),
pct10: createMetricPattern11(client, _m(acc, "pct10")),
pct25: createMetricPattern11(client, _m(acc, "pct25")),
pct75: createMetricPattern11(client, _m(acc, "pct75")),
pct90: createMetricPattern11(client, _m(acc, "pct90")),
txindex: createMetricPattern27(client, acc),
};
}
/** /**
* @typedef {Object} _0satsPattern * @typedef {Object} _0satsPattern
* @property {ActivityPattern2} activity * @property {ActivityPattern2} activity
@@ -3689,6 +3689,50 @@ function create_0satsPattern(client, acc) {
}; };
} }
/**
* @typedef {Object} UnrealizedPattern
* @property {MetricPattern1<Dollars>} negUnrealizedLoss
* @property {MetricPattern1<Dollars>} netUnrealizedPnl
* @property {ActiveSupplyPattern} supplyInLoss
* @property {ActiveSupplyPattern} supplyInProfit
* @property {MetricPattern1<Dollars>} totalUnrealizedPnl
* @property {MetricPattern1<Dollars>} unrealizedLoss
* @property {MetricPattern1<Dollars>} unrealizedProfit
*/
/**
* Create a UnrealizedPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {UnrealizedPattern}
*/
function createUnrealizedPattern(client, acc) {
return {
negUnrealizedLoss: createMetricPattern1(
client,
_m(acc, "neg_unrealized_loss"),
),
netUnrealizedPnl: createMetricPattern1(
client,
_m(acc, "net_unrealized_pnl"),
),
supplyInLoss: createActiveSupplyPattern(client, _m(acc, "supply_in_loss")),
supplyInProfit: createActiveSupplyPattern(
client,
_m(acc, "supply_in_profit"),
),
totalUnrealizedPnl: createMetricPattern1(
client,
_m(acc, "total_unrealized_pnl"),
),
unrealizedLoss: createMetricPattern1(client, _m(acc, "unrealized_loss")),
unrealizedProfit: createMetricPattern1(
client,
_m(acc, "unrealized_profit"),
),
};
}
/** /**
* @typedef {Object} _100btcPattern * @typedef {Object} _100btcPattern
* @property {ActivityPattern2} activity * @property {ActivityPattern2} activity
@@ -3719,29 +3763,29 @@ function create_100btcPattern(client, acc) {
} }
/** /**
* @typedef {Object} _10yTo12yPattern * @typedef {Object} _10yPattern
* @property {ActivityPattern2} activity * @property {ActivityPattern2} activity
* @property {CostBasisPattern2} costBasis * @property {CostBasisPattern} costBasis
* @property {OutputsPattern} outputs * @property {OutputsPattern} outputs
* @property {RealizedPattern2} realized * @property {RealizedPattern4} realized
* @property {RelativePattern2} relative * @property {RelativePattern} relative
* @property {SupplyPattern2} supply * @property {SupplyPattern2} supply
* @property {UnrealizedPattern} unrealized * @property {UnrealizedPattern} unrealized
*/ */
/** /**
* Create a _10yTo12yPattern pattern node * Create a _10yPattern pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name * @param {string} acc - Accumulated metric name
* @returns {_10yTo12yPattern} * @returns {_10yPattern}
*/ */
function create_10yTo12yPattern(client, acc) { function create_10yPattern(client, acc) {
return { return {
activity: createActivityPattern2(client, acc), activity: createActivityPattern2(client, acc),
costBasis: createCostBasisPattern2(client, acc), costBasis: createCostBasisPattern(client, acc),
outputs: createOutputsPattern(client, _m(acc, "utxo_count")), outputs: createOutputsPattern(client, _m(acc, "utxo_count")),
realized: createRealizedPattern2(client, acc), realized: createRealizedPattern4(client, acc),
relative: createRelativePattern2(client, acc), relative: createRelativePattern(client, acc),
supply: createSupplyPattern2(client, _m(acc, "supply")), supply: createSupplyPattern2(client, _m(acc, "supply")),
unrealized: createUnrealizedPattern(client, acc), unrealized: createUnrealizedPattern(client, acc),
}; };
@@ -3806,73 +3850,29 @@ function create_0satsPattern2(client, acc) {
} }
/** /**
* @typedef {Object} UnrealizedPattern * @typedef {Object} _10yTo12yPattern
* @property {MetricPattern1<Dollars>} negUnrealizedLoss
* @property {MetricPattern1<Dollars>} netUnrealizedPnl
* @property {ActiveSupplyPattern} supplyInLoss
* @property {ActiveSupplyPattern} supplyInProfit
* @property {MetricPattern1<Dollars>} totalUnrealizedPnl
* @property {MetricPattern1<Dollars>} unrealizedLoss
* @property {MetricPattern1<Dollars>} unrealizedProfit
*/
/**
* Create a UnrealizedPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {UnrealizedPattern}
*/
function createUnrealizedPattern(client, acc) {
return {
negUnrealizedLoss: createMetricPattern1(
client,
_m(acc, "neg_unrealized_loss"),
),
netUnrealizedPnl: createMetricPattern1(
client,
_m(acc, "net_unrealized_pnl"),
),
supplyInLoss: createActiveSupplyPattern(client, _m(acc, "supply_in_loss")),
supplyInProfit: createActiveSupplyPattern(
client,
_m(acc, "supply_in_profit"),
),
totalUnrealizedPnl: createMetricPattern1(
client,
_m(acc, "total_unrealized_pnl"),
),
unrealizedLoss: createMetricPattern1(client, _m(acc, "unrealized_loss")),
unrealizedProfit: createMetricPattern1(
client,
_m(acc, "unrealized_profit"),
),
};
}
/**
* @typedef {Object} _10yPattern
* @property {ActivityPattern2} activity * @property {ActivityPattern2} activity
* @property {CostBasisPattern} costBasis * @property {CostBasisPattern2} costBasis
* @property {OutputsPattern} outputs * @property {OutputsPattern} outputs
* @property {RealizedPattern4} realized * @property {RealizedPattern2} realized
* @property {RelativePattern} relative * @property {RelativePattern2} relative
* @property {SupplyPattern2} supply * @property {SupplyPattern2} supply
* @property {UnrealizedPattern} unrealized * @property {UnrealizedPattern} unrealized
*/ */
/** /**
* Create a _10yPattern pattern node * Create a _10yTo12yPattern pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name * @param {string} acc - Accumulated metric name
* @returns {_10yPattern} * @returns {_10yTo12yPattern}
*/ */
function create_10yPattern(client, acc) { function create_10yTo12yPattern(client, acc) {
return { return {
activity: createActivityPattern2(client, acc), activity: createActivityPattern2(client, acc),
costBasis: createCostBasisPattern(client, acc), costBasis: createCostBasisPattern2(client, acc),
outputs: createOutputsPattern(client, _m(acc, "utxo_count")), outputs: createOutputsPattern(client, _m(acc, "utxo_count")),
realized: createRealizedPattern4(client, acc), realized: createRealizedPattern2(client, acc),
relative: createRelativePattern(client, acc), relative: createRelativePattern2(client, acc),
supply: createSupplyPattern2(client, _m(acc, "supply")), supply: createSupplyPattern2(client, _m(acc, "supply")),
unrealized: createUnrealizedPattern(client, acc), unrealized: createUnrealizedPattern(client, acc),
}; };
@@ -3940,69 +3940,6 @@ function createSplitPattern2(client, acc) {
}; };
} }
/**
* @typedef {Object} ActiveSupplyPattern
* @property {MetricPattern1<Bitcoin>} bitcoin
* @property {MetricPattern1<Dollars>} dollars
* @property {MetricPattern1<Sats>} sats
*/
/**
* Create a ActiveSupplyPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {ActiveSupplyPattern}
*/
function createActiveSupplyPattern(client, acc) {
return {
bitcoin: createMetricPattern1(client, _m(acc, "btc")),
dollars: createMetricPattern1(client, _m(acc, "usd")),
sats: createMetricPattern1(client, acc),
};
}
/**
* @typedef {Object} CoinbasePattern
* @property {BitcoinPattern} bitcoin
* @property {DollarsPattern<Dollars>} dollars
* @property {DollarsPattern<Sats>} 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} CoinbasePattern2
* @property {BlockCountPattern<Bitcoin>} bitcoin
* @property {BlockCountPattern<Dollars>} dollars
* @property {BlockCountPattern<Sats>} sats
*/
/**
* Create a CoinbasePattern2 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {CoinbasePattern2}
*/
function createCoinbasePattern2(client, acc) {
return {
bitcoin: createBlockCountPattern(client, _m(acc, "btc")),
dollars: createBlockCountPattern(client, _m(acc, "usd")),
sats: createBlockCountPattern(client, acc),
};
}
/** /**
* @typedef {Object} SegwitAdoptionPattern * @typedef {Object} SegwitAdoptionPattern
* @property {MetricPattern11<StoredF32>} base * @property {MetricPattern11<StoredF32>} base
@@ -4045,6 +3982,27 @@ function createCostBasisPattern2(client, acc) {
}; };
} }
/**
* @typedef {Object} ActiveSupplyPattern
* @property {MetricPattern1<Bitcoin>} bitcoin
* @property {MetricPattern1<Dollars>} dollars
* @property {MetricPattern1<Sats>} sats
*/
/**
* Create a ActiveSupplyPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {ActiveSupplyPattern}
*/
function createActiveSupplyPattern(client, acc) {
return {
bitcoin: createMetricPattern1(client, _m(acc, "btc")),
dollars: createMetricPattern1(client, _m(acc, "usd")),
sats: createMetricPattern1(client, acc),
};
}
/** /**
* @typedef {Object} UnclaimedRewardsPattern * @typedef {Object} UnclaimedRewardsPattern
* @property {BitcoinPattern2<Bitcoin>} bitcoin * @property {BitcoinPattern2<Bitcoin>} bitcoin
@@ -4088,21 +4046,44 @@ function create_2015Pattern(client, acc) {
} }
/** /**
* @typedef {Object} _1dReturns1mSdPattern * @typedef {Object} CoinbasePattern
* @property {MetricPattern4<StoredF32>} sd * @property {BitcoinPattern} bitcoin
* @property {MetricPattern4<StoredF32>} sma * @property {DollarsPattern<Dollars>} dollars
* @property {DollarsPattern<Sats>} sats
*/ */
/** /**
* Create a _1dReturns1mSdPattern pattern node * Create a CoinbasePattern pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name * @param {string} acc - Accumulated metric name
* @returns {_1dReturns1mSdPattern} * @returns {CoinbasePattern}
*/ */
function create_1dReturns1mSdPattern(client, acc) { function createCoinbasePattern(client, acc) {
return { return {
sd: createMetricPattern4(client, _m(acc, "sd")), bitcoin: createBitcoinPattern(client, _m(acc, "btc")),
sma: createMetricPattern4(client, _m(acc, "sma")), dollars: createDollarsPattern(client, _m(acc, "usd")),
sats: createDollarsPattern(client, acc),
};
}
/**
* @typedef {Object} CoinbasePattern2
* @property {BlockCountPattern<Bitcoin>} bitcoin
* @property {BlockCountPattern<Dollars>} dollars
* @property {BlockCountPattern<Sats>} sats
*/
/**
* Create a CoinbasePattern2 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {CoinbasePattern2}
*/
function createCoinbasePattern2(client, acc) {
return {
bitcoin: createBlockCountPattern(client, _m(acc, "btc")),
dollars: createBlockCountPattern(client, _m(acc, "usd")),
sats: createBlockCountPattern(client, acc),
}; };
} }
@@ -4131,6 +4112,44 @@ function createRelativePattern4(client, acc) {
}; };
} }
/**
* @typedef {Object} CostBasisPattern
* @property {MetricPattern1<Dollars>} max
* @property {MetricPattern1<Dollars>} min
*/
/**
* Create a CostBasisPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {CostBasisPattern}
*/
function createCostBasisPattern(client, acc) {
return {
max: createMetricPattern1(client, _m(acc, "max_cost_basis")),
min: createMetricPattern1(client, _m(acc, "min_cost_basis")),
};
}
/**
* @typedef {Object} _1dReturns1mSdPattern
* @property {MetricPattern4<StoredF32>} sd
* @property {MetricPattern4<StoredF32>} sma
*/
/**
* Create a _1dReturns1mSdPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {_1dReturns1mSdPattern}
*/
function create_1dReturns1mSdPattern(client, acc) {
return {
sd: createMetricPattern4(client, _m(acc, "sd")),
sma: createMetricPattern4(client, _m(acc, "sma")),
};
}
/** /**
* @typedef {Object} SupplyPattern2 * @typedef {Object} SupplyPattern2
* @property {ActiveSupplyPattern} halved * @property {ActiveSupplyPattern} halved
@@ -4151,21 +4170,23 @@ function createSupplyPattern2(client, acc) {
} }
/** /**
* @typedef {Object} CostBasisPattern * @template T
* @property {MetricPattern1<Dollars>} max * @typedef {Object} SatsPattern
* @property {MetricPattern1<Dollars>} min * @property {MetricPattern1<T>} ohlc
* @property {SplitPattern2<T>} split
*/ */
/** /**
* Create a CostBasisPattern pattern node * Create a SatsPattern pattern node
* @template T
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name * @param {string} acc - Accumulated metric name
* @returns {CostBasisPattern} * @returns {SatsPattern<T>}
*/ */
function createCostBasisPattern(client, acc) { function createSatsPattern(client, acc) {
return { return {
max: createMetricPattern1(client, _m(acc, "max_cost_basis")), ohlc: createMetricPattern1(client, _m(acc, "ohlc_sats")),
min: createMetricPattern1(client, _m(acc, "min_cost_basis")), split: createSplitPattern2(client, _m(acc, "sats")),
}; };
} }
@@ -4211,27 +4232,6 @@ function createBitcoinPattern2(client, acc) {
}; };
} }
/**
* @template T
* @typedef {Object} SatsPattern
* @property {MetricPattern1<T>} ohlc
* @property {SplitPattern2<T>} split
*/
/**
* Create a SatsPattern pattern node
* @template T
* @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name
* @returns {SatsPattern<T>}
*/
function createSatsPattern(client, acc) {
return {
ohlc: createMetricPattern1(client, _m(acc, "ohlc_sats")),
split: createSplitPattern2(client, _m(acc, "sats")),
};
}
/** /**
* @typedef {Object} RealizedPriceExtraPattern * @typedef {Object} RealizedPriceExtraPattern
* @property {MetricPattern4<StoredF32>} ratio * @property {MetricPattern4<StoredF32>} ratio
@@ -4628,8 +4628,8 @@ function createOutputsPattern(client, acc) {
/** /**
* @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All
* @property {ActivityPattern2} activity * @property {MetricsTree_Distribution_UtxoCohorts_All_Activity} activity
* @property {CostBasisPattern2} costBasis * @property {MetricsTree_Distribution_UtxoCohorts_All_CostBasis} costBasis
* @property {OutputsPattern} outputs * @property {OutputsPattern} outputs
* @property {RealizedPattern3} realized * @property {RealizedPattern3} realized
* @property {MetricsTree_Distribution_UtxoCohorts_All_Relative} relative * @property {MetricsTree_Distribution_UtxoCohorts_All_Relative} relative
@@ -4637,6 +4637,22 @@ function createOutputsPattern(client, acc) {
* @property {UnrealizedPattern} unrealized * @property {UnrealizedPattern} unrealized
*/ */
/**
* @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All_Activity
* @property {BlockCountPattern<StoredF64>} coinblocksDestroyed
* @property {BlockCountPattern<StoredF64>} coindaysDestroyed
* @property {MetricPattern11<Sats>} satblocksDestroyed
* @property {MetricPattern11<Sats>} satdaysDestroyed
* @property {UnclaimedRewardsPattern} sent
*/
/**
* @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All_CostBasis
* @property {MetricPattern1<Dollars>} max
* @property {MetricPattern1<Dollars>} min
* @property {PercentilesPattern} percentiles
*/
/** /**
* @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All_Relative * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All_Relative
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToOwnTotalUnrealizedPnl * @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToOwnTotalUnrealizedPnl
@@ -5035,7 +5051,7 @@ function createOutputsPattern(client, acc) {
* @property {MetricsTree_Market_Ath} ath * @property {MetricsTree_Market_Ath} ath
* @property {MetricsTree_Market_Dca} dca * @property {MetricsTree_Market_Dca} dca
* @property {MetricsTree_Market_Indicators} indicators * @property {MetricsTree_Market_Indicators} indicators
* @property {MetricsTree_Market_Lookback} lookback * @property {LookbackPattern<Dollars>} lookback
* @property {MetricsTree_Market_MovingAverage} movingAverage * @property {MetricsTree_Market_MovingAverage} movingAverage
* @property {MetricsTree_Market_Range} range * @property {MetricsTree_Market_Range} range
* @property {MetricsTree_Market_Returns} returns * @property {MetricsTree_Market_Returns} returns
@@ -5102,11 +5118,6 @@ function createOutputsPattern(client, acc) {
* @property {MetricPattern6<StoredF32>} stochRsiK * @property {MetricPattern6<StoredF32>} stochRsiK
*/ */
/**
* @typedef {Object} MetricsTree_Market_Lookback
* @property {PriceAgoPattern<Dollars>} priceAgo
*/
/** /**
* @typedef {Object} MetricsTree_Market_MovingAverage * @typedef {Object} MetricsTree_Market_MovingAverage
* @property {Price111dSmaPattern} price111dSma * @property {Price111dSmaPattern} price111dSma
@@ -5171,7 +5182,24 @@ function createOutputsPattern(client, acc) {
* @property {_1dReturns1mSdPattern} downside1wSd * @property {_1dReturns1mSdPattern} downside1wSd
* @property {_1dReturns1mSdPattern} downside1ySd * @property {_1dReturns1mSdPattern} downside1ySd
* @property {MetricPattern6<StoredF32>} downsideReturns * @property {MetricPattern6<StoredF32>} downsideReturns
* @property {PriceAgoPattern<StoredF32>} priceReturns * @property {MetricsTree_Market_Returns_PriceReturns} priceReturns
*/
/**
* @typedef {Object} MetricsTree_Market_Returns_PriceReturns
* @property {MetricPattern4<StoredF32>} _10y
* @property {MetricPattern4<StoredF32>} _1d
* @property {MetricPattern4<StoredF32>} _1m
* @property {MetricPattern4<StoredF32>} _1w
* @property {MetricPattern4<StoredF32>} _1y
* @property {MetricPattern4<StoredF32>} _2y
* @property {MetricPattern4<StoredF32>} _3m
* @property {MetricPattern4<StoredF32>} _3y
* @property {MetricPattern4<StoredF32>} _4y
* @property {MetricPattern4<StoredF32>} _5y
* @property {MetricPattern4<StoredF32>} _6m
* @property {MetricPattern4<StoredF32>} _6y
* @property {MetricPattern4<StoredF32>} _8y
*/ */
/** /**
@@ -7334,9 +7362,7 @@ class BrkClient extends BrkClientBase {
stochRsiD: createMetricPattern6(this, "stoch_rsi_d"), stochRsiD: createMetricPattern6(this, "stoch_rsi_d"),
stochRsiK: createMetricPattern6(this, "stoch_rsi_k"), stochRsiK: createMetricPattern6(this, "stoch_rsi_k"),
}, },
lookback: { lookback: createLookbackPattern(this, "price"),
priceAgo: createPriceAgoPattern(this, "price"),
},
movingAverage: { movingAverage: {
price111dSma: createPrice111dSmaPattern(this, "price_111d_sma"), price111dSma: createPrice111dSmaPattern(this, "price_111d_sma"),
price12dEma: createPrice111dSmaPattern(this, "price_12d_ema"), price12dEma: createPrice111dSmaPattern(this, "price_12d_ema"),
@@ -7402,7 +7428,21 @@ class BrkClient extends BrkClientBase {
downside1wSd: create_1dReturns1mSdPattern(this, "downside_1w_sd"), downside1wSd: create_1dReturns1mSdPattern(this, "downside_1w_sd"),
downside1ySd: create_1dReturns1mSdPattern(this, "downside_1y_sd"), downside1ySd: create_1dReturns1mSdPattern(this, "downside_1y_sd"),
downsideReturns: createMetricPattern6(this, "downside_returns"), downsideReturns: createMetricPattern6(this, "downside_returns"),
priceReturns: createPriceAgoPattern(this, "price_returns"), priceReturns: {
_10y: createMetricPattern4(this, "10y_price_returns"),
_1d: createMetricPattern4(this, "1d_price_returns"),
_1m: createMetricPattern4(this, "1m_price_returns"),
_1w: createMetricPattern4(this, "1w_price_returns"),
_1y: createMetricPattern4(this, "1y_price_returns"),
_2y: createMetricPattern4(this, "2y_price_returns"),
_3m: createMetricPattern4(this, "3m_price_returns"),
_3y: createMetricPattern4(this, "3y_price_returns"),
_4y: createMetricPattern4(this, "4y_price_returns"),
_5y: createMetricPattern4(this, "5y_price_returns"),
_6m: createMetricPattern4(this, "6m_price_returns"),
_6y: createMetricPattern4(this, "6y_price_returns"),
_8y: createMetricPattern4(this, "8y_price_returns"),
},
}, },
volatility: { volatility: {
price1mVolatility: createMetricPattern4(this, "price_1m_volatility"), price1mVolatility: createMetricPattern4(this, "price_1m_volatility"),
@@ -7618,7 +7658,7 @@ class BrkClient extends BrkClientBase {
}, },
oracle: { oracle: {
ohlcCents: createMetricPattern6(this, "oracle_ohlc_cents"), ohlcCents: createMetricPattern6(this, "oracle_ohlc_cents"),
ohlcDollars: createMetricPattern6(this, "oracle_ohlc_dollars"), ohlcDollars: createMetricPattern6(this, "oracle_ohlc"),
priceCents: createMetricPattern11(this, "orange_price_cents"), priceCents: createMetricPattern11(this, "orange_price_cents"),
txCount: createMetricPattern6(this, "oracle_tx_count"), txCount: createMetricPattern6(this, "oracle_tx_count"),
}, },
File diff suppressed because it is too large Load Diff
+42 -45
View File
@@ -1,14 +1,27 @@
# Run:
# uv run pytest tests/tree.py -s
"""Comprehensive test that fetches all endpoints in the tree.""" """Comprehensive test that fetches all endpoints in the tree."""
from brk_client import BrkClient from brk_client import BrkClient
def is_metric_pattern(obj):
"""Check if an object is a metric pattern (has indexes() method and by attribute)."""
return (
hasattr(obj, "indexes")
and callable(getattr(obj, "indexes", None))
and hasattr(obj, "by")
)
def get_all_metrics(obj, path=""): def get_all_metrics(obj, path=""):
"""Recursively collect all MetricPattern instances from the tree.""" """Recursively collect all MetricPattern instances from the tree."""
metrics = [] metrics = []
for attr_name in dir(obj): for attr_name in dir(obj):
if attr_name.startswith("_"): # Skip dunder methods and internal attributes like _client
if attr_name.startswith("__") or attr_name == "_client":
continue continue
try: try:
@@ -16,74 +29,58 @@ def get_all_metrics(obj, path=""):
except Exception: except Exception:
continue continue
if attr is None or callable(attr):
continue
current_path = f"{path}.{attr_name}" if path else attr_name current_path = f"{path}.{attr_name}" if path else attr_name
# Check if this is a metric pattern (has 'by' attribute with index methods) # Check if this is a metric pattern using the indexes() method
if hasattr(attr, "by"): if is_metric_pattern(attr):
by = attr.by metrics.append((current_path, attr))
indexes = []
for idx_name in dir(by):
if not idx_name.startswith("_") and callable(
getattr(by, idx_name, None)
):
indexes.append(idx_name)
if indexes:
metrics.append((current_path, attr, indexes))
# Recurse into nested tree nodes # Recurse into nested tree nodes
if hasattr(attr, "__dict__") and not callable(attr): if hasattr(attr, "__dict__"):
metrics.extend(get_all_metrics(attr, current_path)) metrics.extend(get_all_metrics(attr, current_path))
return metrics return metrics
def test_all_endpoints(): def test_all_endpoints():
"""Test fetching last 3 values from all metric endpoints.""" """Test fetching last value from all metric endpoints."""
client = BrkClient("http://localhost:3110") client = BrkClient("http://localhost:3110")
metrics = get_all_metrics(client.metrics) metrics = get_all_metrics(client.metrics)
print(f"\nFound {len(metrics)} metrics") print(f"\nFound {len(metrics)} metrics")
success = 0 success = 0
failed = 0
errors = []
for path, metric, indexes in metrics: for path, metric in metrics:
# Use the indexes() method to get all available indexes
indexes = metric.indexes()
for idx_name in indexes: for idx_name in indexes:
full_path = f"{path}.by.{idx_name}"
try: try:
# Verify both access methods work: .by.index() and .get(index)
by = metric.by by = metric.by
endpoint = getattr(by, idx_name)() endpoint_by_property = getattr(by, idx_name)()
# Use the new idiomatic API: tail(3).fetch() or [-3:].fetch() endpoint_by_get = metric.get(idx_name)
res = endpoint.tail(3).fetch()
count = len(res["data"]) if endpoint_by_property is None:
if count != 3: raise Exception(f"metric.by.{idx_name}() returned None")
failed += 1 if endpoint_by_get is None:
error_msg = ( raise Exception(f"metric.get('{idx_name}') returned None")
f"FAIL: {path}.by.{idx_name}() -> expected 3, got {count}"
) endpoint_by_property.tail(1).fetch()
errors.append(error_msg) success += 1
print(error_msg) print(f"OK: {full_path}")
else:
success += 1
print(f"OK: {path}.by.{idx_name}() -> {count} items")
except Exception as e: except Exception as e:
failed += 1 print(f"FAIL: {full_path} -> {e}")
error_msg = f"FAIL: {path}.by.{idx_name}() -> {e}" return
errors.append(error_msg)
print(error_msg)
print("\n=== Results ===") print("\n=== Results ===")
print(f"Success: {success}") print(f"Success: {success}")
print(f"Failed: {failed}")
if errors:
print("\nErrors:")
for err in errors[:10]: # Show first 10 errors
print(f" {err}")
if len(errors) > 10:
print(f" ... and {len(errors) - 10} more")
assert failed == 0, f"{failed} endpoints failed"
if __name__ == "__main__": if __name__ == "__main__":