diff --git a/crates/brk_binder/README.md b/crates/brk_binder/README.md index 1672cd384..ca05370fa 100644 --- a/crates/brk_binder/README.md +++ b/crates/brk_binder/README.md @@ -22,7 +22,7 @@ use brk_binder::{generate_clients, ClientOutputPaths}; let paths = ClientOutputPaths::new() .rust("crates/brk_client/src/lib.rs") .javascript("modules/brk-client/index.js") - .python("packages/brk_client/__init__.py"); + .python("packages/brk_client/brk_client/__init__.py"); generate_clients(&vecs, &openapi_json, &paths)?; ``` diff --git a/crates/brk_binder/src/javascript.rs b/crates/brk_binder/src/javascript.rs index 232971164..c77f7d7d7 100644 --- a/crates/brk_binder/src/javascript.rs +++ b/crates/brk_binder/src/javascript.rs @@ -593,13 +593,13 @@ fn generate_parameterized_field( let metric_expr = if let Some(pos) = pattern.get_field_position(&field.name) { match pos { - FieldNamePosition::Append(suffix) => format!("`/${{acc}}{suffix}`"), - FieldNamePosition::Prepend(prefix) => format!("`/{prefix}${{acc}}`"), - FieldNamePosition::Identity => "`/${acc}`".to_string(), - FieldNamePosition::SetBase(base) => format!("'/{base}'"), + FieldNamePosition::Append(suffix) => format!("`${{acc}}{suffix}`"), + FieldNamePosition::Prepend(prefix) => format!("`{prefix}${{acc}}`"), + FieldNamePosition::Identity => "acc".to_string(), + FieldNamePosition::SetBase(base) => format!("'{base}'"), } } else { - format!("`/${{acc}}_{}`", field.name) + format!("`${{acc}}_{}`", field.name) }; if metadata.field_uses_accessor(field) { @@ -631,7 +631,7 @@ fn generate_tree_path_field( if metadata.is_pattern_type(&field.rust_type) { writeln!( output, - " {}: create{}(client, `${{basePath}}/{}`){}", + " {}: create{}(client, `${{basePath}}_{}`){}", field_name_js, field.rust_type, field.name, comma ) .unwrap(); @@ -639,14 +639,14 @@ fn generate_tree_path_field( let accessor = metadata.find_index_set_pattern(&field.indexes).unwrap(); writeln!( output, - " {}: create{}(client, `${{basePath}}/{}`){}", + " {}: create{}(client, `${{basePath}}_{}`){}", field_name_js, accessor.name, field.name, comma ) .unwrap(); } else { writeln!( output, - " {}: new MetricNode(client, `${{basePath}}/{}`){}", + " {}: new MetricNode(client, `${{basePath}}_{}`){}", field_name_js, field.name, comma ) .unwrap(); diff --git a/crates/brk_binder/src/lib.rs b/crates/brk_binder/src/lib.rs index d5d308608..b94f6ba21 100644 --- a/crates/brk_binder/src/lib.rs +++ b/crates/brk_binder/src/lib.rs @@ -48,14 +48,12 @@ impl ClientOutputPaths { } mod javascript; -mod js; mod openapi; mod python; mod rust; mod types; pub use javascript::*; -pub use js::*; pub use openapi::*; pub use python::*; pub use rust::*; diff --git a/crates/brk_binder/src/openapi.rs b/crates/brk_binder/src/openapi.rs index e52971af6..1a7ec927c 100644 --- a/crates/brk_binder/src/openapi.rs +++ b/crates/brk_binder/src/openapi.rs @@ -45,19 +45,27 @@ impl Endpoint { if let Some(op_id) = &self.operation_id { return op_id.clone(); } - // Generate from path: /api/blocks/{hash} -> "get_api_blocks_by_hash" - let parts: Vec = self - .path - .split('/') - .filter(|s| !s.is_empty()) - .map(|segment| { - if let Some(param) = segment.strip_prefix('{').and_then(|s| s.strip_suffix('}')) { - format!("by_{}", param) - } else { - segment.to_string() + // Generate from path: /api/block/{hash} -> "get_block" + // Skip "api" prefix, convert hyphens to underscores, avoid redundant param names + let mut parts: Vec = Vec::new(); + let mut prev_segment = ""; + + for segment in self.path.split('/').filter(|s| !s.is_empty()) { + if segment == "api" { + continue; + } + if let Some(param) = segment.strip_prefix('{').and_then(|s| s.strip_suffix('}')) { + // Only add "by_{param}" if the previous segment doesn't already contain the param name + let prev_normalized = prev_segment.replace('-', "_"); + if !prev_normalized.ends_with(param) { + parts.push(format!("by_{}", param)); } - }) - .collect(); + } else { + let normalized = segment.replace('-', "_"); + parts.push(normalized); + prev_segment = segment; + } + } format!("get_{}", parts.join("_")) } } @@ -201,12 +209,24 @@ fn extract_parameters(operation: &Operation, location: ParameterIn) -> Vec Some(Parameter { - name: param.name.clone(), - required: param.required.unwrap_or(false), - param_type: "string".to_string(), // Simplified - description: param.description.clone(), - }), + ObjectOrReference::Object(param) if param.location == location => { + let param_type = param + .schema + .as_ref() + .and_then(|s| match s { + ObjectOrReference::Ref { ref_path, .. } => { + ref_path.rsplit('/').next().map(|s| s.to_string()) + } + ObjectOrReference::Object(obj_schema) => schema_to_type_name(obj_schema), + }) + .unwrap_or_else(|| "string".to_string()); + Some(Parameter { + name: param.name.clone(), + required: param.required.unwrap_or(false), + param_type, + description: param.description.clone(), + }) + } _ => None, }) .collect() @@ -242,6 +262,8 @@ fn schema_type_from_schema(schema: &Schema) -> Option { Schema::Object(obj_or_ref) => match obj_or_ref.as_ref() { ObjectOrReference::Object(obj_schema) => schema_to_type_name(obj_schema), ObjectOrReference::Ref { ref_path, .. } => { + // Return the type name as-is (e.g., "Height", "Address") + // These should have definitions generated from schemas ref_path.rsplit('/').next().map(|s| s.to_string()) } }, diff --git a/crates/brk_binder/src/python.rs b/crates/brk_binder/src/python.rs index d3467c123..10d16322a 100644 --- a/crates/brk_binder/src/python.rs +++ b/crates/brk_binder/src/python.rs @@ -586,13 +586,13 @@ fn generate_parameterized_python_field( // For leaf fields, construct the metric path based on position let metric_expr = if let Some(pos) = pattern.get_field_position(&field.name) { match pos { - FieldNamePosition::Append(suffix) => format!("f'/{{acc}}{}'", suffix), - FieldNamePosition::Prepend(prefix) => format!("f'/{}{{acc}}'", prefix), - FieldNamePosition::Identity => "f'/{acc}'".to_string(), - FieldNamePosition::SetBase(base) => format!("'/{}'", base), + FieldNamePosition::Append(suffix) => format!("f'{{acc}}{}'", suffix), + FieldNamePosition::Prepend(prefix) => format!("f'{}{{acc}}'", prefix), + FieldNamePosition::Identity => "acc".to_string(), + FieldNamePosition::SetBase(base) => format!("'{}'", base), } } else { - format!("f'/{{acc}}_{}'", field.name) + format!("f'{{acc}}_{}'", field.name) }; if metadata.field_uses_accessor(field) { @@ -604,6 +604,7 @@ fn generate_parameterized_python_field( ) .unwrap(); } else { + // Direct MetricNode without indexes - pass metric name writeln!( output, " self.{}: {} = MetricNode(client, {})", @@ -625,7 +626,7 @@ fn generate_tree_path_python_field( if metadata.is_pattern_type(&field.rust_type) { writeln!( output, - " self.{}: {} = {}(client, f'{{base_path}}/{}')", + " self.{}: {} = {}(client, f'{{base_path}}_{}')", field_name, py_type, field.rust_type, field.name ) .unwrap(); @@ -633,14 +634,14 @@ fn generate_tree_path_python_field( let accessor = metadata.find_index_set_pattern(&field.indexes).unwrap(); writeln!( output, - " self.{}: {} = {}(client, f'{{base_path}}/{}')", + " self.{}: {} = {}(client, f'{{base_path}}_{}')", field_name, py_type, accessor.name, field.name ) .unwrap(); } else { writeln!( output, - " self.{}: {} = MetricNode(client, f'{{base_path}}/{}')", + " self.{}: {} = MetricNode(client, f'{{base_path}}_{}')", field_name, py_type, field.name ) .unwrap(); @@ -784,7 +785,7 @@ fn generate_tree_class( } else { writeln!( output, - " self.{}: {} = {}(client, f'{{base_path}}/{}')", + " self.{}: {} = {}(client, f'{{base_path}}_{}')", field_name_py, py_type, field.rust_type, field.name ) .unwrap(); @@ -793,7 +794,7 @@ fn generate_tree_class( let accessor = metadata.find_index_set_pattern(&field.indexes).unwrap(); writeln!( output, - " self.{}: {} = {}(client, f'{{base_path}}/{}')", + " self.{}: {} = {}(client, f'{{base_path}}_{}')", field_name_py, py_type, accessor.name, field.name ) .unwrap(); @@ -801,15 +802,15 @@ fn generate_tree_class( // Non-pattern branch - instantiate the nested class writeln!( output, - " self.{}: {} = {}(client, f'{{base_path}}/{}')", + " self.{}: {} = {}(client, f'{{base_path}}_{}')", field_name_py, py_type, field.rust_type, field.name ) .unwrap(); } else { - // Leaf - use MetricNode with base_path + // Leaf metric - direct MetricNode with full API path writeln!( output, - " self.{}: {} = MetricNode(client, f'{{base_path}}/{}')", + " self.{}: {} = MetricNode(client, f'{{base_path}}_{}')", field_name_py, py_type, field.name ) .unwrap(); @@ -966,14 +967,16 @@ fn build_method_params(endpoint: &Endpoint) -> String { let mut params = Vec::new(); for param in &endpoint.path_params { let safe_name = escape_python_keyword(¶m.name); - params.push(format!(", {}: str", safe_name)); + let py_type = js_type_to_python(¶m.param_type); + params.push(format!(", {}: {}", safe_name, py_type)); } for param in &endpoint.query_params { let safe_name = escape_python_keyword(¶m.name); + let py_type = js_type_to_python(¶m.param_type); if param.required { - params.push(format!(", {}: str", safe_name)); + params.push(format!(", {}: {}", safe_name, py_type)); } else { - params.push(format!(", {}: Optional[str] = None", safe_name)); + params.push(format!(", {}: Optional[{}] = None", safe_name, py_type)); } } params.join("") diff --git a/crates/brk_cli/src/main.rs b/crates/brk_cli/src/main.rs index 89e257def..8c40e76ff 100644 --- a/crates/brk_cli/src/main.rs +++ b/crates/brk_cli/src/main.rs @@ -9,7 +9,6 @@ use std::{ }; use brk_alloc::Mimalloc; -use brk_binder::generate_js_files; use brk_bundler::bundle; use brk_computer::Computer; use brk_error::Result; @@ -119,8 +118,6 @@ pub fn run() -> color_eyre::Result<()> { modules_path = downloaded_modules_path; } - generate_js_files(query.inner(), &modules_path)?; - Some( bundle( &modules_path, diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index a2591970d..268962e12 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -680,7 +680,7 @@ impl RealizedPattern3 { } /// Pattern struct for repeated tree structure. -pub struct Ratio1ySdPattern2 { +pub struct Ratio1ySdPattern { pub _0sd_usd: Indexes, pub m0_5sd: Indexes, pub m0_5sd_usd: Indexes, @@ -711,7 +711,7 @@ pub struct Ratio1ySdPattern2 { pub zscore: Indexes, } -impl Ratio1ySdPattern2 { +impl Ratio1ySdPattern { pub fn new(client: Arc, base_path: &str) -> Self { Self { _0sd_usd: Indexes::new(client.clone(), &format!("{base_path}/_0sd_usd")), @@ -874,9 +874,9 @@ pub struct Price13dEmaPattern { pub ratio: Indexes, pub ratio_1m_sma: Indexes, pub ratio_1w_sma: Indexes, - pub ratio_1y_sd: Ratio1ySdPattern2, - pub ratio_2y_sd: Ratio1ySdPattern2, - pub ratio_4y_sd: Ratio1ySdPattern2, + pub ratio_1y_sd: Ratio1ySdPattern, + pub ratio_2y_sd: Ratio1ySdPattern, + pub ratio_4y_sd: Ratio1ySdPattern, pub ratio_pct1: Indexes, pub ratio_pct1_usd: Indexes, pub ratio_pct2: Indexes, @@ -889,7 +889,7 @@ pub struct Price13dEmaPattern { pub ratio_pct98_usd: Indexes, pub ratio_pct99: Indexes, pub ratio_pct99_usd: Indexes, - pub ratio_sd: Ratio1ySdPattern2, + pub ratio_sd: Ratio1ySdPattern, } impl Price13dEmaPattern { @@ -900,9 +900,9 @@ impl Price13dEmaPattern { ratio: Indexes::new(client.clone(), &format!("/{acc}_ratio")), ratio_1m_sma: Indexes::new(client.clone(), &format!("/{acc}_ratio_1m_sma")), ratio_1w_sma: Indexes::new(client.clone(), &format!("/{acc}_ratio_1w_sma")), - ratio_1y_sd: Ratio1ySdPattern2::new(client.clone(), &format!("{acc}_ratio_1y_sd")), - ratio_2y_sd: Ratio1ySdPattern2::new(client.clone(), &format!("{acc}_ratio_2y_sd")), - ratio_4y_sd: Ratio1ySdPattern2::new(client.clone(), &format!("{acc}_ratio_4y_sd")), + ratio_1y_sd: Ratio1ySdPattern::new(client.clone(), &format!("{acc}_ratio_1y_sd")), + ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), &format!("{acc}_ratio_2y_sd")), + ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), &format!("{acc}_ratio_4y_sd")), ratio_pct1: Indexes::new(client.clone(), &format!("/{acc}_ratio_pct1")), ratio_pct1_usd: Indexes::new(client.clone(), &format!("/{acc}_ratio_pct1_usd")), ratio_pct2: Indexes::new(client.clone(), &format!("/{acc}_ratio_pct2")), @@ -915,7 +915,7 @@ impl Price13dEmaPattern { ratio_pct98_usd: Indexes::new(client.clone(), &format!("/{acc}_ratio_pct98_usd")), ratio_pct99: Indexes::new(client.clone(), &format!("/{acc}_ratio_pct99")), ratio_pct99_usd: Indexes::new(client.clone(), &format!("/{acc}_ratio_pct99_usd")), - ratio_sd: Ratio1ySdPattern2::new(client.clone(), &format!("{acc}_ratio_sd")), + ratio_sd: Ratio1ySdPattern::new(client.clone(), &format!("{acc}_ratio_sd")), } } } @@ -1014,47 +1014,6 @@ impl RelativePattern2 { } } -/// Pattern struct for repeated tree structure. -pub struct Ratio1ySdPattern { - pub m0_5sd: Indexes, - pub m1_5sd: Indexes, - pub m1sd: Indexes, - pub m2_5sd: Indexes, - pub m2sd: Indexes, - pub m3sd: Indexes, - pub p0_5sd: Indexes, - pub p1_5sd: Indexes, - pub p1sd: Indexes, - pub p2_5sd: Indexes, - pub p2sd: Indexes, - pub p3sd: Indexes, - pub sd: Indexes, - pub sma: Indexes, - pub zscore: Indexes, -} - -impl Ratio1ySdPattern { - pub fn new(client: Arc, base_path: &str) -> Self { - Self { - m0_5sd: Indexes::new(client.clone(), &format!("{base_path}/m0_5sd")), - m1_5sd: Indexes::new(client.clone(), &format!("{base_path}/m1_5sd")), - m1sd: Indexes::new(client.clone(), &format!("{base_path}/m1sd")), - m2_5sd: Indexes::new(client.clone(), &format!("{base_path}/m2_5sd")), - m2sd: Indexes::new(client.clone(), &format!("{base_path}/m2sd")), - m3sd: Indexes::new(client.clone(), &format!("{base_path}/m3sd")), - p0_5sd: Indexes::new(client.clone(), &format!("{base_path}/p0_5sd")), - p1_5sd: Indexes::new(client.clone(), &format!("{base_path}/p1_5sd")), - p1sd: Indexes::new(client.clone(), &format!("{base_path}/p1sd")), - p2_5sd: Indexes::new(client.clone(), &format!("{base_path}/p2_5sd")), - p2sd: Indexes::new(client.clone(), &format!("{base_path}/p2sd")), - p3sd: Indexes::new(client.clone(), &format!("{base_path}/p3sd")), - sd: Indexes::new(client.clone(), &format!("{base_path}/sd")), - sma: Indexes::new(client.clone(), &format!("{base_path}/sma")), - zscore: Indexes::new(client.clone(), &format!("{base_path}/zscore")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct ActivePriceRatioPattern { pub ratio: Indexes, @@ -1164,60 +1123,31 @@ impl BitcoinPattern { /// Pattern struct for repeated tree structure. pub struct BlockSizePattern { - pub average: Indexes3, + pub average: Indexes4, pub cumulative: Indexes3, - pub max: Indexes3, - pub median: Indexes2, - pub min: Indexes3, - pub pct10: Indexes2, - pub pct25: Indexes2, - pub pct75: Indexes2, - pub pct90: Indexes2, - pub sum: Indexes3, + pub max: Indexes4, + pub median: Indexes5, + pub min: Indexes4, + pub pct10: Indexes5, + pub pct25: Indexes5, + pub pct75: Indexes5, + pub pct90: Indexes5, + pub sum: Indexes4, } impl BlockSizePattern { pub fn new(client: Arc, base_path: &str) -> Self { Self { - average: Indexes3::new(client.clone(), &format!("{base_path}/average")), + average: Indexes4::new(client.clone(), &format!("{base_path}/average")), cumulative: Indexes3::new(client.clone(), &format!("{base_path}/cumulative")), - max: Indexes3::new(client.clone(), &format!("{base_path}/max")), - median: Indexes2::new(client.clone(), &format!("{base_path}/median")), - min: Indexes3::new(client.clone(), &format!("{base_path}/min")), - pct10: Indexes2::new(client.clone(), &format!("{base_path}/pct10")), - pct25: Indexes2::new(client.clone(), &format!("{base_path}/pct25")), - pct75: Indexes2::new(client.clone(), &format!("{base_path}/pct75")), - pct90: Indexes2::new(client.clone(), &format!("{base_path}/pct90")), - sum: Indexes3::new(client.clone(), &format!("{base_path}/sum")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct UnrealizedPattern { - pub neg_unrealized_loss: Indexes26, - pub net_unrealized_pnl: Indexes26, - pub supply_in_loss: SupplyPattern, - pub supply_in_loss_value: SupplyValuePattern, - pub supply_in_profit: SupplyPattern, - pub supply_in_profit_value: SupplyValuePattern, - pub total_unrealized_pnl: Indexes26, - pub unrealized_loss: Indexes26, - pub unrealized_profit: Indexes26, -} - -impl UnrealizedPattern { - pub fn new(client: Arc, base_path: &str) -> Self { - Self { - neg_unrealized_loss: Indexes26::new(client.clone(), &format!("{base_path}/neg_unrealized_loss")), - net_unrealized_pnl: Indexes26::new(client.clone(), &format!("{base_path}/net_unrealized_pnl")), - supply_in_loss: SupplyPattern::new(client.clone(), &format!("{base_path}/supply_in_loss")), - supply_in_loss_value: SupplyValuePattern::new(client.clone(), &format!("{base_path}/supply_in_loss_value")), - supply_in_profit: SupplyPattern::new(client.clone(), &format!("{base_path}/supply_in_profit")), - supply_in_profit_value: SupplyValuePattern::new(client.clone(), &format!("{base_path}/supply_in_profit_value")), - total_unrealized_pnl: Indexes26::new(client.clone(), &format!("{base_path}/total_unrealized_pnl")), - unrealized_loss: Indexes26::new(client.clone(), &format!("{base_path}/unrealized_loss")), - unrealized_profit: Indexes26::new(client.clone(), &format!("{base_path}/unrealized_profit")), + max: Indexes4::new(client.clone(), &format!("{base_path}/max")), + median: Indexes5::new(client.clone(), &format!("{base_path}/median")), + min: Indexes4::new(client.clone(), &format!("{base_path}/min")), + pct10: Indexes5::new(client.clone(), &format!("{base_path}/pct10")), + pct25: Indexes5::new(client.clone(), &format!("{base_path}/pct25")), + pct75: Indexes5::new(client.clone(), &format!("{base_path}/pct75")), + pct90: Indexes5::new(client.clone(), &format!("{base_path}/pct90")), + sum: Indexes4::new(client.clone(), &format!("{base_path}/sum")), } } } @@ -1252,56 +1182,30 @@ impl RelativePattern { } /// Pattern struct for repeated tree structure. -pub struct AddresstypeToHeightToAddrCountPattern { - pub p2a: Indexes2, - pub p2pk33: Indexes2, - pub p2pk65: Indexes2, - pub p2pkh: Indexes2, - pub p2sh: Indexes2, - pub p2tr: Indexes2, - pub p2wpkh: Indexes2, - pub p2wsh: Indexes2, +pub struct UnrealizedPattern { + pub neg_unrealized_loss: Indexes26, + pub net_unrealized_pnl: Indexes26, + pub supply_in_loss: SupplyPattern, + pub supply_in_loss_value: SupplyValuePattern, + pub supply_in_profit: SupplyPattern, + pub supply_in_profit_value: SupplyValuePattern, + pub total_unrealized_pnl: Indexes26, + pub unrealized_loss: Indexes26, + pub unrealized_profit: Indexes26, } -impl AddresstypeToHeightToAddrCountPattern { +impl UnrealizedPattern { pub fn new(client: Arc, base_path: &str) -> Self { Self { - p2a: Indexes2::new(client.clone(), &format!("{base_path}/p2a")), - p2pk33: Indexes2::new(client.clone(), &format!("{base_path}/p2pk33")), - p2pk65: Indexes2::new(client.clone(), &format!("{base_path}/p2pk65")), - p2pkh: Indexes2::new(client.clone(), &format!("{base_path}/p2pkh")), - p2sh: Indexes2::new(client.clone(), &format!("{base_path}/p2sh")), - p2tr: Indexes2::new(client.clone(), &format!("{base_path}/p2tr")), - p2wpkh: Indexes2::new(client.clone(), &format!("{base_path}/p2wpkh")), - p2wsh: Indexes2::new(client.clone(), &format!("{base_path}/p2wsh")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct Constant0Pattern { - pub dateindex: Indexes5, - pub decadeindex: Indexes7, - pub height: Indexes2, - pub monthindex: Indexes8, - pub quarterindex: Indexes9, - pub semesterindex: Indexes10, - pub weekindex: Indexes11, - pub yearindex: Indexes12, -} - -impl Constant0Pattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: &str) -> Self { - Self { - dateindex: Indexes5::new(client.clone(), &format!("/{acc}")), - decadeindex: Indexes7::new(client.clone(), &format!("/{acc}")), - height: Indexes2::new(client.clone(), &format!("/{acc}")), - monthindex: Indexes8::new(client.clone(), &format!("/{acc}")), - quarterindex: Indexes9::new(client.clone(), &format!("/{acc}")), - semesterindex: Indexes10::new(client.clone(), &format!("/{acc}")), - weekindex: Indexes11::new(client.clone(), &format!("/{acc}")), - yearindex: Indexes12::new(client.clone(), &format!("/{acc}")), + neg_unrealized_loss: Indexes26::new(client.clone(), &format!("{base_path}/neg_unrealized_loss")), + net_unrealized_pnl: Indexes26::new(client.clone(), &format!("{base_path}/net_unrealized_pnl")), + supply_in_loss: SupplyPattern::new(client.clone(), &format!("{base_path}/supply_in_loss")), + supply_in_loss_value: SupplyValuePattern::new(client.clone(), &format!("{base_path}/supply_in_loss_value")), + supply_in_profit: SupplyPattern::new(client.clone(), &format!("{base_path}/supply_in_profit")), + supply_in_profit_value: SupplyValuePattern::new(client.clone(), &format!("{base_path}/supply_in_profit_value")), + total_unrealized_pnl: Indexes26::new(client.clone(), &format!("{base_path}/total_unrealized_pnl")), + unrealized_loss: Indexes26::new(client.clone(), &format!("{base_path}/unrealized_loss")), + unrealized_profit: Indexes26::new(client.clone(), &format!("{base_path}/unrealized_profit")), } } } @@ -1334,6 +1238,61 @@ impl BlockIntervalPattern { } } +/// Pattern struct for repeated tree structure. +pub struct Constant0Pattern { + pub dateindex: Indexes5, + pub decadeindex: Indexes7, + pub height: Indexes2, + pub monthindex: Indexes8, + pub quarterindex: Indexes9, + pub semesterindex: Indexes10, + pub weekindex: Indexes11, + pub yearindex: Indexes12, +} + +impl Constant0Pattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: &str) -> Self { + Self { + dateindex: Indexes5::new(client.clone(), &format!("/{acc}")), + decadeindex: Indexes7::new(client.clone(), &format!("/{acc}")), + height: Indexes2::new(client.clone(), &format!("/{acc}")), + monthindex: Indexes8::new(client.clone(), &format!("/{acc}")), + quarterindex: Indexes9::new(client.clone(), &format!("/{acc}")), + semesterindex: Indexes10::new(client.clone(), &format!("/{acc}")), + weekindex: Indexes11::new(client.clone(), &format!("/{acc}")), + yearindex: Indexes12::new(client.clone(), &format!("/{acc}")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct AddresstypeToHeightToAddrCountPattern { + pub p2a: Indexes2, + pub p2pk33: Indexes2, + pub p2pk65: Indexes2, + pub p2pkh: Indexes2, + pub p2sh: Indexes2, + pub p2tr: Indexes2, + pub p2wpkh: Indexes2, + pub p2wsh: Indexes2, +} + +impl AddresstypeToHeightToAddrCountPattern { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + p2a: Indexes2::new(client.clone(), &format!("{base_path}/p2a")), + p2pk33: Indexes2::new(client.clone(), &format!("{base_path}/p2pk33")), + p2pk65: Indexes2::new(client.clone(), &format!("{base_path}/p2pk65")), + p2pkh: Indexes2::new(client.clone(), &format!("{base_path}/p2pkh")), + p2sh: Indexes2::new(client.clone(), &format!("{base_path}/p2sh")), + p2tr: Indexes2::new(client.clone(), &format!("{base_path}/p2tr")), + p2wpkh: Indexes2::new(client.clone(), &format!("{base_path}/p2wpkh")), + p2wsh: Indexes2::new(client.clone(), &format!("{base_path}/p2wsh")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _0satsPattern { pub activity: ActivityPattern, @@ -1359,29 +1318,6 @@ impl _0satsPattern { } } -/// Pattern struct for repeated tree structure. -pub struct _10yTo12yPattern { - pub activity: ActivityPattern, - pub price_paid: PricePaidPattern2, - pub realized: RealizedPattern2, - pub relative: RelativePattern2, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, -} - -impl _10yTo12yPattern { - pub fn new(client: Arc, base_path: &str) -> Self { - Self { - activity: ActivityPattern::new(client.clone(), &format!("{base_path}/activity")), - price_paid: PricePaidPattern2::new(client.clone(), &format!("{base_path}/price_paid")), - realized: RealizedPattern2::new(client.clone(), &format!("{base_path}/realized")), - relative: RelativePattern2::new(client.clone(), &format!("{base_path}/relative")), - supply: SupplyPattern2::new(client.clone(), &format!("{base_path}/supply")), - unrealized: UnrealizedPattern::new(client.clone(), &format!("{base_path}/unrealized")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct UpTo1dPattern { pub activity: ActivityPattern, @@ -1429,22 +1365,24 @@ impl _0satsPattern2 { } /// Pattern struct for repeated tree structure. -pub struct SupplyPattern2 { - pub supply: SupplyPattern, - pub supply_half: ActiveSupplyPattern, - pub supply_half_value: ActiveSupplyPattern, - pub supply_value: SupplyValuePattern, - pub utxo_count: Indexes3, +pub struct _10yTo12yPattern { + pub activity: ActivityPattern, + pub price_paid: PricePaidPattern2, + pub realized: RealizedPattern2, + pub relative: RelativePattern2, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, } -impl SupplyPattern2 { +impl _10yTo12yPattern { pub fn new(client: Arc, base_path: &str) -> Self { Self { - supply: SupplyPattern::new(client.clone(), &format!("{base_path}/supply")), - supply_half: ActiveSupplyPattern::new(client.clone(), &format!("{base_path}/supply_half")), - supply_half_value: ActiveSupplyPattern::new(client.clone(), &format!("{base_path}/supply_half_value")), - supply_value: SupplyValuePattern::new(client.clone(), &format!("{base_path}/supply_value")), - utxo_count: Indexes3::new(client.clone(), &format!("{base_path}/utxo_count")), + activity: ActivityPattern::new(client.clone(), &format!("{base_path}/activity")), + price_paid: PricePaidPattern2::new(client.clone(), &format!("{base_path}/price_paid")), + realized: RealizedPattern2::new(client.clone(), &format!("{base_path}/realized")), + relative: RelativePattern2::new(client.clone(), &format!("{base_path}/relative")), + supply: SupplyPattern2::new(client.clone(), &format!("{base_path}/supply")), + unrealized: UnrealizedPattern::new(client.clone(), &format!("{base_path}/unrealized")), } } } @@ -1470,6 +1408,27 @@ impl ActivityPattern { } } +/// Pattern struct for repeated tree structure. +pub struct SupplyPattern2 { + pub supply: SupplyPattern, + pub supply_half: ActiveSupplyPattern, + pub supply_half_value: ActiveSupplyPattern, + pub supply_value: SupplyValuePattern, + pub utxo_count: Indexes3, +} + +impl SupplyPattern2 { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + supply: SupplyPattern::new(client.clone(), &format!("{base_path}/supply")), + supply_half: ActiveSupplyPattern::new(client.clone(), &format!("{base_path}/supply_half")), + supply_half_value: ActiveSupplyPattern::new(client.clone(), &format!("{base_path}/supply_half_value")), + supply_value: SupplyValuePattern::new(client.clone(), &format!("{base_path}/supply_value")), + utxo_count: Indexes3::new(client.clone(), &format!("{base_path}/utxo_count")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct FeePattern2 { pub base: Indexes2, @@ -1594,16 +1553,17 @@ impl BlockCountPattern { } /// Pattern struct for repeated tree structure. -pub struct SupplyValuePattern { - pub bitcoin: Indexes2, - pub dollars: Indexes2, +pub struct _1dReturns1mSdPattern { + pub sd: Indexes, + pub sma: Indexes, } -impl SupplyValuePattern { - pub fn new(client: Arc, base_path: &str) -> Self { +impl _1dReturns1mSdPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: &str) -> Self { Self { - bitcoin: Indexes2::new(client.clone(), &format!("{base_path}/bitcoin")), - dollars: Indexes2::new(client.clone(), &format!("{base_path}/dollars")), + sd: Indexes::new(client.clone(), &format!("/{acc}_sd")), + sma: Indexes::new(client.clone(), &format!("/{acc}_sma")), } } } @@ -1624,17 +1584,16 @@ impl PricePaidPattern { } /// Pattern struct for repeated tree structure. -pub struct _1dReturns1mSdPattern { - pub sd: Indexes, - pub sma: Indexes, +pub struct SupplyValuePattern { + pub bitcoin: Indexes2, + pub dollars: Indexes2, } -impl _1dReturns1mSdPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: &str) -> Self { +impl SupplyValuePattern { + pub fn new(client: Arc, base_path: &str) -> Self { Self { - sd: Indexes::new(client.clone(), &format!("/{acc}_sd")), - sma: Indexes::new(client.clone(), &format!("/{acc}_sma")), + bitcoin: Indexes2::new(client.clone(), &format!("{base_path}/bitcoin")), + dollars: Indexes2::new(client.clone(), &format!("{base_path}/dollars")), } } } @@ -3796,14 +3755,14 @@ impl BrkClient { /// Address information /// /// Retrieve comprehensive information about a Bitcoin address including balance, transaction history, UTXOs, and estimated investment metrics. Supports all standard Bitcoin address types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR, etc.). - pub fn get_api_address_by_address(&self, address: &str) -> Result { + pub fn get_address(&self, address: &str) -> Result { self.base.get(&format!("/api/address/{address}")) } /// Address transaction IDs /// /// Get transaction IDs for an address, newest first. Use after_txid for pagination. - pub fn get_api_address_by_address_txs(&self, address: &str, after_txid: Option<&str>, limit: Option<&str>) -> Result> { + pub fn get_address_txs(&self, address: &str, after_txid: Option<&str>, limit: Option<&str>) -> Result> { let mut query = Vec::new(); if let Some(v) = after_txid { query.push(format!("after_txid={}", v)); } if let Some(v) = limit { query.push(format!("limit={}", v)); } @@ -3814,7 +3773,7 @@ impl BrkClient { /// Address confirmed transactions /// /// Get confirmed transaction IDs for an address, 25 per page. Use ?after_txid= for pagination. - pub fn get_api_address_by_address_txs_chain(&self, address: &str, after_txid: Option<&str>, limit: Option<&str>) -> Result> { + pub fn get_address_txs_chain(&self, address: &str, after_txid: Option<&str>, limit: Option<&str>) -> Result> { let mut query = Vec::new(); if let Some(v) = after_txid { query.push(format!("after_txid={}", v)); } if let Some(v) = limit { query.push(format!("limit={}", v)); } @@ -3825,105 +3784,105 @@ impl BrkClient { /// Address mempool transactions /// /// Get unconfirmed transaction IDs for an address from the mempool (up to 50). - pub fn get_api_address_by_address_txs_mempool(&self, address: &str) -> Result> { + pub fn get_address_txs_mempool(&self, address: &str) -> Result> { self.base.get(&format!("/api/address/{address}/txs/mempool")) } /// Address UTXOs /// /// Get unspent transaction outputs for an address. - pub fn get_api_address_by_address_utxo(&self, address: &str) -> Result> { + pub fn get_address_utxo(&self, address: &str) -> Result> { self.base.get(&format!("/api/address/{address}/utxo")) } /// Block by height /// /// Retrieve block information by block height. Returns block metadata including hash, timestamp, difficulty, size, weight, and transaction count. - pub fn get_api_block_height_by_height(&self, height: &str) -> Result { + pub fn get_block_height(&self, height: &str) -> Result { self.base.get(&format!("/api/block-height/{height}")) } /// Block information /// /// Retrieve block information by block hash. Returns block metadata including height, timestamp, difficulty, size, weight, and transaction count. - pub fn get_api_block_by_hash(&self, hash: &str) -> Result { + pub fn get_block_by_hash(&self, hash: &str) -> Result { self.base.get(&format!("/api/block/{hash}")) } /// Raw block /// /// Returns the raw block data in binary format. - pub fn get_api_block_by_hash_raw(&self, hash: &str) -> Result> { + pub fn get_block_by_hash_raw(&self, hash: &str) -> Result> { self.base.get(&format!("/api/block/{hash}/raw")) } /// Block status /// /// Retrieve the status of a block. Returns whether the block is in the best chain and, if so, its height and the hash of the next block. - pub fn get_api_block_by_hash_status(&self, hash: &str) -> Result { + pub fn get_block_by_hash_status(&self, hash: &str) -> Result { self.base.get(&format!("/api/block/{hash}/status")) } /// Transaction ID at index /// /// Retrieve a single transaction ID at a specific index within a block. Returns plain text txid. - pub fn get_api_block_by_hash_txid_by_index(&self, hash: &str, index: &str) -> Result { + pub fn get_block_by_hash_txid_by_index(&self, hash: &str, index: &str) -> Result { self.base.get(&format!("/api/block/{hash}/txid/{index}")) } /// Block transaction IDs /// /// Retrieve all transaction IDs in a block by block hash. - pub fn get_api_block_by_hash_txids(&self, hash: &str) -> Result> { + pub fn get_block_by_hash_txids(&self, hash: &str) -> Result> { self.base.get(&format!("/api/block/{hash}/txids")) } /// Block transactions (paginated) /// /// Retrieve transactions in a block by block hash, starting from the specified index. Returns up to 25 transactions at a time. - pub fn get_api_block_by_hash_txs_by_start_index(&self, hash: &str, start_index: &str) -> Result> { + pub fn get_block_by_hash_txs_by_start_index(&self, hash: &str, start_index: &str) -> Result> { self.base.get(&format!("/api/block/{hash}/txs/{start_index}")) } /// Recent blocks /// /// Retrieve the last 10 blocks. Returns block metadata for each block. - pub fn get_api_blocks(&self) -> Result> { + pub fn get_blocks(&self) -> Result> { self.base.get(&format!("/api/blocks")) } /// Blocks from height /// /// Retrieve up to 10 blocks going backwards from the given height. For example, height=100 returns blocks 100, 99, 98, ..., 91. Height=0 returns only block 0. - pub fn get_api_blocks_by_height(&self, height: &str) -> Result> { + pub fn get_blocks_by_height(&self, height: &str) -> Result> { self.base.get(&format!("/api/blocks/{height}")) } /// Mempool statistics /// /// Get current mempool statistics including transaction count, total vsize, and total fees. - pub fn get_api_mempool_info(&self) -> Result { + pub fn get_mempool_info(&self) -> Result { self.base.get(&format!("/api/mempool/info")) } /// Mempool transaction IDs /// /// Get all transaction IDs currently in the mempool. - pub fn get_api_mempool_txids(&self) -> Result> { + pub fn get_mempool_txids(&self) -> Result> { self.base.get(&format!("/api/mempool/txids")) } /// Get supported indexes for a metric /// /// Returns the list of indexes are supported by the specified metric. For example, `realized_price` might be available on dateindex, weekindex, and monthindex. - pub fn get_api_metric_by_metric(&self, metric: &str) -> Result> { + pub fn get_metric(&self, metric: &str) -> Result> { self.base.get(&format!("/api/metric/{metric}")) } /// Get metric data /// /// Fetch data for a specific metric at the given index. Use query parameters to filter by date range and format (json/csv). - pub fn get_api_metric_by_metric_by_index(&self, metric: &str, index: &str, from: Option<&str>, to: Option<&str>, count: Option<&str>, format: Option<&str>) -> Result { + pub fn get_metric_by_index(&self, metric: &str, index: &str, from: Option<&str>, to: Option<&str>, count: Option<&str>, format: Option<&str>) -> Result { let mut query = Vec::new(); if let Some(v) = from { query.push(format!("from={}", v)); } if let Some(v) = to { query.push(format!("to={}", v)); } @@ -3936,7 +3895,7 @@ impl BrkClient { /// Bulk metric data /// /// Fetch multiple metrics in a single request. Supports filtering by index and date range. Returns an array of MetricData objects. - pub fn get_api_metrics_bulk(&self, metrics: &str, index: &str, from: Option<&str>, to: Option<&str>, count: Option<&str>, format: Option<&str>) -> Result> { + pub fn get_metrics_bulk(&self, metrics: &str, index: &str, from: Option<&str>, to: Option<&str>, count: Option<&str>, format: Option<&str>) -> Result> { let mut query = Vec::new(); query.push(format!("metrics={}", metrics)); query.push(format!("index={}", index)); @@ -3951,28 +3910,28 @@ impl BrkClient { /// Metrics catalog /// /// Returns the complete hierarchical catalog of available metrics organized as a tree structure. Metrics are grouped by categories and subcategories. Best viewed in an interactive JSON viewer (e.g., Firefox's built-in JSON viewer) for easy navigation of the nested structure. - pub fn get_api_metrics_catalog(&self) -> Result { + pub fn get_metrics_catalog(&self) -> Result { self.base.get(&format!("/api/metrics/catalog")) } /// Metric count /// /// Current metric count - pub fn get_api_metrics_count(&self) -> Result> { + pub fn get_metrics_count(&self) -> Result> { self.base.get(&format!("/api/metrics/count")) } /// List available indexes /// /// Returns all available indexes with their accepted query aliases. Use any alias when querying metrics. - pub fn get_api_metrics_indexes(&self) -> Result> { + pub fn get_metrics_indexes(&self) -> Result> { self.base.get(&format!("/api/metrics/indexes")) } /// Metrics list /// /// Paginated list of available metrics - pub fn get_api_metrics_list(&self, page: Option<&str>) -> Result { + pub fn get_metrics_list(&self, page: Option<&str>) -> Result { let mut query = Vec::new(); if let Some(v) = page { query.push(format!("page={}", v)); } let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; @@ -3982,7 +3941,7 @@ impl BrkClient { /// Search metrics /// /// Fuzzy search for metrics by name. Supports partial matches and typos. - pub fn get_api_metrics_search_by_metric(&self, metric: &str, limit: Option<&str>) -> Result> { + pub fn get_metrics_search_by_metric(&self, metric: &str, limit: Option<&str>) -> Result> { let mut query = Vec::new(); if let Some(v) = limit { query.push(format!("limit={}", v)); } let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; @@ -3992,147 +3951,147 @@ impl BrkClient { /// Transaction information /// /// Retrieve complete transaction data by transaction ID (txid). Returns the full transaction details including inputs, outputs, and metadata. The transaction data is read directly from the blockchain data files. - pub fn get_api_tx_by_txid(&self, txid: &str) -> Result { + pub fn get_tx_by_txid(&self, txid: &str) -> Result { self.base.get(&format!("/api/tx/{txid}")) } /// Transaction hex /// /// Retrieve the raw transaction as a hex-encoded string. Returns the serialized transaction in hexadecimal format. - pub fn get_api_tx_by_txid_hex(&self, txid: &str) -> Result { + pub fn get_tx_by_txid_hex(&self, txid: &str) -> Result { self.base.get(&format!("/api/tx/{txid}/hex")) } /// Output spend status /// /// Get the spending status of a transaction output. Returns whether the output has been spent and, if so, the spending transaction details. - pub fn get_api_tx_by_txid_outspend_by_vout(&self, txid: &str, vout: &str) -> Result { + pub fn get_tx_by_txid_outspend_by_vout(&self, txid: &str, vout: &str) -> Result { self.base.get(&format!("/api/tx/{txid}/outspend/{vout}")) } /// All output spend statuses /// /// Get the spending status of all outputs in a transaction. Returns an array with the spend status for each output. - pub fn get_api_tx_by_txid_outspends(&self, txid: &str) -> Result> { + pub fn get_tx_by_txid_outspends(&self, txid: &str) -> Result> { self.base.get(&format!("/api/tx/{txid}/outspends")) } /// Transaction status /// /// Retrieve the confirmation status of a transaction. Returns whether the transaction is confirmed and, if so, the block height, hash, and timestamp. - pub fn get_api_tx_by_txid_status(&self, txid: &str) -> Result { + pub fn get_tx_by_txid_status(&self, txid: &str) -> Result { self.base.get(&format!("/api/tx/{txid}/status")) } /// Difficulty adjustment /// /// Get current difficulty adjustment information including progress through the current epoch, estimated retarget date, and difficulty change prediction. - pub fn get_api_v1_difficulty_adjustment(&self) -> Result { + pub fn get_v1_difficulty_adjustment(&self) -> Result { self.base.get(&format!("/api/v1/difficulty-adjustment")) } /// Projected mempool blocks /// /// Get projected blocks from the mempool for fee estimation. Each block contains statistics about transactions that would be included if a block were mined now. - pub fn get_api_v1_fees_mempool_blocks(&self) -> Result> { + pub fn get_v1_fees_mempool_blocks(&self) -> Result> { self.base.get(&format!("/api/v1/fees/mempool-blocks")) } /// Recommended fees /// /// Get recommended fee rates for different confirmation targets based on current mempool state. - pub fn get_api_v1_fees_recommended(&self) -> Result { + pub fn get_v1_fees_recommended(&self) -> Result { self.base.get(&format!("/api/v1/fees/recommended")) } /// Block fees /// /// Get average block fees for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y - pub fn get_api_v1_mining_blocks_fees_by_time_period(&self, time_period: &str) -> Result> { + pub fn get_v1_mining_blocks_fees_by_time_period(&self, time_period: &str) -> Result> { self.base.get(&format!("/api/v1/mining/blocks/fees/{time_period}")) } /// Block rewards /// /// Get average block rewards (coinbase = subsidy + fees) for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y - pub fn get_api_v1_mining_blocks_rewards_by_time_period(&self, time_period: &str) -> Result> { + pub fn get_v1_mining_blocks_rewards_by_time_period(&self, time_period: &str) -> Result> { self.base.get(&format!("/api/v1/mining/blocks/rewards/{time_period}")) } /// Block sizes and weights /// /// Get average block sizes and weights for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y - pub fn get_api_v1_mining_blocks_sizes_weights_by_time_period(&self, time_period: &str) -> Result { + pub fn get_v1_mining_blocks_sizes_weights_by_time_period(&self, time_period: &str) -> Result { self.base.get(&format!("/api/v1/mining/blocks/sizes-weights/{time_period}")) } /// Block by timestamp /// /// Find the block closest to a given UNIX timestamp. - pub fn get_api_v1_mining_blocks_timestamp_by_timestamp(&self, timestamp: &str) -> Result { + pub fn get_v1_mining_blocks_timestamp(&self, timestamp: &str) -> Result { self.base.get(&format!("/api/v1/mining/blocks/timestamp/{timestamp}")) } /// Difficulty adjustments (all time) /// /// Get historical difficulty adjustments. Returns array of [timestamp, height, difficulty, change_percent]. - pub fn get_api_v1_mining_difficulty_adjustments(&self) -> Result> { + pub fn get_v1_mining_difficulty_adjustments(&self) -> Result> { self.base.get(&format!("/api/v1/mining/difficulty-adjustments")) } /// Difficulty adjustments /// /// Get historical difficulty adjustments for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y. Returns array of [timestamp, height, difficulty, change_percent]. - pub fn get_api_v1_mining_difficulty_adjustments_by_time_period(&self, time_period: &str) -> Result> { + pub fn get_v1_mining_difficulty_adjustments_by_time_period(&self, time_period: &str) -> Result> { self.base.get(&format!("/api/v1/mining/difficulty-adjustments/{time_period}")) } /// Network hashrate (all time) /// /// Get network hashrate and difficulty data for all time. - pub fn get_api_v1_mining_hashrate(&self) -> Result { + pub fn get_v1_mining_hashrate(&self) -> Result { self.base.get(&format!("/api/v1/mining/hashrate")) } /// Network hashrate /// /// Get network hashrate and difficulty data for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y - pub fn get_api_v1_mining_hashrate_by_time_period(&self, time_period: &str) -> Result { + pub fn get_v1_mining_hashrate_by_time_period(&self, time_period: &str) -> Result { self.base.get(&format!("/api/v1/mining/hashrate/{time_period}")) } /// Mining pool details /// /// Get detailed information about a specific mining pool including block counts and shares for different time periods. - pub fn get_api_v1_mining_pool_by_slug(&self, slug: &str) -> Result { + pub fn get_v1_mining_pool_by_slug(&self, slug: &str) -> Result { self.base.get(&format!("/api/v1/mining/pool/{slug}")) } /// List all mining pools /// /// Get list of all known mining pools with their identifiers. - pub fn get_api_v1_mining_pools(&self) -> Result> { + pub fn get_v1_mining_pools(&self) -> Result> { self.base.get(&format!("/api/v1/mining/pools")) } /// Mining pool statistics /// /// Get mining pool statistics for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y - pub fn get_api_v1_mining_pools_by_time_period(&self, time_period: &str) -> Result { + pub fn get_v1_mining_pools_by_time_period(&self, time_period: &str) -> Result { self.base.get(&format!("/api/v1/mining/pools/{time_period}")) } /// Mining reward statistics /// /// Get mining reward statistics for the last N blocks including total rewards, fees, and transaction count. - pub fn get_api_v1_mining_reward_stats_by_block_count(&self, block_count: &str) -> Result { + pub fn get_v1_mining_reward_stats_by_block_count(&self, block_count: &str) -> Result { self.base.get(&format!("/api/v1/mining/reward-stats/{block_count}")) } /// Validate address /// /// Validate a Bitcoin address and get information about its type and scriptPubKey. - pub fn get_api_v1_validate_address_by_address(&self, address: &str) -> Result { + pub fn get_v1_validate_address(&self, address: &str) -> Result { self.base.get(&format!("/api/v1/validate-address/{address}")) } diff --git a/crates/brk_computer/src/cointime.rs b/crates/brk_computer/src/cointime.rs index c44f86e80..c2f9e6851 100644 --- a/crates/brk_computer/src/cointime.rs +++ b/crates/brk_computer/src/cointime.rs @@ -111,6 +111,7 @@ impl Vecs { v0, indexes, true, + price, )? }; } diff --git a/crates/brk_computer/src/grouped/ratio_from_dateindex.rs b/crates/brk_computer/src/grouped/ratio_from_dateindex.rs index 8d2fbcf7b..36d571e3e 100644 --- a/crates/brk_computer/src/grouped/ratio_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/ratio_from_dateindex.rs @@ -55,6 +55,7 @@ impl ComputedRatioVecsFromDateIndex { version: Version, indexes: &indexes::Vecs, extended: bool, + price_vecs: Option<&price::Vecs>, ) -> Result { let opts = VecBuilderOptions::default().add_last(); let v = version + VERSION; @@ -88,7 +89,7 @@ impl ComputedRatioVecsFromDateIndex { v, indexes, StandardDeviationVecsOptions::default().add_all(), - price.as_ref(), + price_vecs, ) .unwrap() }; diff --git a/crates/brk_computer/src/grouped/sd_from_dateindex.rs b/crates/brk_computer/src/grouped/sd_from_dateindex.rs index ecfa4056d..ff6079d7f 100644 --- a/crates/brk_computer/src/grouped/sd_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/sd_from_dateindex.rs @@ -2,16 +2,16 @@ use std::mem; use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Date, DateIndex, Dollars, StoredF32, Version}; +use brk_types::{Close, Date, DateIndex, Dollars, StoredF32, Version}; use vecdb::{ AnyStoredVec, AnyVec, CollectableVec, Database, EagerVec, Exit, GenericStoredVec, IterableVec, PcoVec, VecIndex, }; -use crate::{Indexes, grouped::source::Source, indexes, utils::OptionExt}; +use crate::{Indexes, grouped::source::Source, indexes, price, utils::OptionExt}; use super::{ - ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, PriceTimesRatio, VecBuilderOptions, + ClosePriceTimesRatio, ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, VecBuilderOptions, }; #[derive(Clone, Traversable)] @@ -37,19 +37,19 @@ pub struct ComputedStandardDeviationVecsFromDateIndex { pub m2_5sd: Option>, pub m3sd: Option>, - pub _0sd_usd: Option>, - pub p0_5sd_usd: Option>, - pub p1sd_usd: Option>, - pub p1_5sd_usd: Option>, - pub p2sd_usd: Option>, - pub p2_5sd_usd: Option>, - pub p3sd_usd: Option>, - pub m0_5sd_usd: Option>, - pub m1sd_usd: Option>, - pub m1_5sd_usd: Option>, - pub m2sd_usd: Option>, - pub m2_5sd_usd: Option>, - pub m3sd_usd: Option>, + pub _0sd_usd: Option, StoredF32>>, + pub p0_5sd_usd: Option, StoredF32>>, + pub p1sd_usd: Option, StoredF32>>, + pub p1_5sd_usd: Option, StoredF32>>, + pub p2sd_usd: Option, StoredF32>>, + pub p2_5sd_usd: Option, StoredF32>>, + pub p3sd_usd: Option, StoredF32>>, + pub m0_5sd_usd: Option, StoredF32>>, + pub m1sd_usd: Option, StoredF32>>, + pub m1_5sd_usd: Option, StoredF32>>, + pub m2sd_usd: Option, StoredF32>>, + pub m2_5sd_usd: Option, StoredF32>>, + pub m3sd_usd: Option, StoredF32>>, } #[derive(Debug, Default)] @@ -106,7 +106,7 @@ impl ComputedStandardDeviationVecsFromDateIndex { parent_version: Version, indexes: &indexes::Vecs, options: StandardDeviationVecsOptions, - price: Option<&ComputedVecsFromDateIndex>, + price_vecs: Option<&price::Vecs>, ) -> Result { let opts = VecBuilderOptions::default().add_last(); let version = parent_version + Version::ONE; @@ -143,11 +143,12 @@ impl ComputedStandardDeviationVecsFromDateIndex { // Create lazy USD vecs from price and band sources macro_rules! lazy_usd { ($band:expr, $suffix:expr) => { - price + price_vecs + .map(|p| &p.timeindexes_to_price_close) .zip($band.as_ref()) .filter(|_| options.price_bands()) .map(|(p, b)| { - LazyVecsFrom2FromDateIndex::from_computed::( + LazyVecsFrom2FromDateIndex::from_computed::( &format!("{name}_{}", $suffix), version, p, diff --git a/crates/brk_computer/src/grouped/transforms.rs b/crates/brk_computer/src/grouped/transforms.rs index 7835ceef1..ce142bb30 100644 --- a/crates/brk_computer/src/grouped/transforms.rs +++ b/crates/brk_computer/src/grouped/transforms.rs @@ -135,6 +135,17 @@ impl BinaryTransform for PriceTimesRatio { } } +/// Close * StoredF32 -> Dollars (price × ratio) +/// Same as PriceTimesRatio but accepts Close price source. +pub struct ClosePriceTimesRatio; + +impl BinaryTransform, StoredF32, Dollars> for ClosePriceTimesRatio { + #[inline(always)] + fn apply(price: Close, ratio: StoredF32) -> Dollars { + *price * ratio + } +} + /// Close * Sats -> Dollars (price × sats / 1e8) /// Same as PriceTimesSats but accepts Close price source. pub struct ClosePriceTimesSats; diff --git a/crates/brk_computer/src/market/import.rs b/crates/brk_computer/src/market/import.rs index ad4325d0d..db6f666ac 100644 --- a/crates/brk_computer/src/market/import.rs +++ b/crates/brk_computer/src/market/import.rs @@ -65,6 +65,7 @@ impl Vecs { version + v0, indexes, true, + price, )? }; } diff --git a/crates/brk_computer/src/stateful/metrics/realized.rs b/crates/brk_computer/src/stateful/metrics/realized.rs index 6f9b4dd34..eb96fd297 100644 --- a/crates/brk_computer/src/stateful/metrics/realized.rs +++ b/crates/brk_computer/src/stateful/metrics/realized.rs @@ -258,6 +258,7 @@ impl RealizedMetrics { cfg.version + v0, cfg.indexes, extended, + cfg.price, )?, indexes_to_realized_price, indexes_to_realized_cap_rel_to_own_market_cap: extended diff --git a/crates/brk_server/src/lib.rs b/crates/brk_server/src/lib.rs index b8fa7b7f0..52b673ce1 100644 --- a/crates/brk_server/src/lib.rs +++ b/crates/brk_server/src/lib.rs @@ -143,7 +143,7 @@ impl Server { let output_paths = brk_binder::ClientOutputPaths::new() .rust(workspace_root.join("crates/brk_client/src/lib.rs")) .javascript(workspace_root.join("modules/brk-client/index.js")) - .python(workspace_root.join("packages/brk_client/__init__.py")); + .python(workspace_root.join("packages/brk_client/brk_client/__init__.py")); let openapi_json = Arc::new(serde_json::to_string(&openapi).unwrap()); let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {