mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
clients: snapshot
This commit is contained in:
@@ -120,6 +120,9 @@ pub struct PatternBaseResult {
|
||||
/// Whether an outlier child was excluded to find the pattern.
|
||||
/// If true, pattern factory should not be used.
|
||||
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.
|
||||
@@ -137,12 +140,17 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
return PatternBaseResult {
|
||||
base: String::new(),
|
||||
has_outlier: false,
|
||||
is_suffix_mode: true, // default
|
||||
};
|
||||
}
|
||||
|
||||
// Try to find common base from leaf names
|
||||
if let Some((base, has_outlier)) = try_find_base(&child_names, false) {
|
||||
return PatternBaseResult { base, has_outlier };
|
||||
if let Some(result) = try_find_base(&child_names, false) {
|
||||
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
|
||||
@@ -155,10 +163,11 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
.map(|(_, v)| v.clone())
|
||||
.collect();
|
||||
|
||||
if let Some((base, _)) = try_find_base(&filtered, true) {
|
||||
if let Some(result) = try_find_base(&filtered, true) {
|
||||
return PatternBaseResult {
|
||||
base,
|
||||
base: result.base,
|
||||
has_outlier: true,
|
||||
is_suffix_mode: result.is_suffix_mode,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -169,24 +178,40 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
PatternBaseResult {
|
||||
base: String::new(),
|
||||
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.
|
||||
/// Returns Some((base, has_outlier)) if found.
|
||||
fn try_find_base(child_names: &[(String, String)], is_outlier_attempt: bool) -> Option<(String, bool)> {
|
||||
/// Returns Some(FindBaseResult) if found.
|
||||
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();
|
||||
|
||||
// Try common prefix first (suffix mode)
|
||||
if let Some(prefix) = find_common_prefix(&leaf_names) {
|
||||
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)
|
||||
if let Some(suffix) = find_common_suffix(&leaf_names) {
|
||||
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
|
||||
@@ -409,4 +434,64 @@ mod tests {
|
||||
assert_eq!(result.base, "sopr");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,12 +55,17 @@ pub fn prepare_tree_node<'a>(
|
||||
.map(|(f, _)| f.clone())
|
||||
.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 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)
|
||||
&& pattern_name != name
|
||||
&& metadata.is_parameterizable(pattern_name)
|
||||
&& !base_result.has_outlier
|
||||
&& mode_matches
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -84,9 +89,16 @@ pub fn prepare_tree_node<'a>(
|
||||
.as_ref()
|
||||
.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
|
||||
// We inline only if it's a branch AND doesn't match any pattern
|
||||
let should_inline = !is_leaf && !matches_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 || !mode_matches || base_result.has_outlier);
|
||||
|
||||
// Inline type name (only used when should_inline is true)
|
||||
let inline_type_name = if should_inline {
|
||||
|
||||
@@ -6,9 +6,8 @@ use std::fmt::Write;
|
||||
use brk_types::TreeNode;
|
||||
|
||||
use crate::{
|
||||
ClientMetadata, Endpoint, GenericSyntax, JavaScriptSyntax, PatternField,
|
||||
generate_leaf_field, get_first_leaf_name, get_node_fields, get_pattern_instance_base,
|
||||
infer_accumulated_name, prepare_tree_node, to_camel_case,
|
||||
ClientMetadata, Endpoint, GenericSyntax, JavaScriptSyntax, PatternField, generate_leaf_field,
|
||||
prepare_tree_node, to_camel_case,
|
||||
};
|
||||
|
||||
use super::api::generate_api_methods;
|
||||
@@ -121,15 +120,36 @@ pub fn generate_main_client(
|
||||
writeln!(output, " */").unwrap();
|
||||
writeln!(output, " _buildTree(basePath) {{").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, " }}\n").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, " * 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,
|
||||
" * 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, " * @param {{string}} metric - The metric name").unwrap();
|
||||
writeln!(output, " * @param {{Index}} index - The index name").unwrap();
|
||||
@@ -149,66 +169,55 @@ pub fn generate_main_client(
|
||||
fn generate_tree_initializer(
|
||||
output: &mut String,
|
||||
node: &TreeNode,
|
||||
accumulated_name: &str,
|
||||
name: &str,
|
||||
indent: usize,
|
||||
pattern_lookup: &std::collections::HashMap<Vec<PatternField>, String>,
|
||||
metadata: &ClientMetadata,
|
||||
generated: &mut HashSet<String>,
|
||||
) {
|
||||
let indent_str = " ".repeat(indent);
|
||||
|
||||
let Some(ctx) = prepare_tree_node(node, name, pattern_lookup, metadata, generated) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let syntax = JavaScriptSyntax;
|
||||
if let TreeNode::Branch(children) = node {
|
||||
for (child_name, child_node) in children.iter() {
|
||||
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);
|
||||
for child in &ctx.children {
|
||||
let field_name = to_camel_case(child.name);
|
||||
|
||||
let base_result = get_pattern_instance_base(child_node);
|
||||
|
||||
// Use pattern factory only if no outlier was detected
|
||||
if let Some(pattern_name) = pattern_name.filter(|_| !base_result.has_outlier) {
|
||||
writeln!(
|
||||
output,
|
||||
"{}{}: create{}(this, '{}'),",
|
||||
indent_str, field_name, pattern_name, base_result.base
|
||||
)
|
||||
.unwrap();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
if child.is_leaf {
|
||||
if let TreeNode::Leaf(leaf) = child.node {
|
||||
generate_leaf_field(
|
||||
output,
|
||||
&syntax,
|
||||
"this",
|
||||
child.name,
|
||||
leaf,
|
||||
metadata,
|
||||
&indent_str,
|
||||
);
|
||||
}
|
||||
} 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();
|
||||
for index in &pattern.indexes {
|
||||
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!(
|
||||
output,
|
||||
" 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, " Self {{").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();
|
||||
@@ -436,7 +446,12 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
|
||||
writeln!(output, "}}\n").unwrap();
|
||||
|
||||
// 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, " &self.name").unwrap();
|
||||
writeln!(output, " }}").unwrap();
|
||||
@@ -451,12 +466,26 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern
|
||||
writeln!(output, "}}\n").unwrap();
|
||||
|
||||
// Implement MetricPattern<T> trait
|
||||
writeln!(output, "impl<T: DeserializeOwned> MetricPattern<T> for {}<T> {{", pattern.name).unwrap();
|
||||
writeln!(output, " fn get(&self, index: Index) -> Option<MetricEndpointBuilder<T>> {{").unwrap();
|
||||
writeln!(
|
||||
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();
|
||||
for index in &pattern.indexes {
|
||||
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, " }}").unwrap();
|
||||
@@ -486,8 +515,12 @@ pub fn generate_pattern_structs(
|
||||
|
||||
for field in &pattern.fields {
|
||||
let field_name = to_snake_case(&field.name);
|
||||
let type_annotation =
|
||||
metadata.field_type_annotation(field, pattern.is_generic, None, GenericSyntax::RUST);
|
||||
let type_annotation = metadata.field_type_annotation(
|
||||
field,
|
||||
pattern.is_generic,
|
||||
None,
|
||||
GenericSyntax::RUST,
|
||||
);
|
||||
writeln!(output, " pub {}: {},", field_name, type_annotation).unwrap();
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,14 @@ impl ClientMetadata {
|
||||
|| 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.
|
||||
/// If the field matches ANY pattern (parameterizable or not), returns pattern type.
|
||||
/// Otherwise returns the inline type name (parent_child format).
|
||||
|
||||
@@ -52,40 +52,27 @@ fn main() -> brk_client::Result<()> {
|
||||
println!("\nFound {} metrics", metrics.len());
|
||||
|
||||
let mut success = 0;
|
||||
let mut failed = 0;
|
||||
let mut errors: Vec<String> = Vec::new();
|
||||
|
||||
for metric in &metrics {
|
||||
for index in &metric.indexes {
|
||||
let index_str = index.serialize_long();
|
||||
let full_path = format!("{}.by.{}", metric.path, index_str);
|
||||
|
||||
match client.get_metric(
|
||||
metric.name.as_str().into(),
|
||||
*index,
|
||||
None,
|
||||
Some(0),
|
||||
None,
|
||||
Some("-3"),
|
||||
None,
|
||||
) {
|
||||
Ok(response) => {
|
||||
let count = response.json().data.len();
|
||||
if count != 3 {
|
||||
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);
|
||||
}
|
||||
Ok(_) => {
|
||||
success += 1;
|
||||
println!("OK: {}", full_path);
|
||||
}
|
||||
Err(e) => {
|
||||
failed += 1;
|
||||
let error_msg = format!("FAIL: {}.by.{} -> {}", metric.path, index_str, e);
|
||||
errors.push(error_msg.clone());
|
||||
println!("{}", error_msg);
|
||||
println!("FAIL: {} -> {}", full_path, e);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,21 +80,6 @@ fn main() -> brk_client::Result<()> {
|
||||
|
||||
println!("\n=== Results ===");
|
||||
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(())
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3155,7 +3155,7 @@ function createAaopoolPattern(client, acc) {
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} PriceAgoPattern
|
||||
* @typedef {Object} LookbackPattern
|
||||
* @property {MetricPattern4<T>} _10y
|
||||
* @property {MetricPattern4<T>} _1d
|
||||
* @property {MetricPattern4<T>} _1m
|
||||
@@ -3172,13 +3172,13 @@ function createAaopoolPattern(client, acc) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a PriceAgoPattern pattern node
|
||||
* Create a LookbackPattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {PriceAgoPattern<T>}
|
||||
* @returns {LookbackPattern<T>}
|
||||
*/
|
||||
function createPriceAgoPattern(client, acc) {
|
||||
function createLookbackPattern(client, acc) {
|
||||
return {
|
||||
_10y: createMetricPattern4(client, _m(acc, "10y_ago")),
|
||||
_1d: createMetricPattern4(client, _m(acc, "1d_ago")),
|
||||
@@ -3338,17 +3338,17 @@ function createBitcoinPattern(client, acc) {
|
||||
*/
|
||||
function createClassAveragePricePattern(client, acc) {
|
||||
return {
|
||||
_2015: createMetricPattern4(client, _m(acc, "2015_returns")),
|
||||
_2016: createMetricPattern4(client, _m(acc, "2016_returns")),
|
||||
_2017: createMetricPattern4(client, _m(acc, "2017_returns")),
|
||||
_2018: createMetricPattern4(client, _m(acc, "2018_returns")),
|
||||
_2019: createMetricPattern4(client, _m(acc, "2019_returns")),
|
||||
_2020: createMetricPattern4(client, _m(acc, "2020_returns")),
|
||||
_2021: createMetricPattern4(client, _m(acc, "2021_returns")),
|
||||
_2022: createMetricPattern4(client, _m(acc, "2022_returns")),
|
||||
_2023: createMetricPattern4(client, _m(acc, "2023_returns")),
|
||||
_2024: createMetricPattern4(client, _m(acc, "2024_returns")),
|
||||
_2025: createMetricPattern4(client, _m(acc, "2025_returns")),
|
||||
_2015: createMetricPattern4(client, _m(acc, "2015_average_price")),
|
||||
_2016: createMetricPattern4(client, _m(acc, "2016_average_price")),
|
||||
_2017: createMetricPattern4(client, _m(acc, "2017_average_price")),
|
||||
_2018: createMetricPattern4(client, _m(acc, "2018_average_price")),
|
||||
_2019: createMetricPattern4(client, _m(acc, "2019_average_price")),
|
||||
_2020: createMetricPattern4(client, _m(acc, "2020_average_price")),
|
||||
_2021: createMetricPattern4(client, _m(acc, "2021_average_price")),
|
||||
_2022: createMetricPattern4(client, _m(acc, "2022_average_price")),
|
||||
_2023: createMetricPattern4(client, _m(acc, "2023_average_price")),
|
||||
_2024: createMetricPattern4(client, _m(acc, "2024_average_price")),
|
||||
_2025: createMetricPattern4(client, _m(acc, "2025_average_price")),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* @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
|
||||
* @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
|
||||
* @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
|
||||
* @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
|
||||
* @property {ActivityPattern2} activity
|
||||
@@ -3719,29 +3763,29 @@ function create_100btcPattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _10yTo12yPattern
|
||||
* @typedef {Object} _10yPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern2} costBasis
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern2} realized
|
||||
* @property {RelativePattern2} relative
|
||||
* @property {RealizedPattern4} realized
|
||||
* @property {RelativePattern} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _10yTo12yPattern pattern node
|
||||
* Create a _10yPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_10yTo12yPattern}
|
||||
* @returns {_10yPattern}
|
||||
*/
|
||||
function create_10yTo12yPattern(client, acc) {
|
||||
function create_10yPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, "utxo_count")),
|
||||
realized: createRealizedPattern2(client, acc),
|
||||
relative: createRelativePattern2(client, acc),
|
||||
realized: createRealizedPattern4(client, acc),
|
||||
relative: createRelativePattern(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, "supply")),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
@@ -3806,73 +3850,29 @@ function create_0satsPattern2(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} _10yPattern
|
||||
* @typedef {Object} _10yTo12yPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {CostBasisPattern2} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern4} realized
|
||||
* @property {RelativePattern} relative
|
||||
* @property {RealizedPattern2} realized
|
||||
* @property {RelativePattern2} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _10yPattern pattern node
|
||||
* Create a _10yTo12yPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_10yPattern}
|
||||
* @returns {_10yTo12yPattern}
|
||||
*/
|
||||
function create_10yPattern(client, acc) {
|
||||
function create_10yTo12yPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
costBasis: createCostBasisPattern2(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, "utxo_count")),
|
||||
realized: createRealizedPattern4(client, acc),
|
||||
relative: createRelativePattern(client, acc),
|
||||
realized: createRealizedPattern2(client, acc),
|
||||
relative: createRelativePattern2(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, "supply")),
|
||||
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
|
||||
* @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
|
||||
* @property {BitcoinPattern2<Bitcoin>} bitcoin
|
||||
@@ -4088,21 +4046,44 @@ function create_2015Pattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _1dReturns1mSdPattern
|
||||
* @property {MetricPattern4<StoredF32>} sd
|
||||
* @property {MetricPattern4<StoredF32>} sma
|
||||
* @typedef {Object} CoinbasePattern
|
||||
* @property {BitcoinPattern} bitcoin
|
||||
* @property {DollarsPattern<Dollars>} dollars
|
||||
* @property {DollarsPattern<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _1dReturns1mSdPattern pattern node
|
||||
* Create a CoinbasePattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_1dReturns1mSdPattern}
|
||||
* @returns {CoinbasePattern}
|
||||
*/
|
||||
function create_1dReturns1mSdPattern(client, acc) {
|
||||
function createCoinbasePattern(client, acc) {
|
||||
return {
|
||||
sd: createMetricPattern4(client, _m(acc, "sd")),
|
||||
sma: createMetricPattern4(client, _m(acc, "sma")),
|
||||
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),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* @property {ActiveSupplyPattern} halved
|
||||
@@ -4151,21 +4170,23 @@ function createSupplyPattern2(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CostBasisPattern
|
||||
* @property {MetricPattern1<Dollars>} max
|
||||
* @property {MetricPattern1<Dollars>} min
|
||||
* @template T
|
||||
* @typedef {Object} SatsPattern
|
||||
* @property {MetricPattern1<T>} ohlc
|
||||
* @property {SplitPattern2<T>} split
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CostBasisPattern pattern node
|
||||
* Create a SatsPattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CostBasisPattern}
|
||||
* @returns {SatsPattern<T>}
|
||||
*/
|
||||
function createCostBasisPattern(client, acc) {
|
||||
function createSatsPattern(client, acc) {
|
||||
return {
|
||||
max: createMetricPattern1(client, _m(acc, "max_cost_basis")),
|
||||
min: createMetricPattern1(client, _m(acc, "min_cost_basis")),
|
||||
ohlc: createMetricPattern1(client, _m(acc, "ohlc_sats")),
|
||||
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
|
||||
* @property {MetricPattern4<StoredF32>} ratio
|
||||
@@ -4628,8 +4628,8 @@ function createOutputsPattern(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern2} costBasis
|
||||
* @property {MetricsTree_Distribution_UtxoCohorts_All_Activity} activity
|
||||
* @property {MetricsTree_Distribution_UtxoCohorts_All_CostBasis} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern3} realized
|
||||
* @property {MetricsTree_Distribution_UtxoCohorts_All_Relative} relative
|
||||
@@ -4637,6 +4637,22 @@ function createOutputsPattern(client, acc) {
|
||||
* @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
|
||||
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToOwnTotalUnrealizedPnl
|
||||
@@ -5035,7 +5051,7 @@ function createOutputsPattern(client, acc) {
|
||||
* @property {MetricsTree_Market_Ath} ath
|
||||
* @property {MetricsTree_Market_Dca} dca
|
||||
* @property {MetricsTree_Market_Indicators} indicators
|
||||
* @property {MetricsTree_Market_Lookback} lookback
|
||||
* @property {LookbackPattern<Dollars>} lookback
|
||||
* @property {MetricsTree_Market_MovingAverage} movingAverage
|
||||
* @property {MetricsTree_Market_Range} range
|
||||
* @property {MetricsTree_Market_Returns} returns
|
||||
@@ -5102,11 +5118,6 @@ function createOutputsPattern(client, acc) {
|
||||
* @property {MetricPattern6<StoredF32>} stochRsiK
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Market_Lookback
|
||||
* @property {PriceAgoPattern<Dollars>} priceAgo
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Market_MovingAverage
|
||||
* @property {Price111dSmaPattern} price111dSma
|
||||
@@ -5171,7 +5182,24 @@ function createOutputsPattern(client, acc) {
|
||||
* @property {_1dReturns1mSdPattern} downside1wSd
|
||||
* @property {_1dReturns1mSdPattern} downside1ySd
|
||||
* @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"),
|
||||
stochRsiK: createMetricPattern6(this, "stoch_rsi_k"),
|
||||
},
|
||||
lookback: {
|
||||
priceAgo: createPriceAgoPattern(this, "price"),
|
||||
},
|
||||
lookback: createLookbackPattern(this, "price"),
|
||||
movingAverage: {
|
||||
price111dSma: createPrice111dSmaPattern(this, "price_111d_sma"),
|
||||
price12dEma: createPrice111dSmaPattern(this, "price_12d_ema"),
|
||||
@@ -7402,7 +7428,21 @@ class BrkClient extends BrkClientBase {
|
||||
downside1wSd: create_1dReturns1mSdPattern(this, "downside_1w_sd"),
|
||||
downside1ySd: create_1dReturns1mSdPattern(this, "downside_1y_sd"),
|
||||
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: {
|
||||
price1mVolatility: createMetricPattern4(this, "price_1m_volatility"),
|
||||
@@ -7618,7 +7658,7 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
oracle: {
|
||||
ohlcCents: createMetricPattern6(this, "oracle_ohlc_cents"),
|
||||
ohlcDollars: createMetricPattern6(this, "oracle_ohlc_dollars"),
|
||||
ohlcDollars: createMetricPattern6(this, "oracle_ohlc"),
|
||||
priceCents: createMetricPattern11(this, "orange_price_cents"),
|
||||
txCount: createMetricPattern6(this, "oracle_tx_count"),
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,27 @@
|
||||
# Run:
|
||||
# uv run pytest tests/tree.py -s
|
||||
|
||||
"""Comprehensive test that fetches all endpoints in the tree."""
|
||||
|
||||
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=""):
|
||||
"""Recursively collect all MetricPattern instances from the tree."""
|
||||
metrics = []
|
||||
|
||||
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
|
||||
|
||||
try:
|
||||
@@ -16,74 +29,58 @@ def get_all_metrics(obj, path=""):
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if attr is None or callable(attr):
|
||||
continue
|
||||
|
||||
current_path = f"{path}.{attr_name}" if path else attr_name
|
||||
|
||||
# Check if this is a metric pattern (has 'by' attribute with index methods)
|
||||
if hasattr(attr, "by"):
|
||||
by = attr.by
|
||||
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))
|
||||
# Check if this is a metric pattern using the indexes() method
|
||||
if is_metric_pattern(attr):
|
||||
metrics.append((current_path, attr))
|
||||
|
||||
# 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))
|
||||
|
||||
return metrics
|
||||
|
||||
|
||||
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")
|
||||
|
||||
metrics = get_all_metrics(client.metrics)
|
||||
print(f"\nFound {len(metrics)} metrics")
|
||||
|
||||
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:
|
||||
full_path = f"{path}.by.{idx_name}"
|
||||
|
||||
try:
|
||||
# Verify both access methods work: .by.index() and .get(index)
|
||||
by = metric.by
|
||||
endpoint = getattr(by, idx_name)()
|
||||
# Use the new idiomatic API: tail(3).fetch() or [-3:].fetch()
|
||||
res = endpoint.tail(3).fetch()
|
||||
count = len(res["data"])
|
||||
if count != 3:
|
||||
failed += 1
|
||||
error_msg = (
|
||||
f"FAIL: {path}.by.{idx_name}() -> expected 3, got {count}"
|
||||
)
|
||||
errors.append(error_msg)
|
||||
print(error_msg)
|
||||
else:
|
||||
success += 1
|
||||
print(f"OK: {path}.by.{idx_name}() -> {count} items")
|
||||
endpoint_by_property = getattr(by, idx_name)()
|
||||
endpoint_by_get = metric.get(idx_name)
|
||||
|
||||
if endpoint_by_property is None:
|
||||
raise Exception(f"metric.by.{idx_name}() returned None")
|
||||
if endpoint_by_get is None:
|
||||
raise Exception(f"metric.get('{idx_name}') returned None")
|
||||
|
||||
endpoint_by_property.tail(1).fetch()
|
||||
success += 1
|
||||
print(f"OK: {full_path}")
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
error_msg = f"FAIL: {path}.by.{idx_name}() -> {e}"
|
||||
errors.append(error_msg)
|
||||
print(error_msg)
|
||||
print(f"FAIL: {full_path} -> {e}")
|
||||
return
|
||||
|
||||
print("\n=== Results ===")
|
||||
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__":
|
||||
|
||||
Reference in New Issue
Block a user