diff --git a/crates/brk_binder/src/javascript.rs b/crates/brk_binder/src/javascript.rs index 6b93e5c5d..bc4ab03b9 100644 --- a/crates/brk_binder/src/javascript.rs +++ b/crates/brk_binder/src/javascript.rs @@ -67,12 +67,26 @@ fn update_package_json_version(package_json_path: &Path) -> io::Result<()> { Ok(()) } +/// Convert only top-level object keys to camelCase (for consistency with tree field names) +/// Nested values (including id fields) are left unchanged for URL paths +fn camel_case_top_level_keys(value: Value) -> Value { + match value { + Value::Object(map) => { + let new_map: serde_json::Map = map + .into_iter() + .map(|(k, v)| (to_camel_case(&k), v)) + .collect(); + Value::Object(new_map) + } + other => other, + } +} + fn generate_static_constants(output: &mut String) { use serde::Serialize; - fn static_const(output: &mut String, name: &str, value: &T) { + fn instance_const(output: &mut String, name: &str, value: &T) { let json = serde_json::to_string_pretty(value).unwrap(); - // Indent the JSON for proper formatting inside the class let indented = json .lines() .enumerate() @@ -87,23 +101,23 @@ fn generate_static_constants(output: &mut String) { .join("\n"); writeln!( output, - " static {} = /** @type {{const}} */ ({});\n", + " {} = /** @type {{const}} */ ({});\n", name, indented ) .unwrap(); } - fn static_const_raw(output: &mut String, name: &str, value: &str) { - writeln!(output, " static {} = {};\n", name, value).unwrap(); + fn instance_const_raw(output: &mut String, name: &str, value: &str) { + writeln!(output, " {} = {};\n", name, value).unwrap(); } // VERSION - static_const_raw(output, "VERSION", &format!("\"v{}\"", VERSION)); + instance_const_raw(output, "VERSION", &format!("\"v{}\"", VERSION)); // INDEXES let indexes = Index::all(); let indexes_json: Vec<&'static str> = indexes.iter().map(|i| i.serialize_long()).collect(); - static_const(output, "INDEXES", &indexes_json); + instance_const(output, "INDEXES", &indexes_json); // POOL_ID_TO_POOL_NAME let pools = pools(); @@ -111,19 +125,43 @@ fn generate_static_constants(output: &mut String) { sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); let pool_map: std::collections::BTreeMap = sorted_pools.iter().map(|p| (p.slug(), p.name)).collect(); - static_const(output, "POOL_ID_TO_POOL_NAME", &pool_map); + instance_const(output, "POOL_ID_TO_POOL_NAME", &pool_map); - // Cohort names - static_const(output, "TERM_NAMES", &TERM_NAMES); - static_const(output, "EPOCH_NAMES", &EPOCH_NAMES); - static_const(output, "YEAR_NAMES", &YEAR_NAMES); - static_const(output, "SPENDABLE_TYPE_NAMES", &SPENDABLE_TYPE_NAMES); - static_const(output, "AGE_RANGE_NAMES", &AGE_RANGE_NAMES); - static_const(output, "MAX_AGE_NAMES", &MAX_AGE_NAMES); - static_const(output, "MIN_AGE_NAMES", &MIN_AGE_NAMES); - static_const(output, "AMOUNT_RANGE_NAMES", &AMOUNT_RANGE_NAMES); - static_const(output, "GE_AMOUNT_NAMES", &GE_AMOUNT_NAMES); - static_const(output, "LT_AMOUNT_NAMES", <_AMOUNT_NAMES); + // Cohort names - top-level keys converted to camelCase to match tree field names + fn instance_const_camel(output: &mut String, name: &str, value: &T) { + let json_value: Value = serde_json::to_value(value).unwrap(); + let camel_value = camel_case_top_level_keys(json_value); + let json = serde_json::to_string_pretty(&camel_value).unwrap(); + let indented = json + .lines() + .enumerate() + .map(|(i, line)| { + if i == 0 { + line.to_string() + } else { + format!(" {}", line) + } + }) + .collect::>() + .join("\n"); + writeln!( + output, + " {} = /** @type {{const}} */ ({});\n", + name, indented + ) + .unwrap(); + } + + instance_const_camel(output, "TERM_NAMES", &TERM_NAMES); + instance_const_camel(output, "EPOCH_NAMES", &EPOCH_NAMES); + instance_const_camel(output, "YEAR_NAMES", &YEAR_NAMES); + instance_const_camel(output, "SPENDABLE_TYPE_NAMES", &SPENDABLE_TYPE_NAMES); + instance_const_camel(output, "AGE_RANGE_NAMES", &AGE_RANGE_NAMES); + instance_const_camel(output, "MAX_AGE_NAMES", &MAX_AGE_NAMES); + instance_const_camel(output, "MIN_AGE_NAMES", &MIN_AGE_NAMES); + instance_const_camel(output, "AMOUNT_RANGE_NAMES", &AMOUNT_RANGE_NAMES); + instance_const_camel(output, "GE_AMOUNT_NAMES", &GE_AMOUNT_NAMES); + instance_const_camel(output, "LT_AMOUNT_NAMES", <_AMOUNT_NAMES); } fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) { diff --git a/crates/brk_binder/src/js.rs b/crates/brk_binder/src/js.rs deleted file mode 100644 index 8fa6a2d84..000000000 --- a/crates/brk_binder/src/js.rs +++ /dev/null @@ -1,240 +0,0 @@ -use std::{ - collections::{BTreeMap, HashMap}, - fs, io, - path::Path, -}; - -use brk_query::Query; -use brk_types::{Index, pools}; - -use crate::VERSION; - -const AUTO_GENERATED_DISCLAIMER: &str = "// -// File auto-generated, any modifications will be overwritten -//"; - -pub fn generate_js_files(query: &Query, modules_path: &Path) -> io::Result<()> { - let path = modules_path.join("brk-client"); - - if !fs::exists(&path)? { - return Ok(()); - } - - let path = path.join("generated"); - fs::create_dir_all(&path)?; - - generate_version_file(&path)?; - generate_metrics_file(query, &path)?; - generate_pools_file(&path) -} - -fn generate_version_file(parent: &Path) -> io::Result<()> { - let path = parent.join(Path::new("version.js")); - - let contents = format!( - "{AUTO_GENERATED_DISCLAIMER} - -export const VERSION = \"v{VERSION}\"; -" - ); - - fs::write(path, contents) -} - -fn generate_pools_file(parent: &Path) -> io::Result<()> { - let path = parent.join(Path::new("pools.js")); - - let pools = pools(); - - let mut contents = format!("{AUTO_GENERATED_DISCLAIMER}\n"); - - contents += " -/** - * @typedef {typeof POOL_ID_TO_POOL_NAME} PoolIdToPoolName - * @typedef {keyof PoolIdToPoolName} PoolId - */ - -export const POOL_ID_TO_POOL_NAME = /** @type {const} */ ({ -"; - - let mut sorted_pools: Vec<_> = pools.iter().collect(); - sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); - - contents += &sorted_pools - .iter() - .map(|pool| { - let slug = pool.slug(); - format!(" {slug}: \"{}\",", pool.name) - }) - .collect::>() - .join("\n"); - - contents += "\n});\n"; - - fs::write(path, contents) -} - -fn generate_metrics_file(query: &Query, parent: &Path) -> io::Result<()> { - let path = parent.join(Path::new("metrics.js")); - - let indexes = Index::all(); - - let mut contents = format!( - "{AUTO_GENERATED_DISCLAIMER} - -export const INDEXES = /** @type {{const}} */ ([ -{} -]); - -/** - * @typedef {{typeof INDEXES[number]}} IndexName - */ -", - indexes - .iter() - .map(|i| format!(" \"{}\"", i.serialize_long())) - .collect::>() - .join(",\n") - ); - - // contents += &indexes - // .iter() - // .map(|i| format!(" * @typedef {{\"{}\"}} {i}", i.serialize_long())) - // .collect::>() - // .join("\n"); - - // contents += &format!( - // " - // * @typedef {{{}}} Index - // */ - // ", - // indexes - // .iter() - // .map(|i| i.to_string()) - // .collect::>() - // .join(" | ") - // ); - - let mut unique_index_groups = BTreeMap::new(); - - let mut word_to_freq: BTreeMap<_, usize> = BTreeMap::new(); - query.metric_to_index_to_vec().keys().for_each(|metric| { - metric.split("_").for_each(|word| { - *word_to_freq.entry(word).or_default() += 1; - }); - }); - let mut word_to_freq = word_to_freq.into_iter().collect::>(); - word_to_freq.sort_unstable_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(b.0))); - let words = word_to_freq - .into_iter() - .map(|(str, _)| str) - .collect::>(); - - contents += &format!( - " -export const INDEX_TO_WORD = [ - {} -]; - -", - words - .iter() - .enumerate() - .map(|(index, word)| format!("\"{word}\", // {}", index_to_letters(index))) - .collect::>() - .join("\n ") - ); - - let word_to_base62 = words - .into_iter() - .enumerate() - .map(|(i, w)| (w, index_to_letters(i))) - .collect::>(); - - let mut ser_metric_to_indexes = " -/** @type {Record} */ -export const COMPRESSED_METRIC_TO_INDEXES = { -" - .to_string(); - - query - .metric_to_index_to_vec() - .iter() - .for_each(|(metric, index_to_vec)| { - let indexes = index_to_vec - .keys() - .map(|i| format!("\"{}\"", i.serialize_long())) - .collect::>() - .join(", "); - let indexes = format!("[{indexes}]"); - let unique = unique_index_groups.len(); - let index = index_to_letters(*unique_index_groups.entry(indexes).or_insert(unique)); - - let compressed_metric = metric.split('_').fold(String::new(), |mut acc, w| { - if !acc.is_empty() { - acc.push('_'); - } - acc.push_str(&word_to_base62[w]); - acc - }); - - ser_metric_to_indexes += &format!(" {compressed_metric}: {index},\n"); - }); - - ser_metric_to_indexes += "}; -"; - - let mut sorted_groups: Vec<_> = unique_index_groups.into_iter().collect(); - sorted_groups.sort_by_key(|(_, index)| *index); - sorted_groups.into_iter().for_each(|(group, index)| { - let index = index_to_letters(index); - contents += &format!("/** @type {{IndexName[]}} */\nconst {index} = {group};\n"); - }); - - contents += &ser_metric_to_indexes; - - fs::write(path, contents) -} - -fn index_to_letters(mut index: usize) -> String { - if index < 52 { - return (index_to_char(index) as char).to_string(); - } - let mut result = [0u8; 8]; - let mut pos = 8; - loop { - pos -= 1; - result[pos] = index_to_char(index % 52); - index /= 52; - if index == 0 { - break; - } - index -= 1; - } - unsafe { String::from_utf8_unchecked(result[pos..].to_vec()) } -} - -fn index_to_char(index: usize) -> u8 { - match index { - 0..=25 => b'A' + index as u8, - 26..=51 => b'a' + (index - 26) as u8, - _ => unreachable!(), - } -} - -// fn letters_to_index(s: &str) -> usize { -// let mut result = 0; -// for byte in s.bytes() { -// let value = char_to_index(byte) as usize; -// result = result * 52 + value + 1; -// } -// result - 1 -// } - -// fn char_to_index(byte: u8) -> u8 { -// match byte { -// b'A'..=b'Z' => byte - b'A', -// b'a'..=b'z' => byte - b'a' + 26, -// _ => 255, // Invalid -// } -// } diff --git a/crates/brk_binder/src/rust.rs b/crates/brk_binder/src/rust.rs index 56bbad200..f5161314d 100644 --- a/crates/brk_binder/src/rust.rs +++ b/crates/brk_binder/src/rust.rs @@ -23,7 +23,8 @@ pub fn generate_rust_client( writeln!(output, "#![allow(non_camel_case_types)]").unwrap(); writeln!(output, "#![allow(dead_code)]").unwrap(); writeln!(output, "#![allow(unused_variables)]").unwrap(); - writeln!(output, "#![allow(clippy::useless_format)]\n").unwrap(); + writeln!(output, "#![allow(clippy::useless_format)]").unwrap(); + writeln!(output, "#![allow(clippy::unnecessary_to_owned)]\n").unwrap(); generate_imports(&mut output); generate_base_client(&mut output); diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 0f078a38f..8961ee7ca 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -5,6 +5,7 @@ #![allow(dead_code)] #![allow(unused_variables)] #![allow(clippy::useless_format)] +#![allow(clippy::unnecessary_to_owned)] use std::sync::Arc; use serde::de::DeserializeOwned; @@ -285,13 +286,13 @@ impl Indexes28 { } /// Index accessor for metrics with 3 indexes. -pub struct Indexes15 { +pub struct Indexes23 { pub by_quarterindex: MetricNode, pub by_semesterindex: MetricNode, pub by_yearindex: MetricNode, } -impl Indexes15 { +impl Indexes23 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_quarterindex: MetricNode::new(client.clone(), format!("{base_path}/quarterindex")), @@ -317,12 +318,12 @@ impl Indexes13 { } /// Index accessor for metrics with 2 indexes. -pub struct Indexes14 { +pub struct Indexes22 { pub by_monthindex: MetricNode, pub by_weekindex: MetricNode, } -impl Indexes14 { +impl Indexes22 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_monthindex: MetricNode::new(client.clone(), format!("{base_path}/monthindex")), @@ -449,11 +450,11 @@ impl Indexes12 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes16 { +pub struct Indexes14 { pub by_p2aaddressindex: MetricNode, } -impl Indexes16 { +impl Indexes14 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2aaddressindex: MetricNode::new(client.clone(), format!("{base_path}/p2aaddressindex")), @@ -462,11 +463,11 @@ impl Indexes16 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes17 { +pub struct Indexes15 { pub by_p2pk33addressindex: MetricNode, } -impl Indexes17 { +impl Indexes15 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2pk33addressindex: MetricNode::new(client.clone(), format!("{base_path}/p2pk33addressindex")), @@ -475,11 +476,11 @@ impl Indexes17 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes18 { +pub struct Indexes16 { pub by_p2pk65addressindex: MetricNode, } -impl Indexes18 { +impl Indexes16 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2pk65addressindex: MetricNode::new(client.clone(), format!("{base_path}/p2pk65addressindex")), @@ -488,11 +489,11 @@ impl Indexes18 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes19 { +pub struct Indexes17 { pub by_p2pkhaddressindex: MetricNode, } -impl Indexes19 { +impl Indexes17 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2pkhaddressindex: MetricNode::new(client.clone(), format!("{base_path}/p2pkhaddressindex")), @@ -501,11 +502,11 @@ impl Indexes19 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes20 { +pub struct Indexes18 { pub by_p2shaddressindex: MetricNode, } -impl Indexes20 { +impl Indexes18 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2shaddressindex: MetricNode::new(client.clone(), format!("{base_path}/p2shaddressindex")), @@ -514,11 +515,11 @@ impl Indexes20 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes21 { +pub struct Indexes19 { pub by_p2traddressindex: MetricNode, } -impl Indexes21 { +impl Indexes19 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2traddressindex: MetricNode::new(client.clone(), format!("{base_path}/p2traddressindex")), @@ -527,11 +528,11 @@ impl Indexes21 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes22 { +pub struct Indexes20 { pub by_p2wpkhaddressindex: MetricNode, } -impl Indexes22 { +impl Indexes20 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2wpkhaddressindex: MetricNode::new(client.clone(), format!("{base_path}/p2wpkhaddressindex")), @@ -540,11 +541,11 @@ impl Indexes22 { } /// Index accessor for metrics with 1 indexes. -pub struct Indexes23 { +pub struct Indexes21 { pub by_p2wshaddressindex: MetricNode, } -impl Indexes23 { +impl Indexes21 { pub fn new(client: Arc, base_path: &str) -> Self { Self { by_p2wshaddressindex: MetricNode::new(client.clone(), format!("{base_path}/p2wshaddressindex")), @@ -1224,27 +1225,27 @@ 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 p2a: Indexes14, + pub p2pk33: Indexes15, + pub p2pk65: Indexes16, + pub p2pkh: Indexes17, + pub p2sh: Indexes18, + pub p2tr: Indexes19, + pub p2wpkh: Indexes20, + pub p2wsh: Indexes21, } 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")), + p2a: Indexes14::new(client.clone(), &format!("{base_path}_p2a")), + p2pk33: Indexes15::new(client.clone(), &format!("{base_path}_p2pk33")), + p2pk65: Indexes16::new(client.clone(), &format!("{base_path}_p2pk65")), + p2pkh: Indexes17::new(client.clone(), &format!("{base_path}_p2pkh")), + p2sh: Indexes18::new(client.clone(), &format!("{base_path}_p2sh")), + p2tr: Indexes19::new(client.clone(), &format!("{base_path}_p2tr")), + p2wpkh: Indexes20::new(client.clone(), &format!("{base_path}_p2wpkh")), + p2wsh: Indexes21::new(client.clone(), &format!("{base_path}_p2wsh")), } } } @@ -1399,6 +1400,27 @@ impl _10yTo12yPattern { } } +/// Pattern struct for repeated tree structure. +pub struct ActivityPattern { + pub coinblocks_destroyed: BlockCountPattern, + pub coindays_destroyed: BlockCountPattern, + pub satblocks_destroyed: Indexes2, + pub satdays_destroyed: Indexes2, + pub sent: FeePattern2, +} + +impl ActivityPattern { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + coinblocks_destroyed: BlockCountPattern::new(client.clone(), &format!("{base_path}_coinblocks_destroyed")), + coindays_destroyed: BlockCountPattern::new(client.clone(), &format!("{base_path}_coindays_destroyed")), + satblocks_destroyed: Indexes2::new(client.clone(), &format!("{base_path}_satblocks_destroyed")), + satdays_destroyed: Indexes2::new(client.clone(), &format!("{base_path}_satdays_destroyed")), + sent: FeePattern2::new(client.clone(), &format!("{base_path}_sent")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct SupplyPattern2 { pub supply: SupplyPattern, @@ -1421,22 +1443,20 @@ impl SupplyPattern2 { } /// Pattern struct for repeated tree structure. -pub struct ActivityPattern { - pub coinblocks_destroyed: BlockCountPattern, - pub coindays_destroyed: BlockCountPattern, - pub satblocks_destroyed: Indexes2, - pub satdays_destroyed: Indexes2, - pub sent: FeePattern2, +pub struct SupplyPattern { + pub base: Indexes2, + pub bitcoin: Indexes, + pub dollars: Indexes, + pub sats: Indexes, } -impl ActivityPattern { +impl SupplyPattern { pub fn new(client: Arc, base_path: &str) -> Self { Self { - coinblocks_destroyed: BlockCountPattern::new(client.clone(), &format!("{base_path}_coinblocks_destroyed")), - coindays_destroyed: BlockCountPattern::new(client.clone(), &format!("{base_path}_coindays_destroyed")), - satblocks_destroyed: Indexes2::new(client.clone(), &format!("{base_path}_satblocks_destroyed")), - satdays_destroyed: Indexes2::new(client.clone(), &format!("{base_path}_satdays_destroyed")), - sent: FeePattern2::new(client.clone(), &format!("{base_path}_sent")), + base: Indexes2::new(client.clone(), &format!("{base_path}_base")), + bitcoin: Indexes::new(client.clone(), &format!("{base_path}_bitcoin")), + dollars: Indexes::new(client.clone(), &format!("{base_path}_dollars")), + sats: Indexes::new(client.clone(), &format!("{base_path}_sats")), } } } @@ -1461,20 +1481,18 @@ impl FeePattern2 { } /// Pattern struct for repeated tree structure. -pub struct SupplyPattern { - pub base: Indexes2, - pub bitcoin: Indexes, - pub dollars: Indexes, - pub sats: Indexes, +pub struct PricePaidPattern2 { + pub max_price_paid: Indexes3, + pub min_price_paid: Indexes3, + pub price_percentiles: PricePercentilesPattern, } -impl SupplyPattern { +impl PricePaidPattern2 { pub fn new(client: Arc, base_path: &str) -> Self { Self { - base: Indexes2::new(client.clone(), &format!("{base_path}_base")), - bitcoin: Indexes::new(client.clone(), &format!("{base_path}_bitcoin")), - dollars: Indexes::new(client.clone(), &format!("{base_path}_dollars")), - sats: Indexes::new(client.clone(), &format!("{base_path}_sats")), + max_price_paid: Indexes3::new(client.clone(), &format!("{base_path}_max_price_paid")), + min_price_paid: Indexes3::new(client.clone(), &format!("{base_path}_min_price_paid")), + price_percentiles: PricePercentilesPattern::new(client.clone(), &format!("{base_path}_price_percentiles")), } } } @@ -1530,23 +1548,6 @@ impl ActiveSupplyPattern { } } -/// Pattern struct for repeated tree structure. -pub struct PricePaidPattern2 { - pub max_price_paid: Indexes3, - pub min_price_paid: Indexes3, - pub price_percentiles: PricePercentilesPattern, -} - -impl PricePaidPattern2 { - pub fn new(client: Arc, base_path: &str) -> Self { - Self { - max_price_paid: Indexes3::new(client.clone(), &format!("{base_path}_max_price_paid")), - min_price_paid: Indexes3::new(client.clone(), &format!("{base_path}_min_price_paid")), - price_percentiles: PricePercentilesPattern::new(client.clone(), &format!("{base_path}_price_percentiles")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct BlockCountPattern { pub base: Indexes2, @@ -1564,6 +1565,21 @@ impl BlockCountPattern { } } +/// Pattern struct for repeated tree structure. +pub struct SatsPattern { + pub cumulative: Indexes3, + pub sum: Indexes4, +} + +impl SatsPattern { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + cumulative: Indexes3::new(client.clone(), &format!("{base_path}_cumulative")), + sum: Indexes4::new(client.clone(), &format!("{base_path}_sum")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct SupplyValuePattern { pub bitcoin: Indexes2, @@ -1610,21 +1626,6 @@ impl _1dReturns1mSdPattern { } } -/// Pattern struct for repeated tree structure. -pub struct SatsPattern { - pub cumulative: Indexes3, - pub sum: Indexes4, -} - -impl SatsPattern { - pub fn new(client: Arc, base_path: &str) -> Self { - Self { - cumulative: Indexes3::new(client.clone(), &format!("{base_path}_cumulative")), - sum: Indexes4::new(client.clone(), &format!("{base_path}_sum")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct BitcoinPattern2 { pub base: Indexes2, @@ -1720,36 +1721,121 @@ impl CatalogTree_Computed_Blks { /// Catalog tree node. pub struct CatalogTree_Computed_Chain { + pub block: CatalogTree_Computed_Chain_Block, + pub coinbase: CatalogTree_Computed_Chain_Coinbase, + pub epoch: CatalogTree_Computed_Chain_Epoch, + pub mining: CatalogTree_Computed_Chain_Mining, + pub output_type: CatalogTree_Computed_Chain_OutputType, + pub transaction: CatalogTree_Computed_Chain_Transaction, + pub volume: CatalogTree_Computed_Chain_Volume, +} + +impl CatalogTree_Computed_Chain { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + block: CatalogTree_Computed_Chain_Block::new(client.clone(), &format!("{base_path}_block")), + coinbase: CatalogTree_Computed_Chain_Coinbase::new(client.clone(), &format!("{base_path}_coinbase")), + epoch: CatalogTree_Computed_Chain_Epoch::new(client.clone(), &format!("{base_path}_epoch")), + mining: CatalogTree_Computed_Chain_Mining::new(client.clone(), &format!("{base_path}_mining")), + output_type: CatalogTree_Computed_Chain_OutputType::new(client.clone(), &format!("{base_path}_output_type")), + transaction: CatalogTree_Computed_Chain_Transaction::new(client.clone(), &format!("{base_path}_transaction")), + volume: CatalogTree_Computed_Chain_Volume::new(client.clone(), &format!("{base_path}_volume")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_Block { pub _1m_block_count: Indexes, pub _1w_block_count: Indexes, pub _1y_block_count: Indexes, pub _24h_block_count: Indexes2, - pub _24h_coinbase_sum: Indexes2, - pub _24h_coinbase_usd_sum: Indexes2, - pub annualized_volume: Indexes, - pub annualized_volume_btc: Indexes, - pub annualized_volume_usd: Indexes, pub block_count: BlockCountPattern, pub block_count_target: Indexes, pub block_interval: BlockIntervalPattern, pub block_size: BlockSizePattern, pub block_vbytes: BlockSizePattern, pub block_weight: BlockSizePattern, + pub interval: Indexes2, + pub vbytes: Indexes2, +} + +impl CatalogTree_Computed_Chain_Block { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + _1m_block_count: Indexes::new(client.clone(), &format!("{base_path}_1m_block_count")), + _1w_block_count: Indexes::new(client.clone(), &format!("{base_path}_1w_block_count")), + _1y_block_count: Indexes::new(client.clone(), &format!("{base_path}_1y_block_count")), + _24h_block_count: Indexes2::new(client.clone(), &format!("{base_path}_24h_block_count")), + block_count: BlockCountPattern::new(client.clone(), &format!("{base_path}_block_count")), + block_count_target: Indexes::new(client.clone(), &format!("{base_path}_block_count_target")), + block_interval: BlockIntervalPattern::new(client.clone(), "block_interval"), + block_size: BlockSizePattern::new(client.clone(), &format!("{base_path}_block_size")), + block_vbytes: BlockSizePattern::new(client.clone(), &format!("{base_path}_block_vbytes")), + block_weight: BlockSizePattern::new(client.clone(), &format!("{base_path}_block_weight")), + interval: Indexes2::new(client.clone(), &format!("{base_path}_interval")), + vbytes: Indexes2::new(client.clone(), &format!("{base_path}_vbytes")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_Coinbase { + pub _24h_coinbase_sum: Indexes2, + pub _24h_coinbase_usd_sum: Indexes2, + pub coinbase: CoinbasePattern, + pub fee_dominance: Indexes5, + pub inflation_rate: Indexes, + pub puell_multiple: Indexes, + pub subsidy: CoinbasePattern, + pub subsidy_dominance: Indexes5, + pub subsidy_usd_1y_sma: Indexes, + pub unclaimed_rewards: UnclaimedRewardsPattern, +} + +impl CatalogTree_Computed_Chain_Coinbase { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + _24h_coinbase_sum: Indexes2::new(client.clone(), &format!("{base_path}_24h_coinbase_sum")), + _24h_coinbase_usd_sum: Indexes2::new(client.clone(), &format!("{base_path}_24h_coinbase_usd_sum")), + coinbase: CoinbasePattern::new(client.clone(), &format!("{base_path}_coinbase")), + fee_dominance: Indexes5::new(client.clone(), &format!("{base_path}_fee_dominance")), + inflation_rate: Indexes::new(client.clone(), &format!("{base_path}_inflation_rate")), + puell_multiple: Indexes::new(client.clone(), &format!("{base_path}_puell_multiple")), + subsidy: CoinbasePattern::new(client.clone(), &format!("{base_path}_subsidy")), + subsidy_dominance: Indexes5::new(client.clone(), &format!("{base_path}_subsidy_dominance")), + subsidy_usd_1y_sma: Indexes::new(client.clone(), &format!("{base_path}_subsidy_usd_1y_sma")), + unclaimed_rewards: UnclaimedRewardsPattern::new(client.clone(), &format!("{base_path}_unclaimed_rewards")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_Epoch { + pub difficultyepoch: Indexes, + pub halvingepoch: Indexes, + pub timestamp: MetricNode, +} + +impl CatalogTree_Computed_Chain_Epoch { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + difficultyepoch: Indexes::new(client.clone(), &format!("{base_path}_difficultyepoch")), + halvingepoch: Indexes::new(client.clone(), &format!("{base_path}_halvingepoch")), + timestamp: MetricNode::new(client.clone(), format!("{base_path}_timestamp")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_Mining { pub blocks_before_next_difficulty_adjustment: Indexes3, pub blocks_before_next_halving: Indexes3, - pub coinbase: CoinbasePattern, pub days_before_next_difficulty_adjustment: Indexes3, pub days_before_next_halving: Indexes3, pub difficulty: Indexes4, pub difficulty_adjustment: Indexes3, pub difficulty_as_hash: Indexes3, - pub difficultyepoch: Indexes, - pub emptyoutput_count: BitcoinPattern, - pub exact_utxo_count: Indexes3, - pub fee: CatalogTree_Computed_Chain_Fee, - pub fee_dominance: Indexes5, - pub fee_rate: CatalogTree_Computed_Chain_FeeRate, - pub halvingepoch: Indexes, pub hash_price_phs: Indexes3, pub hash_price_phs_min: Indexes3, pub hash_price_rebound: Indexes3, @@ -1765,80 +1851,18 @@ pub struct CatalogTree_Computed_Chain { pub hash_value_rebound: Indexes3, pub hash_value_ths: Indexes3, pub hash_value_ths_min: Indexes3, - pub inflation_rate: Indexes, - pub input_count: BlockSizePattern, - pub input_value: Indexes6, - pub inputs_per_sec: Indexes, - pub interval: Indexes2, - pub is_coinbase: Indexes6, - pub opreturn_count: BitcoinPattern, - pub output_count: BlockSizePattern, - pub output_value: Indexes6, - pub outputs_per_sec: Indexes, - pub p2a_count: BitcoinPattern, - pub p2ms_count: BitcoinPattern, - pub p2pk33_count: BitcoinPattern, - pub p2pk65_count: BitcoinPattern, - pub p2pkh_count: BitcoinPattern, - pub p2sh_count: BitcoinPattern, - pub p2tr_count: BitcoinPattern, - pub p2wpkh_count: BitcoinPattern, - pub p2wsh_count: BitcoinPattern, - pub puell_multiple: Indexes, - pub sent_sum: CatalogTree_Computed_Chain_SentSum, - pub subsidy: CoinbasePattern, - pub subsidy_dominance: Indexes5, - pub subsidy_usd_1y_sma: Indexes, - pub timestamp: MetricNode, - pub tx_btc_velocity: Indexes, - pub tx_count: BitcoinPattern, - pub tx_per_sec: Indexes, - pub tx_usd_velocity: Indexes, - pub tx_v1: BlockCountPattern, - pub tx_v2: BlockCountPattern, - pub tx_v3: BlockCountPattern, - pub tx_vsize: BlockIntervalPattern, - pub tx_weight: BlockIntervalPattern, - pub unclaimed_rewards: UnclaimedRewardsPattern, - pub unknownoutput_count: BitcoinPattern, - pub vbytes: Indexes2, - pub vsize: Indexes6, - pub weight: Indexes6, } -impl CatalogTree_Computed_Chain { +impl CatalogTree_Computed_Chain_Mining { pub fn new(client: Arc, base_path: &str) -> Self { Self { - _1m_block_count: Indexes::new(client.clone(), &format!("{base_path}_1m_block_count")), - _1w_block_count: Indexes::new(client.clone(), &format!("{base_path}_1w_block_count")), - _1y_block_count: Indexes::new(client.clone(), &format!("{base_path}_1y_block_count")), - _24h_block_count: Indexes2::new(client.clone(), &format!("{base_path}_24h_block_count")), - _24h_coinbase_sum: Indexes2::new(client.clone(), &format!("{base_path}_24h_coinbase_sum")), - _24h_coinbase_usd_sum: Indexes2::new(client.clone(), &format!("{base_path}_24h_coinbase_usd_sum")), - annualized_volume: Indexes::new(client.clone(), &format!("{base_path}_annualized_volume")), - annualized_volume_btc: Indexes::new(client.clone(), &format!("{base_path}_annualized_volume_btc")), - annualized_volume_usd: Indexes::new(client.clone(), &format!("{base_path}_annualized_volume_usd")), - block_count: BlockCountPattern::new(client.clone(), &format!("{base_path}_block_count")), - block_count_target: Indexes::new(client.clone(), &format!("{base_path}_block_count_target")), - block_interval: BlockIntervalPattern::new(client.clone(), "block_interval"), - block_size: BlockSizePattern::new(client.clone(), &format!("{base_path}_block_size")), - block_vbytes: BlockSizePattern::new(client.clone(), &format!("{base_path}_block_vbytes")), - block_weight: BlockSizePattern::new(client.clone(), &format!("{base_path}_block_weight")), blocks_before_next_difficulty_adjustment: Indexes3::new(client.clone(), &format!("{base_path}_blocks_before_next_difficulty_adjustment")), blocks_before_next_halving: Indexes3::new(client.clone(), &format!("{base_path}_blocks_before_next_halving")), - coinbase: CoinbasePattern::new(client.clone(), &format!("{base_path}_coinbase")), days_before_next_difficulty_adjustment: Indexes3::new(client.clone(), &format!("{base_path}_days_before_next_difficulty_adjustment")), days_before_next_halving: Indexes3::new(client.clone(), &format!("{base_path}_days_before_next_halving")), difficulty: Indexes4::new(client.clone(), &format!("{base_path}_difficulty")), difficulty_adjustment: Indexes3::new(client.clone(), &format!("{base_path}_difficulty_adjustment")), difficulty_as_hash: Indexes3::new(client.clone(), &format!("{base_path}_difficulty_as_hash")), - difficultyepoch: Indexes::new(client.clone(), &format!("{base_path}_difficultyepoch")), - emptyoutput_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_emptyoutput_count")), - exact_utxo_count: Indexes3::new(client.clone(), &format!("{base_path}_exact_utxo_count")), - fee: CatalogTree_Computed_Chain_Fee::new(client.clone(), &format!("{base_path}_fee")), - fee_dominance: Indexes5::new(client.clone(), &format!("{base_path}_fee_dominance")), - fee_rate: CatalogTree_Computed_Chain_FeeRate::new(client.clone(), &format!("{base_path}_fee_rate")), - halvingepoch: Indexes::new(client.clone(), &format!("{base_path}_halvingepoch")), hash_price_phs: Indexes3::new(client.clone(), &format!("{base_path}_hash_price_phs")), hash_price_phs_min: Indexes3::new(client.clone(), &format!("{base_path}_hash_price_phs_min")), hash_price_rebound: Indexes3::new(client.clone(), &format!("{base_path}_hash_price_rebound")), @@ -1854,16 +1878,33 @@ impl CatalogTree_Computed_Chain { hash_value_rebound: Indexes3::new(client.clone(), &format!("{base_path}_hash_value_rebound")), hash_value_ths: Indexes3::new(client.clone(), &format!("{base_path}_hash_value_ths")), hash_value_ths_min: Indexes3::new(client.clone(), &format!("{base_path}_hash_value_ths_min")), - inflation_rate: Indexes::new(client.clone(), &format!("{base_path}_inflation_rate")), - input_count: BlockSizePattern::new(client.clone(), &format!("{base_path}_input_count")), - input_value: Indexes6::new(client.clone(), &format!("{base_path}_input_value")), - inputs_per_sec: Indexes::new(client.clone(), &format!("{base_path}_inputs_per_sec")), - interval: Indexes2::new(client.clone(), &format!("{base_path}_interval")), - is_coinbase: Indexes6::new(client.clone(), &format!("{base_path}_is_coinbase")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_OutputType { + pub emptyoutput_count: BitcoinPattern, + pub exact_utxo_count: Indexes3, + pub opreturn_count: BitcoinPattern, + pub p2a_count: BitcoinPattern, + pub p2ms_count: BitcoinPattern, + pub p2pk33_count: BitcoinPattern, + pub p2pk65_count: BitcoinPattern, + pub p2pkh_count: BitcoinPattern, + pub p2sh_count: BitcoinPattern, + pub p2tr_count: BitcoinPattern, + pub p2wpkh_count: BitcoinPattern, + pub p2wsh_count: BitcoinPattern, + pub unknownoutput_count: BitcoinPattern, +} + +impl CatalogTree_Computed_Chain_OutputType { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + emptyoutput_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_emptyoutput_count")), + exact_utxo_count: Indexes3::new(client.clone(), &format!("{base_path}_exact_utxo_count")), opreturn_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_opreturn_count")), - output_count: BlockSizePattern::new(client.clone(), &format!("{base_path}_output_count")), - output_value: Indexes6::new(client.clone(), &format!("{base_path}_output_value")), - outputs_per_sec: Indexes::new(client.clone(), &format!("{base_path}_outputs_per_sec")), p2a_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_p2a_count")), p2ms_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_p2ms_count")), p2pk33_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_p2pk33_count")), @@ -1873,24 +1914,46 @@ impl CatalogTree_Computed_Chain { p2tr_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_p2tr_count")), p2wpkh_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_p2wpkh_count")), p2wsh_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_p2wsh_count")), - puell_multiple: Indexes::new(client.clone(), &format!("{base_path}_puell_multiple")), - sent_sum: CatalogTree_Computed_Chain_SentSum::new(client.clone(), &format!("{base_path}_sent_sum")), - subsidy: CoinbasePattern::new(client.clone(), &format!("{base_path}_subsidy")), - subsidy_dominance: Indexes5::new(client.clone(), &format!("{base_path}_subsidy_dominance")), - subsidy_usd_1y_sma: Indexes::new(client.clone(), &format!("{base_path}_subsidy_usd_1y_sma")), - timestamp: MetricNode::new(client.clone(), format!("{base_path}_timestamp")), - tx_btc_velocity: Indexes::new(client.clone(), &format!("{base_path}_tx_btc_velocity")), + unknownoutput_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_unknownoutput_count")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_Transaction { + pub fee: CatalogTree_Computed_Chain_Transaction_Fee, + pub fee_rate: CatalogTree_Computed_Chain_Transaction_FeeRate, + pub input_count: BlockSizePattern, + pub input_value: Indexes6, + pub is_coinbase: Indexes6, + pub output_count: BlockSizePattern, + pub output_value: Indexes6, + pub tx_count: BitcoinPattern, + pub tx_v1: BlockCountPattern, + pub tx_v2: BlockCountPattern, + pub tx_v3: BlockCountPattern, + pub tx_vsize: BlockIntervalPattern, + pub tx_weight: BlockIntervalPattern, + pub vsize: Indexes6, + pub weight: Indexes6, +} + +impl CatalogTree_Computed_Chain_Transaction { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + fee: CatalogTree_Computed_Chain_Transaction_Fee::new(client.clone(), &format!("{base_path}_fee")), + fee_rate: CatalogTree_Computed_Chain_Transaction_FeeRate::new(client.clone(), &format!("{base_path}_fee_rate")), + input_count: BlockSizePattern::new(client.clone(), &format!("{base_path}_input_count")), + input_value: Indexes6::new(client.clone(), &format!("{base_path}_input_value")), + is_coinbase: Indexes6::new(client.clone(), &format!("{base_path}_is_coinbase")), + output_count: BlockSizePattern::new(client.clone(), &format!("{base_path}_output_count")), + output_value: Indexes6::new(client.clone(), &format!("{base_path}_output_value")), tx_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_tx_count")), - tx_per_sec: Indexes::new(client.clone(), &format!("{base_path}_tx_per_sec")), - tx_usd_velocity: Indexes::new(client.clone(), &format!("{base_path}_tx_usd_velocity")), tx_v1: BlockCountPattern::new(client.clone(), &format!("{base_path}_tx_v1")), tx_v2: BlockCountPattern::new(client.clone(), &format!("{base_path}_tx_v2")), tx_v3: BlockCountPattern::new(client.clone(), &format!("{base_path}_tx_v3")), tx_vsize: BlockIntervalPattern::new(client.clone(), "tx_vsize"), tx_weight: BlockIntervalPattern::new(client.clone(), "tx_weight"), - unclaimed_rewards: UnclaimedRewardsPattern::new(client.clone(), &format!("{base_path}_unclaimed_rewards")), - unknownoutput_count: BitcoinPattern::new(client.clone(), &format!("{base_path}_unknownoutput_count")), - vbytes: Indexes2::new(client.clone(), &format!("{base_path}_vbytes")), vsize: Indexes6::new(client.clone(), &format!("{base_path}_vsize")), weight: Indexes6::new(client.clone(), &format!("{base_path}_weight")), } @@ -1898,7 +1961,7 @@ impl CatalogTree_Computed_Chain { } /// Catalog tree node. -pub struct CatalogTree_Computed_Chain_Fee { +pub struct CatalogTree_Computed_Chain_Transaction_Fee { pub base: Indexes6, pub bitcoin: BlockSizePattern, pub bitcoin_txindex: Indexes6, @@ -1907,7 +1970,7 @@ pub struct CatalogTree_Computed_Chain_Fee { pub sats: BlockSizePattern, } -impl CatalogTree_Computed_Chain_Fee { +impl CatalogTree_Computed_Chain_Transaction_Fee { pub fn new(client: Arc, base_path: &str) -> Self { Self { base: Indexes6::new(client.clone(), &format!("{base_path}_base")), @@ -1921,7 +1984,7 @@ impl CatalogTree_Computed_Chain_Fee { } /// Catalog tree node. -pub struct CatalogTree_Computed_Chain_FeeRate { +pub struct CatalogTree_Computed_Chain_Transaction_FeeRate { pub average: Indexes3, pub base: Indexes6, pub max: Indexes3, @@ -1933,7 +1996,7 @@ pub struct CatalogTree_Computed_Chain_FeeRate { pub pct90: Indexes2, } -impl CatalogTree_Computed_Chain_FeeRate { +impl CatalogTree_Computed_Chain_Transaction_FeeRate { pub fn new(client: Arc, base_path: &str) -> Self { Self { average: Indexes3::new(client.clone(), &format!("{base_path}_average")), @@ -1950,13 +2013,42 @@ impl CatalogTree_Computed_Chain_FeeRate { } /// Catalog tree node. -pub struct CatalogTree_Computed_Chain_SentSum { +pub struct CatalogTree_Computed_Chain_Volume { + pub annualized_volume: Indexes, + pub annualized_volume_btc: Indexes, + pub annualized_volume_usd: Indexes, + pub inputs_per_sec: Indexes, + pub outputs_per_sec: Indexes, + pub sent_sum: CatalogTree_Computed_Chain_Volume_SentSum, + pub tx_btc_velocity: Indexes, + pub tx_per_sec: Indexes, + pub tx_usd_velocity: Indexes, +} + +impl CatalogTree_Computed_Chain_Volume { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + annualized_volume: Indexes::new(client.clone(), &format!("{base_path}_annualized_volume")), + annualized_volume_btc: Indexes::new(client.clone(), &format!("{base_path}_annualized_volume_btc")), + annualized_volume_usd: Indexes::new(client.clone(), &format!("{base_path}_annualized_volume_usd")), + inputs_per_sec: Indexes::new(client.clone(), &format!("{base_path}_inputs_per_sec")), + outputs_per_sec: Indexes::new(client.clone(), &format!("{base_path}_outputs_per_sec")), + sent_sum: CatalogTree_Computed_Chain_Volume_SentSum::new(client.clone(), &format!("{base_path}_sent_sum")), + tx_btc_velocity: Indexes::new(client.clone(), &format!("{base_path}_tx_btc_velocity")), + tx_per_sec: Indexes::new(client.clone(), &format!("{base_path}_tx_per_sec")), + tx_usd_velocity: Indexes::new(client.clone(), &format!("{base_path}_tx_usd_velocity")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Chain_Volume_SentSum { pub bitcoin: BitcoinPattern2, pub dollars: Indexes3, pub sats: Indexes3, } -impl CatalogTree_Computed_Chain_SentSum { +impl CatalogTree_Computed_Chain_Volume_SentSum { pub fn new(client: Arc, base_path: &str) -> Self { Self { bitcoin: BitcoinPattern2::new(client.clone(), &format!("{base_path}_bitcoin")), @@ -2083,86 +2175,125 @@ impl CatalogTree_Computed_Fetched { /// Catalog tree node. pub struct CatalogTree_Computed_Indexes { - pub date: Indexes13, - pub date_fixed: Indexes2, - pub dateindex: Indexes13, - pub dateindex_count: Indexes14, - pub decadeindex: MetricNode, - pub difficultyepoch: MetricNode, - pub emptyoutputindex: MetricNode, - pub first_dateindex: Indexes14, - pub first_height: MetricNode, - pub first_monthindex: Indexes15, - pub first_yearindex: Indexes7, - pub halvingepoch: MetricNode, - pub height: Indexes2, - pub height_count: MetricNode, - pub input_count: Indexes6, - pub monthindex: MetricNode, - pub monthindex_count: Indexes15, - pub opreturnindex: MetricNode, - pub output_count: Indexes6, - pub p2aaddressindex: Indexes16, - pub p2msoutputindex: MetricNode, - pub p2pk33addressindex: Indexes17, - pub p2pk65addressindex: Indexes18, - pub p2pkhaddressindex: Indexes19, - pub p2shaddressindex: Indexes20, - pub p2traddressindex: Indexes21, - pub p2wpkhaddressindex: Indexes22, - pub p2wshaddressindex: Indexes23, - pub quarterindex: MetricNode, - pub semesterindex: MetricNode, - pub timestamp_fixed: Indexes2, - pub txindex: Indexes6, - pub txindex_count: Indexes2, - pub txinindex: Indexes24, - pub txoutindex: Indexes25, - pub unknownoutputindex: MetricNode, - pub weekindex: MetricNode, - pub yearindex: MetricNode, - pub yearindex_count: Indexes7, + pub address: CatalogTree_Computed_Indexes_Address, + pub block: CatalogTree_Computed_Indexes_Block, + pub time: CatalogTree_Computed_Indexes_Time, + pub transaction: CatalogTree_Computed_Indexes_Transaction, } impl CatalogTree_Computed_Indexes { pub fn new(client: Arc, base_path: &str) -> Self { Self { - date: Indexes13::new(client.clone(), &format!("{base_path}_date")), - date_fixed: Indexes2::new(client.clone(), &format!("{base_path}_date_fixed")), - dateindex: Indexes13::new(client.clone(), &format!("{base_path}_dateindex")), - dateindex_count: Indexes14::new(client.clone(), &format!("{base_path}_dateindex_count")), - decadeindex: MetricNode::new(client.clone(), format!("{base_path}_decadeindex")), - difficultyepoch: MetricNode::new(client.clone(), format!("{base_path}_difficultyepoch")), + address: CatalogTree_Computed_Indexes_Address::new(client.clone(), &format!("{base_path}_address")), + block: CatalogTree_Computed_Indexes_Block::new(client.clone(), &format!("{base_path}_block")), + time: CatalogTree_Computed_Indexes_Time::new(client.clone(), &format!("{base_path}_time")), + transaction: CatalogTree_Computed_Indexes_Transaction::new(client.clone(), &format!("{base_path}_transaction")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Indexes_Address { + pub emptyoutputindex: MetricNode, + pub opreturnindex: MetricNode, + pub p2aaddressindex: Indexes14, + pub p2msoutputindex: MetricNode, + pub p2pk33addressindex: Indexes15, + pub p2pk65addressindex: Indexes16, + pub p2pkhaddressindex: Indexes17, + pub p2shaddressindex: Indexes18, + pub p2traddressindex: Indexes19, + pub p2wpkhaddressindex: Indexes20, + pub p2wshaddressindex: Indexes21, + pub unknownoutputindex: MetricNode, +} + +impl CatalogTree_Computed_Indexes_Address { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { emptyoutputindex: MetricNode::new(client.clone(), format!("{base_path}_emptyoutputindex")), - first_dateindex: Indexes14::new(client.clone(), &format!("{base_path}_first_dateindex")), + opreturnindex: MetricNode::new(client.clone(), format!("{base_path}_opreturnindex")), + p2aaddressindex: Indexes14::new(client.clone(), &format!("{base_path}_p2aaddressindex")), + p2msoutputindex: MetricNode::new(client.clone(), format!("{base_path}_p2msoutputindex")), + p2pk33addressindex: Indexes15::new(client.clone(), &format!("{base_path}_p2pk33addressindex")), + p2pk65addressindex: Indexes16::new(client.clone(), &format!("{base_path}_p2pk65addressindex")), + p2pkhaddressindex: Indexes17::new(client.clone(), &format!("{base_path}_p2pkhaddressindex")), + p2shaddressindex: Indexes18::new(client.clone(), &format!("{base_path}_p2shaddressindex")), + p2traddressindex: Indexes19::new(client.clone(), &format!("{base_path}_p2traddressindex")), + p2wpkhaddressindex: Indexes20::new(client.clone(), &format!("{base_path}_p2wpkhaddressindex")), + p2wshaddressindex: Indexes21::new(client.clone(), &format!("{base_path}_p2wshaddressindex")), + unknownoutputindex: MetricNode::new(client.clone(), format!("{base_path}_unknownoutputindex")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Indexes_Block { + pub date: Indexes2, + pub date_fixed: Indexes2, + pub dateindex: Indexes2, + pub difficultyepoch: MetricNode, + pub first_height: MetricNode, + pub halvingepoch: MetricNode, + pub height: Indexes2, + pub height_count: MetricNode, + pub timestamp_fixed: Indexes2, + pub txindex_count: Indexes2, +} + +impl CatalogTree_Computed_Indexes_Block { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + date: Indexes2::new(client.clone(), &format!("{base_path}_date")), + date_fixed: Indexes2::new(client.clone(), &format!("{base_path}_date_fixed")), + dateindex: Indexes2::new(client.clone(), &format!("{base_path}_dateindex")), + difficultyepoch: MetricNode::new(client.clone(), format!("{base_path}_difficultyepoch")), first_height: MetricNode::new(client.clone(), format!("{base_path}_first_height")), - first_monthindex: Indexes15::new(client.clone(), &format!("{base_path}_first_monthindex")), - first_yearindex: Indexes7::new(client.clone(), &format!("{base_path}_first_yearindex")), halvingepoch: MetricNode::new(client.clone(), format!("{base_path}_halvingepoch")), height: Indexes2::new(client.clone(), &format!("{base_path}_height")), height_count: MetricNode::new(client.clone(), format!("{base_path}_height_count")), - input_count: Indexes6::new(client.clone(), &format!("{base_path}_input_count")), + timestamp_fixed: Indexes2::new(client.clone(), &format!("{base_path}_timestamp_fixed")), + txindex_count: Indexes2::new(client.clone(), &format!("{base_path}_txindex_count")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Indexes_Time { + pub date: Indexes5, + pub dateindex: Indexes5, + pub dateindex_count: Indexes22, + pub decadeindex: MetricNode, + pub first_dateindex: Indexes22, + pub first_height: Indexes5, + pub first_monthindex: Indexes23, + pub first_yearindex: Indexes7, + pub height_count: Indexes5, + pub monthindex: MetricNode, + pub monthindex_count: Indexes23, + pub quarterindex: MetricNode, + pub semesterindex: MetricNode, + pub weekindex: MetricNode, + pub yearindex: MetricNode, + pub yearindex_count: Indexes7, +} + +impl CatalogTree_Computed_Indexes_Time { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + date: Indexes5::new(client.clone(), &format!("{base_path}_date")), + dateindex: Indexes5::new(client.clone(), &format!("{base_path}_dateindex")), + dateindex_count: Indexes22::new(client.clone(), &format!("{base_path}_dateindex_count")), + decadeindex: MetricNode::new(client.clone(), format!("{base_path}_decadeindex")), + first_dateindex: Indexes22::new(client.clone(), &format!("{base_path}_first_dateindex")), + first_height: Indexes5::new(client.clone(), &format!("{base_path}_first_height")), + first_monthindex: Indexes23::new(client.clone(), &format!("{base_path}_first_monthindex")), + first_yearindex: Indexes7::new(client.clone(), &format!("{base_path}_first_yearindex")), + height_count: Indexes5::new(client.clone(), &format!("{base_path}_height_count")), monthindex: MetricNode::new(client.clone(), format!("{base_path}_monthindex")), - monthindex_count: Indexes15::new(client.clone(), &format!("{base_path}_monthindex_count")), - opreturnindex: MetricNode::new(client.clone(), format!("{base_path}_opreturnindex")), - output_count: Indexes6::new(client.clone(), &format!("{base_path}_output_count")), - p2aaddressindex: Indexes16::new(client.clone(), &format!("{base_path}_p2aaddressindex")), - p2msoutputindex: MetricNode::new(client.clone(), format!("{base_path}_p2msoutputindex")), - p2pk33addressindex: Indexes17::new(client.clone(), &format!("{base_path}_p2pk33addressindex")), - p2pk65addressindex: Indexes18::new(client.clone(), &format!("{base_path}_p2pk65addressindex")), - p2pkhaddressindex: Indexes19::new(client.clone(), &format!("{base_path}_p2pkhaddressindex")), - p2shaddressindex: Indexes20::new(client.clone(), &format!("{base_path}_p2shaddressindex")), - p2traddressindex: Indexes21::new(client.clone(), &format!("{base_path}_p2traddressindex")), - p2wpkhaddressindex: Indexes22::new(client.clone(), &format!("{base_path}_p2wpkhaddressindex")), - p2wshaddressindex: Indexes23::new(client.clone(), &format!("{base_path}_p2wshaddressindex")), + monthindex_count: Indexes23::new(client.clone(), &format!("{base_path}_monthindex_count")), quarterindex: MetricNode::new(client.clone(), format!("{base_path}_quarterindex")), semesterindex: MetricNode::new(client.clone(), format!("{base_path}_semesterindex")), - timestamp_fixed: Indexes2::new(client.clone(), &format!("{base_path}_timestamp_fixed")), - txindex: Indexes6::new(client.clone(), &format!("{base_path}_txindex")), - txindex_count: Indexes2::new(client.clone(), &format!("{base_path}_txindex_count")), - txinindex: Indexes24::new(client.clone(), &format!("{base_path}_txinindex")), - txoutindex: Indexes25::new(client.clone(), &format!("{base_path}_txoutindex")), - unknownoutputindex: MetricNode::new(client.clone(), format!("{base_path}_unknownoutputindex")), weekindex: MetricNode::new(client.clone(), format!("{base_path}_weekindex")), yearindex: MetricNode::new(client.clone(), format!("{base_path}_yearindex")), yearindex_count: Indexes7::new(client.clone(), &format!("{base_path}_yearindex_count")), @@ -2170,75 +2301,116 @@ impl CatalogTree_Computed_Indexes { } } +/// Catalog tree node. +pub struct CatalogTree_Computed_Indexes_Transaction { + pub input_count: Indexes6, + pub output_count: Indexes6, + pub txindex: Indexes6, + pub txinindex: Indexes24, + pub txoutindex: Indexes25, +} + +impl CatalogTree_Computed_Indexes_Transaction { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + input_count: Indexes6::new(client.clone(), &format!("{base_path}_input_count")), + output_count: Indexes6::new(client.clone(), &format!("{base_path}_output_count")), + txindex: Indexes6::new(client.clone(), &format!("{base_path}_txindex")), + txinindex: Indexes24::new(client.clone(), &format!("{base_path}_txinindex")), + txoutindex: Indexes25::new(client.clone(), &format!("{base_path}_txoutindex")), + } + } +} + /// Catalog tree node. pub struct CatalogTree_Computed_Market { - pub _1d_returns_1m_sd: _1dReturns1mSdPattern, - pub _1d_returns_1w_sd: _1dReturns1mSdPattern, - pub _1d_returns_1y_sd: _1dReturns1mSdPattern, - pub _10y_cagr: Indexes, + pub ath: CatalogTree_Computed_Market_Ath, + pub dca: CatalogTree_Computed_Market_Dca, + pub history: CatalogTree_Computed_Market_History, + pub moving_average: CatalogTree_Computed_Market_MovingAverage, + pub range: CatalogTree_Computed_Market_Range, + pub volatility: CatalogTree_Computed_Market_Volatility, +} + +impl CatalogTree_Computed_Market { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + ath: CatalogTree_Computed_Market_Ath::new(client.clone(), &format!("{base_path}_ath")), + dca: CatalogTree_Computed_Market_Dca::new(client.clone(), &format!("{base_path}_dca")), + history: CatalogTree_Computed_Market_History::new(client.clone(), &format!("{base_path}_history")), + moving_average: CatalogTree_Computed_Market_MovingAverage::new(client.clone(), &format!("{base_path}_moving_average")), + range: CatalogTree_Computed_Market_Range::new(client.clone(), &format!("{base_path}_range")), + volatility: CatalogTree_Computed_Market_Volatility::new(client.clone(), &format!("{base_path}_volatility")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Market_Ath { + pub days_since_price_ath: Indexes, + pub max_days_between_price_aths: Indexes, + pub max_years_between_price_aths: Indexes, + pub price_ath: Indexes26, + pub price_drawdown: Indexes26, +} + +impl CatalogTree_Computed_Market_Ath { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + days_since_price_ath: Indexes::new(client.clone(), &format!("{base_path}_days_since_price_ath")), + max_days_between_price_aths: Indexes::new(client.clone(), &format!("{base_path}_max_days_between_price_aths")), + max_years_between_price_aths: Indexes::new(client.clone(), &format!("{base_path}_max_years_between_price_aths")), + price_ath: Indexes26::new(client.clone(), &format!("{base_path}_price_ath")), + price_drawdown: Indexes26::new(client.clone(), &format!("{base_path}_price_drawdown")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Market_Dca { pub _10y_dca_avg_price: Indexes, pub _10y_dca_cagr: Indexes, pub _10y_dca_returns: Indexes, pub _10y_dca_stack: Indexes, - pub _10y_price_returns: Indexes, - pub _1d_price_returns: Indexes, pub _1m_dca_avg_price: Indexes, pub _1m_dca_returns: Indexes, pub _1m_dca_stack: Indexes, - pub _1m_price_returns: Indexes, pub _1w_dca_avg_price: Indexes, pub _1w_dca_returns: Indexes, pub _1w_dca_stack: Indexes, - pub _1w_price_returns: Indexes, pub _1y_dca_avg_price: Indexes, pub _1y_dca_returns: Indexes, pub _1y_dca_stack: Indexes, - pub _1y_price_returns: Indexes, - pub _2y_cagr: Indexes, pub _2y_dca_avg_price: Indexes, pub _2y_dca_cagr: Indexes, pub _2y_dca_returns: Indexes, pub _2y_dca_stack: Indexes, - pub _2y_price_returns: Indexes, pub _3m_dca_avg_price: Indexes, pub _3m_dca_returns: Indexes, pub _3m_dca_stack: Indexes, - pub _3m_price_returns: Indexes, - pub _3y_cagr: Indexes, pub _3y_dca_avg_price: Indexes, pub _3y_dca_cagr: Indexes, pub _3y_dca_returns: Indexes, pub _3y_dca_stack: Indexes, - pub _3y_price_returns: Indexes, - pub _4y_cagr: Indexes, pub _4y_dca_avg_price: Indexes, pub _4y_dca_cagr: Indexes, pub _4y_dca_returns: Indexes, pub _4y_dca_stack: Indexes, - pub _4y_price_returns: Indexes, - pub _5y_cagr: Indexes, pub _5y_dca_avg_price: Indexes, pub _5y_dca_cagr: Indexes, pub _5y_dca_returns: Indexes, pub _5y_dca_stack: Indexes, - pub _5y_price_returns: Indexes, pub _6m_dca_avg_price: Indexes, pub _6m_dca_returns: Indexes, pub _6m_dca_stack: Indexes, - pub _6m_price_returns: Indexes, - pub _6y_cagr: Indexes, pub _6y_dca_avg_price: Indexes, pub _6y_dca_cagr: Indexes, pub _6y_dca_returns: Indexes, pub _6y_dca_stack: Indexes, - pub _6y_price_returns: Indexes, - pub _8y_cagr: Indexes, pub _8y_dca_avg_price: Indexes, pub _8y_dca_cagr: Indexes, pub _8y_dca_returns: Indexes, pub _8y_dca_stack: Indexes, - pub _8y_price_returns: Indexes, - pub days_since_price_ath: Indexes, pub dca_class_2015_avg_price: Indexes, pub dca_class_2015_returns: Indexes, pub dca_class_2015_stack: Indexes, @@ -2272,139 +2444,54 @@ pub struct CatalogTree_Computed_Market { pub dca_class_2025_avg_price: Indexes, pub dca_class_2025_returns: Indexes, pub dca_class_2025_stack: Indexes, - pub max_days_between_price_aths: Indexes, - pub max_years_between_price_aths: Indexes, - pub price_10y_ago: Indexes, - pub price_13d_ema: Price13dEmaPattern, - pub price_13d_sma: Price13dEmaPattern, - pub price_144d_ema: Price13dEmaPattern, - pub price_144d_sma: Price13dEmaPattern, - pub price_1d_ago: Indexes, - pub price_1m_ago: Indexes, - pub price_1m_ema: Price13dEmaPattern, - pub price_1m_max: Indexes, - pub price_1m_min: Indexes, - pub price_1m_sma: Price13dEmaPattern, - pub price_1m_volatility: Indexes, - pub price_1w_ago: Indexes, - pub price_1w_ema: Price13dEmaPattern, - pub price_1w_max: Indexes, - pub price_1w_min: Indexes, - pub price_1w_sma: Price13dEmaPattern, - pub price_1w_volatility: Indexes, - pub price_1y_ago: Indexes, - pub price_1y_ema: Price13dEmaPattern, - pub price_1y_max: Indexes, - pub price_1y_min: Indexes, - pub price_1y_sma: Price13dEmaPattern, - pub price_1y_volatility: Indexes, - pub price_200d_ema: Price13dEmaPattern, - pub price_200d_sma: Price13dEmaPattern, - pub price_200d_sma_x0_8: Indexes, - pub price_200d_sma_x2_4: Indexes, - pub price_200w_ema: Price13dEmaPattern, - pub price_200w_sma: Price13dEmaPattern, - pub price_21d_ema: Price13dEmaPattern, - pub price_21d_sma: Price13dEmaPattern, - pub price_2w_choppiness_index: Indexes, - pub price_2w_max: Indexes, - pub price_2w_min: Indexes, - pub price_2y_ago: Indexes, - pub price_2y_ema: Price13dEmaPattern, - pub price_2y_sma: Price13dEmaPattern, - pub price_34d_ema: Price13dEmaPattern, - pub price_34d_sma: Price13dEmaPattern, - pub price_3m_ago: Indexes, - pub price_3y_ago: Indexes, - pub price_4y_ago: Indexes, - pub price_4y_ema: Price13dEmaPattern, - pub price_4y_sma: Price13dEmaPattern, - pub price_55d_ema: Price13dEmaPattern, - pub price_55d_sma: Price13dEmaPattern, - pub price_5y_ago: Indexes, - pub price_6m_ago: Indexes, - pub price_6y_ago: Indexes, - pub price_89d_ema: Price13dEmaPattern, - pub price_89d_sma: Price13dEmaPattern, - pub price_8d_ema: Price13dEmaPattern, - pub price_8d_sma: Price13dEmaPattern, - pub price_8y_ago: Indexes, - pub price_ath: Indexes26, - pub price_drawdown: Indexes26, - pub price_true_range: Indexes5, - pub price_true_range_2w_sum: Indexes5, } -impl CatalogTree_Computed_Market { +impl CatalogTree_Computed_Market_Dca { pub fn new(client: Arc, base_path: &str) -> Self { Self { - _1d_returns_1m_sd: _1dReturns1mSdPattern::new(client.clone(), "1d_returns_1m_sd"), - _1d_returns_1w_sd: _1dReturns1mSdPattern::new(client.clone(), "1d_returns_1w_sd"), - _1d_returns_1y_sd: _1dReturns1mSdPattern::new(client.clone(), "1d_returns_1y_sd"), - _10y_cagr: Indexes::new(client.clone(), &format!("{base_path}__10y_cagr")), _10y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__10y_dca_avg_price")), _10y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__10y_dca_cagr")), _10y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__10y_dca_returns")), _10y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__10y_dca_stack")), - _10y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__10y_price_returns")), - _1d_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1d_price_returns")), _1m_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__1m_dca_avg_price")), _1m_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__1m_dca_returns")), _1m_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__1m_dca_stack")), - _1m_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1m_price_returns")), _1w_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__1w_dca_avg_price")), _1w_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__1w_dca_returns")), _1w_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__1w_dca_stack")), - _1w_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1w_price_returns")), _1y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__1y_dca_avg_price")), _1y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__1y_dca_returns")), _1y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__1y_dca_stack")), - _1y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1y_price_returns")), - _2y_cagr: Indexes::new(client.clone(), &format!("{base_path}__2y_cagr")), _2y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__2y_dca_avg_price")), _2y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__2y_dca_cagr")), _2y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__2y_dca_returns")), _2y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__2y_dca_stack")), - _2y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__2y_price_returns")), _3m_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__3m_dca_avg_price")), _3m_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__3m_dca_returns")), _3m_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__3m_dca_stack")), - _3m_price_returns: Indexes::new(client.clone(), &format!("{base_path}__3m_price_returns")), - _3y_cagr: Indexes::new(client.clone(), &format!("{base_path}__3y_cagr")), _3y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__3y_dca_avg_price")), _3y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__3y_dca_cagr")), _3y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__3y_dca_returns")), _3y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__3y_dca_stack")), - _3y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__3y_price_returns")), - _4y_cagr: Indexes::new(client.clone(), &format!("{base_path}__4y_cagr")), _4y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__4y_dca_avg_price")), _4y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__4y_dca_cagr")), _4y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__4y_dca_returns")), _4y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__4y_dca_stack")), - _4y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__4y_price_returns")), - _5y_cagr: Indexes::new(client.clone(), &format!("{base_path}__5y_cagr")), _5y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__5y_dca_avg_price")), _5y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__5y_dca_cagr")), _5y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__5y_dca_returns")), _5y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__5y_dca_stack")), - _5y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__5y_price_returns")), _6m_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__6m_dca_avg_price")), _6m_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__6m_dca_returns")), _6m_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__6m_dca_stack")), - _6m_price_returns: Indexes::new(client.clone(), &format!("{base_path}__6m_price_returns")), - _6y_cagr: Indexes::new(client.clone(), &format!("{base_path}__6y_cagr")), _6y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__6y_dca_avg_price")), _6y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__6y_dca_cagr")), _6y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__6y_dca_returns")), _6y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__6y_dca_stack")), - _6y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__6y_price_returns")), - _8y_cagr: Indexes::new(client.clone(), &format!("{base_path}__8y_cagr")), _8y_dca_avg_price: Indexes::new(client.clone(), &format!("{base_path}__8y_dca_avg_price")), _8y_dca_cagr: Indexes::new(client.clone(), &format!("{base_path}__8y_dca_cagr")), _8y_dca_returns: Indexes::new(client.clone(), &format!("{base_path}__8y_dca_returns")), _8y_dca_stack: Indexes::new(client.clone(), &format!("{base_path}__8y_dca_stack")), - _8y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__8y_price_returns")), - days_since_price_ath: Indexes::new(client.clone(), &format!("{base_path}_days_since_price_ath")), dca_class_2015_avg_price: Indexes::new(client.clone(), &format!("{base_path}_dca_class_2015_avg_price")), dca_class_2015_returns: Indexes::new(client.clone(), &format!("{base_path}_dca_class_2015_returns")), dca_class_2015_stack: Indexes::new(client.clone(), &format!("{base_path}_dca_class_2015_stack")), @@ -2438,32 +2525,134 @@ impl CatalogTree_Computed_Market { dca_class_2025_avg_price: Indexes::new(client.clone(), &format!("{base_path}_dca_class_2025_avg_price")), dca_class_2025_returns: Indexes::new(client.clone(), &format!("{base_path}_dca_class_2025_returns")), dca_class_2025_stack: Indexes::new(client.clone(), &format!("{base_path}_dca_class_2025_stack")), - max_days_between_price_aths: Indexes::new(client.clone(), &format!("{base_path}_max_days_between_price_aths")), - max_years_between_price_aths: Indexes::new(client.clone(), &format!("{base_path}_max_years_between_price_aths")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Market_History { + pub _10y_cagr: Indexes, + pub _10y_price_returns: Indexes, + pub _1d_price_returns: Indexes, + pub _1m_price_returns: Indexes, + pub _1w_price_returns: Indexes, + pub _1y_price_returns: Indexes, + pub _2y_cagr: Indexes, + pub _2y_price_returns: Indexes, + pub _3m_price_returns: Indexes, + pub _3y_cagr: Indexes, + pub _3y_price_returns: Indexes, + pub _4y_cagr: Indexes, + pub _4y_price_returns: Indexes, + pub _5y_cagr: Indexes, + pub _5y_price_returns: Indexes, + pub _6m_price_returns: Indexes, + pub _6y_cagr: Indexes, + pub _6y_price_returns: Indexes, + pub _8y_cagr: Indexes, + pub _8y_price_returns: Indexes, + pub price_10y_ago: Indexes, + pub price_1d_ago: Indexes, + pub price_1m_ago: Indexes, + pub price_1w_ago: Indexes, + pub price_1y_ago: Indexes, + pub price_2y_ago: Indexes, + pub price_3m_ago: Indexes, + pub price_3y_ago: Indexes, + pub price_4y_ago: Indexes, + pub price_5y_ago: Indexes, + pub price_6m_ago: Indexes, + pub price_6y_ago: Indexes, + pub price_8y_ago: Indexes, +} + +impl CatalogTree_Computed_Market_History { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + _10y_cagr: Indexes::new(client.clone(), &format!("{base_path}__10y_cagr")), + _10y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__10y_price_returns")), + _1d_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1d_price_returns")), + _1m_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1m_price_returns")), + _1w_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1w_price_returns")), + _1y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__1y_price_returns")), + _2y_cagr: Indexes::new(client.clone(), &format!("{base_path}__2y_cagr")), + _2y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__2y_price_returns")), + _3m_price_returns: Indexes::new(client.clone(), &format!("{base_path}__3m_price_returns")), + _3y_cagr: Indexes::new(client.clone(), &format!("{base_path}__3y_cagr")), + _3y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__3y_price_returns")), + _4y_cagr: Indexes::new(client.clone(), &format!("{base_path}__4y_cagr")), + _4y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__4y_price_returns")), + _5y_cagr: Indexes::new(client.clone(), &format!("{base_path}__5y_cagr")), + _5y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__5y_price_returns")), + _6m_price_returns: Indexes::new(client.clone(), &format!("{base_path}__6m_price_returns")), + _6y_cagr: Indexes::new(client.clone(), &format!("{base_path}__6y_cagr")), + _6y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__6y_price_returns")), + _8y_cagr: Indexes::new(client.clone(), &format!("{base_path}__8y_cagr")), + _8y_price_returns: Indexes::new(client.clone(), &format!("{base_path}__8y_price_returns")), price_10y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_10y_ago")), + price_1d_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1d_ago")), + price_1m_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1m_ago")), + price_1w_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1w_ago")), + price_1y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1y_ago")), + price_2y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_2y_ago")), + price_3m_ago: Indexes::new(client.clone(), &format!("{base_path}_price_3m_ago")), + price_3y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_3y_ago")), + price_4y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_4y_ago")), + price_5y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_5y_ago")), + price_6m_ago: Indexes::new(client.clone(), &format!("{base_path}_price_6m_ago")), + price_6y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_6y_ago")), + price_8y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_8y_ago")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Market_MovingAverage { + pub price_13d_ema: Price13dEmaPattern, + pub price_13d_sma: Price13dEmaPattern, + pub price_144d_ema: Price13dEmaPattern, + pub price_144d_sma: Price13dEmaPattern, + pub price_1m_ema: Price13dEmaPattern, + pub price_1m_sma: Price13dEmaPattern, + pub price_1w_ema: Price13dEmaPattern, + pub price_1w_sma: Price13dEmaPattern, + pub price_1y_ema: Price13dEmaPattern, + pub price_1y_sma: Price13dEmaPattern, + pub price_200d_ema: Price13dEmaPattern, + pub price_200d_sma: Price13dEmaPattern, + pub price_200d_sma_x0_8: Indexes, + pub price_200d_sma_x2_4: Indexes, + pub price_200w_ema: Price13dEmaPattern, + pub price_200w_sma: Price13dEmaPattern, + pub price_21d_ema: Price13dEmaPattern, + pub price_21d_sma: Price13dEmaPattern, + pub price_2y_ema: Price13dEmaPattern, + pub price_2y_sma: Price13dEmaPattern, + pub price_34d_ema: Price13dEmaPattern, + pub price_34d_sma: Price13dEmaPattern, + pub price_4y_ema: Price13dEmaPattern, + pub price_4y_sma: Price13dEmaPattern, + pub price_55d_ema: Price13dEmaPattern, + pub price_55d_sma: Price13dEmaPattern, + pub price_89d_ema: Price13dEmaPattern, + pub price_89d_sma: Price13dEmaPattern, + pub price_8d_ema: Price13dEmaPattern, + pub price_8d_sma: Price13dEmaPattern, +} + +impl CatalogTree_Computed_Market_MovingAverage { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { price_13d_ema: Price13dEmaPattern::new(client.clone(), "price_13d_ema"), price_13d_sma: Price13dEmaPattern::new(client.clone(), "price_13d_sma"), price_144d_ema: Price13dEmaPattern::new(client.clone(), "price_144d_ema"), price_144d_sma: Price13dEmaPattern::new(client.clone(), "price_144d_sma"), - price_1d_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1d_ago")), - price_1m_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1m_ago")), price_1m_ema: Price13dEmaPattern::new(client.clone(), "price_1m_ema"), - price_1m_max: Indexes::new(client.clone(), &format!("{base_path}_price_1m_max")), - price_1m_min: Indexes::new(client.clone(), &format!("{base_path}_price_1m_min")), price_1m_sma: Price13dEmaPattern::new(client.clone(), "price_1m_sma"), - price_1m_volatility: Indexes::new(client.clone(), &format!("{base_path}_price_1m_volatility")), - price_1w_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1w_ago")), price_1w_ema: Price13dEmaPattern::new(client.clone(), "price_1w_ema"), - price_1w_max: Indexes::new(client.clone(), &format!("{base_path}_price_1w_max")), - price_1w_min: Indexes::new(client.clone(), &format!("{base_path}_price_1w_min")), price_1w_sma: Price13dEmaPattern::new(client.clone(), "price_1w_sma"), - price_1w_volatility: Indexes::new(client.clone(), &format!("{base_path}_price_1w_volatility")), - price_1y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_1y_ago")), price_1y_ema: Price13dEmaPattern::new(client.clone(), "price_1y_ema"), - price_1y_max: Indexes::new(client.clone(), &format!("{base_path}_price_1y_max")), - price_1y_min: Indexes::new(client.clone(), &format!("{base_path}_price_1y_min")), price_1y_sma: Price13dEmaPattern::new(client.clone(), "price_1y_sma"), - price_1y_volatility: Indexes::new(client.clone(), &format!("{base_path}_price_1y_volatility")), price_200d_ema: Price13dEmaPattern::new(client.clone(), "price_200d_ema"), price_200d_sma: Price13dEmaPattern::new(client.clone(), "price_200d_sma"), price_200d_sma_x0_8: Indexes::new(client.clone(), &format!("{base_path}_price_200d_sma_x0_8")), @@ -2472,37 +2661,78 @@ impl CatalogTree_Computed_Market { price_200w_sma: Price13dEmaPattern::new(client.clone(), "price_200w_sma"), price_21d_ema: Price13dEmaPattern::new(client.clone(), "price_21d_ema"), price_21d_sma: Price13dEmaPattern::new(client.clone(), "price_21d_sma"), - price_2w_choppiness_index: Indexes::new(client.clone(), &format!("{base_path}_price_2w_choppiness_index")), - price_2w_max: Indexes::new(client.clone(), &format!("{base_path}_price_2w_max")), - price_2w_min: Indexes::new(client.clone(), &format!("{base_path}_price_2w_min")), - price_2y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_2y_ago")), price_2y_ema: Price13dEmaPattern::new(client.clone(), "price_2y_ema"), price_2y_sma: Price13dEmaPattern::new(client.clone(), "price_2y_sma"), price_34d_ema: Price13dEmaPattern::new(client.clone(), "price_34d_ema"), price_34d_sma: Price13dEmaPattern::new(client.clone(), "price_34d_sma"), - price_3m_ago: Indexes::new(client.clone(), &format!("{base_path}_price_3m_ago")), - price_3y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_3y_ago")), - price_4y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_4y_ago")), price_4y_ema: Price13dEmaPattern::new(client.clone(), "price_4y_ema"), price_4y_sma: Price13dEmaPattern::new(client.clone(), "price_4y_sma"), price_55d_ema: Price13dEmaPattern::new(client.clone(), "price_55d_ema"), price_55d_sma: Price13dEmaPattern::new(client.clone(), "price_55d_sma"), - price_5y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_5y_ago")), - price_6m_ago: Indexes::new(client.clone(), &format!("{base_path}_price_6m_ago")), - price_6y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_6y_ago")), price_89d_ema: Price13dEmaPattern::new(client.clone(), "price_89d_ema"), price_89d_sma: Price13dEmaPattern::new(client.clone(), "price_89d_sma"), price_8d_ema: Price13dEmaPattern::new(client.clone(), "price_8d_ema"), price_8d_sma: Price13dEmaPattern::new(client.clone(), "price_8d_sma"), - price_8y_ago: Indexes::new(client.clone(), &format!("{base_path}_price_8y_ago")), - price_ath: Indexes26::new(client.clone(), &format!("{base_path}_price_ath")), - price_drawdown: Indexes26::new(client.clone(), &format!("{base_path}_price_drawdown")), + } + } +} + +/// Catalog tree node. +pub struct CatalogTree_Computed_Market_Range { + pub price_1m_max: Indexes, + pub price_1m_min: Indexes, + pub price_1w_max: Indexes, + pub price_1w_min: Indexes, + pub price_1y_max: Indexes, + pub price_1y_min: Indexes, + pub price_2w_choppiness_index: Indexes, + pub price_2w_max: Indexes, + pub price_2w_min: Indexes, + pub price_true_range: Indexes5, + pub price_true_range_2w_sum: Indexes5, +} + +impl CatalogTree_Computed_Market_Range { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + price_1m_max: Indexes::new(client.clone(), &format!("{base_path}_price_1m_max")), + price_1m_min: Indexes::new(client.clone(), &format!("{base_path}_price_1m_min")), + price_1w_max: Indexes::new(client.clone(), &format!("{base_path}_price_1w_max")), + price_1w_min: Indexes::new(client.clone(), &format!("{base_path}_price_1w_min")), + price_1y_max: Indexes::new(client.clone(), &format!("{base_path}_price_1y_max")), + price_1y_min: Indexes::new(client.clone(), &format!("{base_path}_price_1y_min")), + price_2w_choppiness_index: Indexes::new(client.clone(), &format!("{base_path}_price_2w_choppiness_index")), + price_2w_max: Indexes::new(client.clone(), &format!("{base_path}_price_2w_max")), + price_2w_min: Indexes::new(client.clone(), &format!("{base_path}_price_2w_min")), price_true_range: Indexes5::new(client.clone(), &format!("{base_path}_price_true_range")), price_true_range_2w_sum: Indexes5::new(client.clone(), &format!("{base_path}_price_true_range_2w_sum")), } } } +/// Catalog tree node. +pub struct CatalogTree_Computed_Market_Volatility { + pub _1d_returns_1m_sd: _1dReturns1mSdPattern, + pub _1d_returns_1w_sd: _1dReturns1mSdPattern, + pub _1d_returns_1y_sd: _1dReturns1mSdPattern, + pub price_1m_volatility: Indexes, + pub price_1w_volatility: Indexes, + pub price_1y_volatility: Indexes, +} + +impl CatalogTree_Computed_Market_Volatility { + pub fn new(client: Arc, base_path: &str) -> Self { + Self { + _1d_returns_1m_sd: _1dReturns1mSdPattern::new(client.clone(), "1d_returns_1m_sd"), + _1d_returns_1w_sd: _1dReturns1mSdPattern::new(client.clone(), "1d_returns_1w_sd"), + _1d_returns_1y_sd: _1dReturns1mSdPattern::new(client.clone(), "1d_returns_1y_sd"), + price_1m_volatility: Indexes::new(client.clone(), &format!("{base_path}_price_1m_volatility")), + price_1w_volatility: Indexes::new(client.clone(), &format!("{base_path}_price_1w_volatility")), + price_1y_volatility: Indexes::new(client.clone(), &format!("{base_path}_price_1y_volatility")), + } + } +} + /// Catalog tree node. pub struct CatalogTree_Computed_Pools { pub pool: Indexes2, @@ -3590,14 +3820,14 @@ pub struct CatalogTree_Indexed_Address { pub first_p2traddressindex: Indexes2, pub first_p2wpkhaddressindex: Indexes2, pub first_p2wshaddressindex: Indexes2, - pub p2abytes: Indexes16, - pub p2pk33bytes: Indexes17, - pub p2pk65bytes: Indexes18, - pub p2pkhbytes: Indexes19, - pub p2shbytes: Indexes20, - pub p2trbytes: Indexes21, - pub p2wpkhbytes: Indexes22, - pub p2wshbytes: Indexes23, + pub p2abytes: Indexes14, + pub p2pk33bytes: Indexes15, + pub p2pk65bytes: Indexes16, + pub p2pkhbytes: Indexes17, + pub p2shbytes: Indexes18, + pub p2trbytes: Indexes19, + pub p2wpkhbytes: Indexes20, + pub p2wshbytes: Indexes21, } impl CatalogTree_Indexed_Address { @@ -3611,14 +3841,14 @@ impl CatalogTree_Indexed_Address { first_p2traddressindex: Indexes2::new(client.clone(), &format!("{base_path}_first_p2traddressindex")), first_p2wpkhaddressindex: Indexes2::new(client.clone(), &format!("{base_path}_first_p2wpkhaddressindex")), first_p2wshaddressindex: Indexes2::new(client.clone(), &format!("{base_path}_first_p2wshaddressindex")), - p2abytes: Indexes16::new(client.clone(), &format!("{base_path}_p2abytes")), - p2pk33bytes: Indexes17::new(client.clone(), &format!("{base_path}_p2pk33bytes")), - p2pk65bytes: Indexes18::new(client.clone(), &format!("{base_path}_p2pk65bytes")), - p2pkhbytes: Indexes19::new(client.clone(), &format!("{base_path}_p2pkhbytes")), - p2shbytes: Indexes20::new(client.clone(), &format!("{base_path}_p2shbytes")), - p2trbytes: Indexes21::new(client.clone(), &format!("{base_path}_p2trbytes")), - p2wpkhbytes: Indexes22::new(client.clone(), &format!("{base_path}_p2wpkhbytes")), - p2wshbytes: Indexes23::new(client.clone(), &format!("{base_path}_p2wshbytes")), + p2abytes: Indexes14::new(client.clone(), &format!("{base_path}_p2abytes")), + p2pk33bytes: Indexes15::new(client.clone(), &format!("{base_path}_p2pk33bytes")), + p2pk65bytes: Indexes16::new(client.clone(), &format!("{base_path}_p2pk65bytes")), + p2pkhbytes: Indexes17::new(client.clone(), &format!("{base_path}_p2pkhbytes")), + p2shbytes: Indexes18::new(client.clone(), &format!("{base_path}_p2shbytes")), + p2trbytes: Indexes19::new(client.clone(), &format!("{base_path}_p2trbytes")), + p2wpkhbytes: Indexes20::new(client.clone(), &format!("{base_path}_p2wpkhbytes")), + p2wshbytes: Indexes21::new(client.clone(), &format!("{base_path}_p2wshbytes")), } } } diff --git a/crates/brk_computer/examples/computer_read.rs b/crates/brk_computer/examples/computer_read.rs index 6187fb9ff..08f1cef44 100644 --- a/crates/brk_computer/examples/computer_read.rs +++ b/crates/brk_computer/examples/computer_read.rs @@ -30,7 +30,7 @@ fn run() -> Result<()> { let computer = Computer::forced_import(&outputs_dir, &indexer, Some(fetcher))?; - let _a = dbg!(computer.chain.txindex_to_fee.region().meta()); + let _a = dbg!(computer.chain.transaction.txindex_to_fee.region().meta()); Ok(()) } diff --git a/crates/brk_computer/src/chain/block/compute.rs b/crates/brk_computer/src/chain/block/compute.rs new file mode 100644 index 000000000..d144253a8 --- /dev/null +++ b/crates/brk_computer/src/chain/block/compute.rs @@ -0,0 +1,139 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{CheckedSub, Height, StoredU32, StoredU64, Timestamp}; +use vecdb::{Exit, TypedVecIterator}; + +use super::Vecs; +use crate::{Indexes, indexes}; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + let mut height_to_timestamp_fixed_iter = + indexes.block.height_to_timestamp_fixed.into_iter(); + let mut prev = Height::ZERO; + self.height_to_24h_block_count.compute_transform( + starting_indexes.height, + &indexes.block.height_to_timestamp_fixed, + |(h, t, ..)| { + while t.difference_in_days_between(height_to_timestamp_fixed_iter.get_unwrap(prev)) + > 0 + { + prev.increment(); + if prev > h { + unreachable!() + } + } + (h, StoredU32::from(*h + 1 - *prev)) + }, + exit, + )?; + + self.indexes_to_block_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_range( + starting_indexes.height, + &indexer.vecs.block.height_to_weight, + |h| (h, StoredU32::from(1_u32)), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_1w_block_count + .compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.unwrap_sum(), + 7, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_1m_block_count + .compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.unwrap_sum(), + 30, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_1y_block_count + .compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.unwrap_sum(), + 365, + exit, + )?; + Ok(()) + })?; + + let mut height_to_timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?; + self.height_to_interval.compute_transform( + starting_indexes.height, + &indexer.vecs.block.height_to_timestamp, + |(height, timestamp, ..)| { + let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| { + let prev_timestamp = height_to_timestamp_iter.get_unwrap(prev_h); + timestamp + .checked_sub(prev_timestamp) + .unwrap_or(Timestamp::ZERO) + }); + (height, interval) + }, + exit, + )?; + + self.indexes_to_block_interval.compute_rest( + indexes, + starting_indexes, + exit, + Some(&self.height_to_interval), + )?; + + self.indexes_to_block_weight.compute_rest( + indexes, + starting_indexes, + exit, + Some(&indexer.vecs.block.height_to_weight), + )?; + + self.indexes_to_block_size.compute_rest( + indexes, + starting_indexes, + exit, + Some(&indexer.vecs.block.height_to_total_size), + )?; + + self.height_to_vbytes.compute_transform( + starting_indexes.height, + &indexer.vecs.block.height_to_weight, + |(h, w, ..)| { + ( + h, + StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()), + ) + }, + exit, + )?; + + self.indexes_to_block_vbytes.compute_rest( + indexes, + starting_indexes, + exit, + Some(&self.height_to_vbytes), + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/block/import.rs b/crates/brk_computer/src/chain/block/import.rs new file mode 100644 index 000000000..51337a69c --- /dev/null +++ b/crates/brk_computer/src/chain/block/import.rs @@ -0,0 +1,171 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{StoredU64, Version}; +use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1}; + +use super::Vecs; +use crate::{ + grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + indexes, +}; + +use crate::chain::{ + TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DECADE, TARGET_BLOCKS_PER_MONTH, + TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK, + TARGET_BLOCKS_PER_YEAR, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexer: &Indexer, + indexes: &indexes::Vecs, + ) -> Result { + let v0 = Version::ZERO; + + let last = || VecBuilderOptions::default().add_last(); + let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); + let stats = || { + VecBuilderOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + }; + let full_stats = || { + VecBuilderOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + .add_sum() + .add_cumulative() + }; + + let dateindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.dateindex_to_dateindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DAY)), + ); + let weekindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.weekindex_to_weekindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_WEEK)), + ); + let monthindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.monthindex_to_monthindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_MONTH)), + ); + let quarterindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.quarterindex_to_quarterindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_QUARTER)), + ); + let semesterindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.semesterindex_to_semesterindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_SEMESTER)), + ); + let yearindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.yearindex_to_yearindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_YEAR)), + ); + let decadeindex_to_block_count_target = LazyVecFrom1::init( + "block_count_target", + version + v0, + indexes.time.decadeindex_to_decadeindex.boxed_clone(), + |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DECADE)), + ); + + let height_to_interval = EagerVec::forced_import(db, "interval", version + v0)?; + let height_to_vbytes = EagerVec::forced_import(db, "vbytes", version + v0)?; + + Ok(Self { + dateindex_to_block_count_target, + weekindex_to_block_count_target, + monthindex_to_block_count_target, + quarterindex_to_block_count_target, + semesterindex_to_block_count_target, + yearindex_to_block_count_target, + decadeindex_to_block_count_target, + height_to_interval: height_to_interval.clone(), + height_to_24h_block_count: EagerVec::forced_import( + db, + "24h_block_count", + version + v0, + )?, + height_to_vbytes: height_to_vbytes.clone(), + indexes_to_block_count: ComputedVecsFromHeight::forced_import( + db, + "block_count", + Source::Compute, + version + v0, + indexes, + sum_cum(), + )?, + indexes_to_1w_block_count: ComputedVecsFromDateIndex::forced_import( + db, + "1w_block_count", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_1m_block_count: ComputedVecsFromDateIndex::forced_import( + db, + "1m_block_count", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_1y_block_count: ComputedVecsFromDateIndex::forced_import( + db, + "1y_block_count", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_block_interval: ComputedVecsFromHeight::forced_import( + db, + "block_interval", + Source::Vec(height_to_interval.boxed_clone()), + version + v0, + indexes, + stats(), + )?, + indexes_to_block_size: ComputedVecsFromHeight::forced_import( + db, + "block_size", + Source::Vec(indexer.vecs.block.height_to_total_size.boxed_clone()), + version + v0, + indexes, + full_stats(), + )?, + indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import( + db, + "block_vbytes", + Source::Vec(height_to_vbytes.boxed_clone()), + version + v0, + indexes, + full_stats(), + )?, + indexes_to_block_weight: ComputedVecsFromHeight::forced_import( + db, + "block_weight", + Source::Vec(indexer.vecs.block.height_to_weight.boxed_clone()), + version + v0, + indexes, + full_stats(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/block/mod.rs b/crates/brk_computer/src/chain/block/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/block/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/block/vecs.rs b/crates/brk_computer/src/chain/block/vecs.rs new file mode 100644 index 000000000..54a736e73 --- /dev/null +++ b/crates/brk_computer/src/chain/block/vecs.rs @@ -0,0 +1,35 @@ +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, Height, MonthIndex, QuarterIndex, SemesterIndex, StoredU32, StoredU64, + Timestamp, WeekIndex, Weight, YearIndex, +}; +use vecdb::{EagerVec, LazyVecFrom1, PcoVec}; + +use crate::grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight}; + +/// Block-related metrics: count, interval, size, weight, vbytes +#[derive(Clone, Traversable)] +pub struct Vecs { + pub dateindex_to_block_count_target: LazyVecFrom1, + pub weekindex_to_block_count_target: LazyVecFrom1, + pub monthindex_to_block_count_target: + LazyVecFrom1, + pub quarterindex_to_block_count_target: + LazyVecFrom1, + pub semesterindex_to_block_count_target: + LazyVecFrom1, + pub yearindex_to_block_count_target: LazyVecFrom1, + pub decadeindex_to_block_count_target: + LazyVecFrom1, + pub height_to_interval: EagerVec>, + pub height_to_24h_block_count: EagerVec>, + pub height_to_vbytes: EagerVec>, + pub indexes_to_block_count: ComputedVecsFromHeight, + pub indexes_to_1w_block_count: ComputedVecsFromDateIndex, + pub indexes_to_1m_block_count: ComputedVecsFromDateIndex, + pub indexes_to_1y_block_count: ComputedVecsFromDateIndex, + pub indexes_to_block_interval: ComputedVecsFromHeight, + pub indexes_to_block_size: ComputedVecsFromHeight, + pub indexes_to_block_vbytes: ComputedVecsFromHeight, + pub indexes_to_block_weight: ComputedVecsFromHeight, +} diff --git a/crates/brk_computer/src/chain/coinbase/compute.rs b/crates/brk_computer/src/chain/coinbase/compute.rs new file mode 100644 index 000000000..2691d01f4 --- /dev/null +++ b/crates/brk_computer/src/chain/coinbase/compute.rs @@ -0,0 +1,225 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{CheckedSub, Dollars, HalvingEpoch, Height, Sats, StoredF32, TxOutIndex}; +use vecdb::{Exit, IterableVec, TypedVecIterator, VecIndex}; + +use super::Vecs; +use crate::{ + Indexes, + chain::{block, transaction}, + indexes, price, + utils::OptionExt, +}; + +impl Vecs { + #[allow(clippy::too_many_arguments)] + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + block_vecs: &block::Vecs, + transaction_vecs: &transaction::Vecs, + starting_indexes: &Indexes, + price: Option<&price::Vecs>, + exit: &Exit, + ) -> Result<()> { + self.indexes_to_coinbase + .compute_all(indexes, price, starting_indexes, exit, |vec| { + let mut txindex_to_first_txoutindex_iter = + indexer.vecs.tx.txindex_to_first_txoutindex.iter()?; + let mut txindex_to_output_count_iter = + indexes.transaction.txindex_to_output_count.iter(); + let mut txoutindex_to_value_iter = indexer.vecs.txout.txoutindex_to_value.iter()?; + vec.compute_transform( + starting_indexes.height, + &indexer.vecs.tx.height_to_first_txindex, + |(height, txindex, ..)| { + let first_txoutindex = txindex_to_first_txoutindex_iter + .get_unwrap(txindex) + .to_usize(); + let output_count = txindex_to_output_count_iter.get_unwrap(txindex); + let mut sats = Sats::ZERO; + (first_txoutindex..first_txoutindex + usize::from(output_count)).for_each( + |txoutindex| { + sats += txoutindex_to_value_iter + .get_unwrap(TxOutIndex::from(txoutindex)); + }, + ); + (height, sats) + }, + exit, + )?; + Ok(()) + })?; + + let mut height_to_coinbase_iter = self + .indexes_to_coinbase + .sats + .height + .as_ref() + .unwrap() + .into_iter(); + self.height_to_24h_coinbase_sum.compute_transform( + starting_indexes.height, + &block_vecs.height_to_24h_block_count, + |(h, count, ..)| { + let range = *h - (*count - 1)..=*h; + let sum = range + .map(Height::from) + .map(|h| height_to_coinbase_iter.get_unwrap(h)) + .sum::(); + (h, sum) + }, + exit, + )?; + drop(height_to_coinbase_iter); + + if let Some(mut height_to_coinbase_iter) = self + .indexes_to_coinbase + .dollars + .as_ref() + .map(|c| c.height.u().into_iter()) + { + self.height_to_24h_coinbase_usd_sum.compute_transform( + starting_indexes.height, + &block_vecs.height_to_24h_block_count, + |(h, count, ..)| { + let range = *h - (*count - 1)..=*h; + let sum = range + .map(Height::from) + .map(|h| height_to_coinbase_iter.get_unwrap(h)) + .sum::(); + (h, sum) + }, + exit, + )?; + } + + self.indexes_to_subsidy + .compute_all(indexes, price, starting_indexes, exit, |vec| { + vec.compute_transform2( + starting_indexes.height, + self.indexes_to_coinbase.sats.height.u(), + transaction_vecs.indexes_to_fee.sats.height.unwrap_sum(), + |(height, coinbase, fees, ..)| { + ( + height, + coinbase.checked_sub(fees).unwrap_or_else(|| { + dbg!(height, coinbase, fees); + panic!() + }), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_unclaimed_rewards.compute_all( + indexes, + price, + starting_indexes, + exit, + |vec| { + vec.compute_transform( + starting_indexes.height, + self.indexes_to_subsidy.sats.height.u(), + |(height, subsidy, ..)| { + let halving = HalvingEpoch::from(height); + let expected = Sats::FIFTY_BTC / 2_usize.pow(halving.to_usize() as u32); + (height, expected.checked_sub(subsidy).unwrap()) + }, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_inflation_rate + .compute_all(starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.dateindex, + self.indexes_to_subsidy.sats.dateindex.unwrap_sum(), + self.indexes_to_subsidy.sats.dateindex.unwrap_cumulative(), + |(i, subsidy_1d_sum, subsidy_cumulative, ..)| { + ( + i, + (365.0 * *subsidy_1d_sum as f64 / *subsidy_cumulative as f64 * 100.0) + .into(), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.dateindex_to_fee_dominance.compute_transform2( + starting_indexes.dateindex, + transaction_vecs.indexes_to_fee.sats.dateindex.unwrap_sum(), + self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), + |(i, fee, coinbase, ..)| { + ( + i, + StoredF32::from(u64::from(fee) as f64 / u64::from(coinbase) as f64 * 100.0), + ) + }, + exit, + )?; + + self.dateindex_to_subsidy_dominance.compute_transform2( + starting_indexes.dateindex, + self.indexes_to_subsidy.sats.dateindex.unwrap_sum(), + self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), + |(i, subsidy, coinbase, ..)| { + ( + i, + StoredF32::from(u64::from(subsidy) as f64 / u64::from(coinbase) as f64 * 100.0), + ) + }, + exit, + )?; + + if self.indexes_to_subsidy_usd_1y_sma.is_some() { + let date_to_coinbase_usd_sum = self + .indexes_to_coinbase + .dollars + .as_ref() + .unwrap() + .dateindex + .unwrap_sum(); + + self.indexes_to_subsidy_usd_1y_sma + .as_mut() + .unwrap() + .compute_all(starting_indexes, exit, |v| { + v.compute_sma( + starting_indexes.dateindex, + date_to_coinbase_usd_sum, + 365, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_puell_multiple + .as_mut() + .unwrap() + .compute_all(starting_indexes, exit, |v| { + v.compute_divide( + starting_indexes.dateindex, + date_to_coinbase_usd_sum, + self.indexes_to_subsidy_usd_1y_sma + .as_ref() + .unwrap() + .dateindex + .as_ref() + .unwrap(), + exit, + )?; + Ok(()) + })?; + } + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/coinbase/import.rs b/crates/brk_computer/src/chain/coinbase/import.rs new file mode 100644 index 000000000..36e619aa5 --- /dev/null +++ b/crates/brk_computer/src/chain/coinbase/import.rs @@ -0,0 +1,109 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec}; + +use super::Vecs; +use crate::{ + grouped::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, Source, VecBuilderOptions}, + indexes, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + compute_dollars: bool, + ) -> Result { + let v0 = Version::ZERO; + let last = || VecBuilderOptions::default().add_last(); + + Ok(Self { + height_to_24h_coinbase_sum: EagerVec::forced_import( + db, + "24h_coinbase_sum", + version + v0, + )?, + height_to_24h_coinbase_usd_sum: EagerVec::forced_import( + db, + "24h_coinbase_usd_sum", + version + v0, + )?, + indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import( + db, + "coinbase", + Source::Compute, + version + v0, + VecBuilderOptions::default() + .add_sum() + .add_cumulative() + .add_percentiles() + .add_minmax() + .add_average(), + compute_dollars, + indexes, + )?, + indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import( + db, + "subsidy", + Source::Compute, + version + v0, + VecBuilderOptions::default() + .add_percentiles() + .add_sum() + .add_cumulative() + .add_minmax() + .add_average(), + compute_dollars, + indexes, + )?, + indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight::forced_import( + db, + "unclaimed_rewards", + Source::Compute, + version + v0, + VecBuilderOptions::default().add_sum().add_cumulative(), + compute_dollars, + indexes, + )?, + dateindex_to_fee_dominance: EagerVec::forced_import(db, "fee_dominance", version + v0)?, + dateindex_to_subsidy_dominance: EagerVec::forced_import( + db, + "subsidy_dominance", + version + v0, + )?, + indexes_to_subsidy_usd_1y_sma: compute_dollars + .then(|| { + ComputedVecsFromDateIndex::forced_import( + db, + "subsidy_usd_1y_sma", + Source::Compute, + version + v0, + indexes, + last(), + ) + }) + .transpose()?, + indexes_to_puell_multiple: compute_dollars + .then(|| { + ComputedVecsFromDateIndex::forced_import( + db, + "puell_multiple", + Source::Compute, + version + v0, + indexes, + last(), + ) + }) + .transpose()?, + indexes_to_inflation_rate: ComputedVecsFromDateIndex::forced_import( + db, + "inflation_rate", + Source::Compute, + version + v0, + indexes, + last(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/coinbase/mod.rs b/crates/brk_computer/src/chain/coinbase/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/coinbase/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/coinbase/vecs.rs b/crates/brk_computer/src/chain/coinbase/vecs.rs new file mode 100644 index 000000000..150df5c82 --- /dev/null +++ b/crates/brk_computer/src/chain/coinbase/vecs.rs @@ -0,0 +1,20 @@ +use brk_traversable::Traversable; +use brk_types::{DateIndex, Dollars, Height, Sats, StoredF32}; +use vecdb::{EagerVec, PcoVec}; + +use crate::grouped::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex}; + +/// Coinbase/subsidy/rewards metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub height_to_24h_coinbase_sum: EagerVec>, + pub height_to_24h_coinbase_usd_sum: EagerVec>, + pub indexes_to_coinbase: ComputedValueVecsFromHeight, + pub indexes_to_subsidy: ComputedValueVecsFromHeight, + pub indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight, + pub dateindex_to_fee_dominance: EagerVec>, + pub dateindex_to_subsidy_dominance: EagerVec>, + pub indexes_to_subsidy_usd_1y_sma: Option>, + pub indexes_to_puell_multiple: Option>, + pub indexes_to_inflation_rate: ComputedVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/chain/compute.rs b/crates/brk_computer/src/chain/compute.rs index 1ac68ad31..191b7f893 100644 --- a/crates/brk_computer/src/chain/compute.rs +++ b/crates/brk_computer/src/chain/compute.rs @@ -1,14 +1,10 @@ use brk_error::Result; use brk_indexer::Indexer; -use brk_types::{ - CheckedSub, FeeRate, HalvingEpoch, Height, ONE_DAY_IN_SEC_F64, Sats, StoredF32, StoredF64, - StoredU32, StoredU64, Timestamp, TxOutIndex, TxVersion, -}; -use vecdb::{Exit, IterableVec, TypedVecIterator, VecIndex, unlikely}; +use vecdb::Exit; -use crate::{grouped::ComputedVecsFromHeight, indexes, price, txins, utils::OptionExt, Indexes}; +use crate::{indexes, price, txins, Indexes}; -use super::{Vecs, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F32, TARGET_BLOCKS_PER_DAY_F64}; +use super::Vecs; impl Vecs { pub fn compute( @@ -20,1111 +16,48 @@ impl Vecs { price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { - self.compute_(indexer, indexes, txins, starting_indexes, price, exit)?; + // Independent computations first + self.block.compute(indexer, indexes, starting_indexes, exit)?; + self.epoch.compute(indexer, indexes, starting_indexes, exit)?; + self.transaction.compute(indexer, indexes, txins, starting_indexes, price, exit)?; + + // Coinbase depends on block and transaction + self.coinbase.compute( + indexer, + indexes, + &self.block, + &self.transaction, + starting_indexes, + price, + exit, + )?; + + // Output type depends on transaction + self.output_type.compute(indexer, indexes, &self.transaction, starting_indexes, exit)?; + + // Volume depends on transaction and coinbase + self.volume.compute( + indexer, + indexes, + &self.transaction, + &self.coinbase, + starting_indexes, + price, + exit, + )?; + + // Mining depends on block and coinbase + self.mining.compute( + indexer, + indexes, + &self.block, + &self.coinbase, + starting_indexes, + exit, + )?; + let _lock = exit.lock(); self.db.compact()?; Ok(()) } - - fn compute_( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - txins: &txins::Vecs, - starting_indexes: &Indexes, - price: Option<&price::Vecs>, - exit: &Exit, - ) -> Result<()> { - self.timeindexes_to_timestamp - .compute_all(starting_indexes, exit, |vec| { - vec.compute_transform( - starting_indexes.dateindex, - &indexes.dateindex_to_date, - |(di, d, ..)| (di, Timestamp::from(d)), - exit, - )?; - Ok(()) - })?; - - let mut height_to_timestamp_fixed_iter = indexes.height_to_timestamp_fixed.into_iter(); - let mut prev = Height::ZERO; - self.height_to_24h_block_count.compute_transform( - starting_indexes.height, - &indexes.height_to_timestamp_fixed, - |(h, t, ..)| { - while t.difference_in_days_between(height_to_timestamp_fixed_iter.get_unwrap(prev)) - > 0 - { - prev.increment(); - if prev > h { - unreachable!() - } - } - (h, StoredU32::from(*h + 1 - *prev)) - }, - exit, - )?; - - self.indexes_to_block_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_range( - starting_indexes.height, - &indexer.vecs.block.height_to_weight, - |h| (h, StoredU32::from(1_u32)), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_1w_block_count - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_block_count.dateindex.unwrap_sum(), - 7, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_1m_block_count - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_block_count.dateindex.unwrap_sum(), - 30, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_1y_block_count - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_block_count.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; - - let mut height_to_timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?; - self.height_to_interval.compute_transform( - starting_indexes.height, - &indexer.vecs.block.height_to_timestamp, - |(height, timestamp, ..)| { - let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| { - let prev_timestamp = height_to_timestamp_iter.get_unwrap(prev_h); - timestamp - .checked_sub(prev_timestamp) - .unwrap_or(Timestamp::ZERO) - }); - (height, interval) - }, - exit, - )?; - - self.indexes_to_block_interval.compute_rest( - indexes, - starting_indexes, - exit, - Some(&self.height_to_interval), - )?; - - self.indexes_to_block_weight.compute_rest( - indexes, - starting_indexes, - exit, - Some(&indexer.vecs.block.height_to_weight), - )?; - - self.indexes_to_block_size.compute_rest( - indexes, - starting_indexes, - exit, - Some(&indexer.vecs.block.height_to_total_size), - )?; - - self.height_to_vbytes.compute_transform( - starting_indexes.height, - &indexer.vecs.block.height_to_weight, - |(h, w, ..)| { - ( - h, - StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()), - ) - }, - exit, - )?; - - self.indexes_to_block_vbytes.compute_rest( - indexes, - starting_indexes, - exit, - Some(&self.height_to_vbytes), - )?; - - let mut height_to_timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?; - - self.difficultyepoch_to_timestamp.compute_transform( - starting_indexes.difficultyepoch, - &indexes.difficultyepoch_to_first_height, - |(i, h, ..)| (i, height_to_timestamp_iter.get_unwrap(h)), - exit, - )?; - - self.halvingepoch_to_timestamp.compute_transform( - starting_indexes.halvingepoch, - &indexes.halvingepoch_to_first_height, - |(i, h, ..)| (i, height_to_timestamp_iter.get_unwrap(h)), - exit, - )?; - - let mut height_to_difficultyepoch_iter = indexes.height_to_difficultyepoch.into_iter(); - self.indexes_to_difficultyepoch - .compute_all(starting_indexes, exit, |vec| { - let mut height_count_iter = indexes.dateindex_to_height_count.into_iter(); - vec.compute_transform( - starting_indexes.dateindex, - &indexes.dateindex_to_first_height, - |(di, height, ..)| { - ( - di, - height_to_difficultyepoch_iter - .get_unwrap(height + (*height_count_iter.get_unwrap(di) - 1)), - ) - }, - exit, - )?; - Ok(()) - })?; - - let mut height_to_halvingepoch_iter = indexes.height_to_halvingepoch.into_iter(); - self.indexes_to_halvingepoch - .compute_all(starting_indexes, exit, |vec| { - let mut height_count_iter = indexes.dateindex_to_height_count.into_iter(); - vec.compute_transform( - starting_indexes.dateindex, - &indexes.dateindex_to_first_height, - |(di, height, ..)| { - ( - di, - height_to_halvingepoch_iter - .get_unwrap(height + (*height_count_iter.get_unwrap(di) - 1)), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_difficulty.compute_rest( - indexes, - starting_indexes, - exit, - Some(&indexer.vecs.block.height_to_difficulty), - )?; - - self.indexes_to_tx_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.tx.height_to_first_txindex, - &indexer.vecs.tx.txindex_to_txid, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_input_count.compute_rest( - indexer, - indexes, - starting_indexes, - exit, - Some(&indexes.txindex_to_input_count), - )?; - - self.indexes_to_output_count.compute_rest( - indexer, - indexes, - starting_indexes, - exit, - Some(&indexes.txindex_to_output_count), - )?; - - let compute_indexes_to_tx_vany = - |indexes_to_tx_vany: &mut ComputedVecsFromHeight, txversion| { - let mut txindex_to_txversion_iter = indexer.vecs.tx.txindex_to_txversion.iter()?; - indexes_to_tx_vany.compute_all(indexes, starting_indexes, exit, |vec| { - vec.compute_filtered_count_from_indexes( - starting_indexes.height, - &indexer.vecs.tx.height_to_first_txindex, - &indexer.vecs.tx.txindex_to_txid, - |txindex| { - let v = txindex_to_txversion_iter.get_unwrap(txindex); - v == txversion - }, - exit, - )?; - Ok(()) - }) - }; - compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v1, TxVersion::ONE)?; - compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v2, TxVersion::TWO)?; - compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v3, TxVersion::THREE)?; - - self.txindex_to_input_value.compute_sum_from_indexes( - starting_indexes.txindex, - &indexer.vecs.tx.txindex_to_first_txinindex, - &indexes.txindex_to_input_count, - &txins.txinindex_to_value, - exit, - )?; - - self.txindex_to_output_value.compute_sum_from_indexes( - starting_indexes.txindex, - &indexer.vecs.tx.txindex_to_first_txoutindex, - &indexes.txindex_to_output_count, - &indexer.vecs.txout.txoutindex_to_value, - exit, - )?; - - self.txindex_to_fee.compute_transform2( - starting_indexes.txindex, - &self.txindex_to_input_value, - &self.txindex_to_output_value, - |(i, input, output, ..)| { - let fee = if unlikely(input.is_max()) { - Sats::ZERO - } else { - input - output - }; - (i, fee) - }, - exit, - )?; - - self.txindex_to_fee_rate.compute_transform2( - starting_indexes.txindex, - &self.txindex_to_fee, - &self.txindex_to_vsize, - |(txindex, fee, vsize, ..)| (txindex, FeeRate::from((fee, vsize))), - exit, - )?; - - self.indexes_to_sent_sum - .compute_all(indexes, price, starting_indexes, exit, |v| { - v.compute_filtered_sum_from_indexes( - starting_indexes.height, - &indexer.vecs.tx.height_to_first_txindex, - &indexes.height_to_txindex_count, - &self.txindex_to_input_value, - |sats| !sats.is_max(), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_fee.compute_rest( - indexer, - indexes, - starting_indexes, - exit, - Some(&self.txindex_to_fee), - price, - )?; - - self.indexes_to_fee_rate.compute_rest( - indexer, - indexes, - starting_indexes, - exit, - Some(&self.txindex_to_fee_rate), - )?; - - self.indexes_to_tx_weight.compute_rest( - indexer, - indexes, - starting_indexes, - exit, - Some(&self.txindex_to_weight), - )?; - - self.indexes_to_tx_vsize.compute_rest( - indexer, - indexes, - starting_indexes, - exit, - Some(&self.txindex_to_vsize), - )?; - - self.indexes_to_coinbase - .compute_all(indexes, price, starting_indexes, exit, |vec| { - let mut txindex_to_first_txoutindex_iter = - indexer.vecs.tx.txindex_to_first_txoutindex.iter()?; - let mut txindex_to_output_count_iter = indexes.txindex_to_output_count.iter(); - let mut txoutindex_to_value_iter = - indexer.vecs.txout.txoutindex_to_value.iter()?; - vec.compute_transform( - starting_indexes.height, - &indexer.vecs.tx.height_to_first_txindex, - |(height, txindex, ..)| { - let first_txoutindex = txindex_to_first_txoutindex_iter - .get_unwrap(txindex) - .to_usize(); - let output_count = txindex_to_output_count_iter.get_unwrap(txindex); - let mut sats = Sats::ZERO; - (first_txoutindex..first_txoutindex + usize::from(output_count)).for_each( - |txoutindex| { - sats += txoutindex_to_value_iter - .get_unwrap(TxOutIndex::from(txoutindex)); - }, - ); - (height, sats) - }, - exit, - )?; - Ok(()) - })?; - - let mut height_to_coinbase_iter = self - .indexes_to_coinbase - .sats - .height - .as_ref() - .unwrap() - .into_iter(); - self.height_to_24h_coinbase_sum.compute_transform( - starting_indexes.height, - &self.height_to_24h_block_count, - |(h, count, ..)| { - let range = *h - (*count - 1)..=*h; - let sum = range - .map(Height::from) - .map(|h| height_to_coinbase_iter.get_unwrap(h)) - .sum::(); - (h, sum) - }, - exit, - )?; - drop(height_to_coinbase_iter); - - if let Some(mut height_to_coinbase_iter) = self - .indexes_to_coinbase - .dollars - .as_ref() - .map(|c| c.height.u().into_iter()) - { - self.height_to_24h_coinbase_usd_sum.compute_transform( - starting_indexes.height, - &self.height_to_24h_block_count, - |(h, count, ..)| { - let range = *h - (*count - 1)..=*h; - let sum = range - .map(Height::from) - .map(|h| height_to_coinbase_iter.get_unwrap(h)) - .sum::(); - (h, sum) - }, - exit, - )?; - } - - self.indexes_to_subsidy - .compute_all(indexes, price, starting_indexes, exit, |vec| { - vec.compute_transform2( - starting_indexes.height, - self.indexes_to_coinbase.sats.height.u(), - self.indexes_to_fee.sats.height.unwrap_sum(), - |(height, coinbase, fees, ..)| { - ( - height, - coinbase.checked_sub(fees).unwrap_or_else(|| { - dbg!(height, coinbase, fees); - panic!() - }), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_unclaimed_rewards.compute_all( - indexes, - price, - starting_indexes, - exit, - |vec| { - vec.compute_transform( - starting_indexes.height, - self.indexes_to_subsidy.sats.height.u(), - |(height, subsidy, ..)| { - let halving = HalvingEpoch::from(height); - let expected = Sats::FIFTY_BTC / 2_usize.pow(halving.to_usize() as u32); - (height, expected.checked_sub(subsidy).unwrap()) - }, - exit, - )?; - Ok(()) - }, - )?; - - self.indexes_to_inflation_rate - .compute_all(starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.dateindex, - self.indexes_to_subsidy.sats.dateindex.unwrap_sum(), - self.indexes_to_subsidy.sats.dateindex.unwrap_cumulative(), - |(i, subsidy_1d_sum, subsidy_cumulative, ..)| { - ( - i, - (365.0 * *subsidy_1d_sum as f64 / *subsidy_cumulative as f64 * 100.0) - .into(), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2a_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2aaddressindex, - &indexer.vecs.address.p2aaddressindex_to_p2abytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2ms_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.output.height_to_first_p2msoutputindex, - &indexer.vecs.output.p2msoutputindex_to_txindex, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2pk33_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2pk33addressindex, - &indexer.vecs.address.p2pk33addressindex_to_p2pk33bytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2pk65_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2pk65addressindex, - &indexer.vecs.address.p2pk65addressindex_to_p2pk65bytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2pkh_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2pkhaddressindex, - &indexer.vecs.address.p2pkhaddressindex_to_p2pkhbytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2sh_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2shaddressindex, - &indexer.vecs.address.p2shaddressindex_to_p2shbytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2tr_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2traddressindex, - &indexer.vecs.address.p2traddressindex_to_p2trbytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2wpkh_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2wpkhaddressindex, - &indexer.vecs.address.p2wpkhaddressindex_to_p2wpkhbytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_p2wsh_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.address.height_to_first_p2wshaddressindex, - &indexer.vecs.address.p2wshaddressindex_to_p2wshbytes, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_opreturn_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.output.height_to_first_opreturnindex, - &indexer.vecs.output.opreturnindex_to_txindex, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_unknownoutput_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.output.height_to_first_unknownoutputindex, - &indexer.vecs.output.unknownoutputindex_to_txindex, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_emptyoutput_count - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.output.height_to_first_emptyoutputindex, - &indexer.vecs.output.emptyoutputindex_to_txindex, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_exact_utxo_count - .compute_all(indexes, starting_indexes, exit, |v| { - let mut input_count_iter = self - .indexes_to_input_count - .height - .unwrap_cumulative() - .into_iter(); - let mut opreturn_count_iter = self - .indexes_to_opreturn_count - .height_extra - .unwrap_cumulative() - .into_iter(); - v.compute_transform( - starting_indexes.height, - self.indexes_to_output_count.height.unwrap_cumulative(), - |(h, output_count, ..)| { - let input_count = input_count_iter.get_unwrap(h); - let opreturn_count = opreturn_count_iter.get_unwrap(h); - let block_count = u64::from(h + 1_usize); - // -1 > genesis output is unspendable - let mut utxo_count = - *output_count - (*input_count - block_count) - *opreturn_count - 1; - - // txid dup: e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468 - // Block 91_722 https://mempool.space/block/00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e - // Block 91_880 https://mempool.space/block/00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721 - // - // txid dup: d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599 - // Block 91_812 https://mempool.space/block/00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f - // Block 91_842 https://mempool.space/block/00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec - // - // Warning: Dups invalidate the previous coinbase according to - // https://chainquery.com/bitcoin-cli/gettxoutsetinfo - - if h >= Height::new(91_842) { - utxo_count -= 1; - } - if h >= Height::new(91_880) { - utxo_count -= 1; - } - - (h, StoredU64::from(utxo_count)) - }, - exit, - )?; - Ok(()) - })?; - - self.dateindex_to_fee_dominance.compute_transform2( - starting_indexes.dateindex, - self.indexes_to_fee.sats.dateindex.unwrap_sum(), - self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), - |(i, fee, coinbase, ..)| { - ( - i, - StoredF32::from(u64::from(fee) as f64 / u64::from(coinbase) as f64 * 100.0), - ) - }, - exit, - )?; - self.dateindex_to_subsidy_dominance.compute_transform2( - starting_indexes.dateindex, - self.indexes_to_subsidy.sats.dateindex.unwrap_sum(), - self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), - |(i, subsidy, coinbase, ..)| { - ( - i, - StoredF32::from(u64::from(subsidy) as f64 / u64::from(coinbase) as f64 * 100.0), - ) - }, - exit, - )?; - - self.indexes_to_difficulty_as_hash - .compute_all(indexes, starting_indexes, exit, |v| { - let multiplier = 2.0_f64.powi(32) / 600.0; - v.compute_transform( - starting_indexes.height, - &indexer.vecs.block.height_to_difficulty, - |(i, v, ..)| (i, StoredF32::from(*v * multiplier)), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_rate - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.height, - &self.height_to_24h_block_count, - self.indexes_to_difficulty_as_hash.height.u(), - |(i, block_count_sum, difficulty_as_hash, ..)| { - ( - i, - StoredF64::from( - (f64::from(block_count_sum) / TARGET_BLOCKS_PER_DAY_F64) - * f64::from(difficulty_as_hash), - ), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_rate_1w_sma - .compute_all(starting_indexes, exit, |v| { - v.compute_sma( - starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), - 7, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_rate_1m_sma - .compute_all(starting_indexes, exit, |v| { - v.compute_sma( - starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), - 30, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_rate_2m_sma - .compute_all(starting_indexes, exit, |v| { - v.compute_sma( - starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), - 2 * 30, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_rate_1y_sma - .compute_all(starting_indexes, exit, |v| { - v.compute_sma( - starting_indexes.dateindex, - self.indexes_to_hash_rate.dateindex.unwrap_last(), - 365, - exit, - )?; - Ok(()) - })?; - - if self.indexes_to_subsidy_usd_1y_sma.is_some() { - let date_to_coinbase_usd_sum = self - .indexes_to_coinbase - .dollars - .as_ref() - .unwrap() - .dateindex - .unwrap_sum(); - - self.indexes_to_subsidy_usd_1y_sma - .as_mut() - .unwrap() - .compute_all(starting_indexes, exit, |v| { - v.compute_sma( - starting_indexes.dateindex, - date_to_coinbase_usd_sum, - 365, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_puell_multiple - .as_mut() - .unwrap() - .compute_all(starting_indexes, exit, |v| { - v.compute_divide( - starting_indexes.dateindex, - date_to_coinbase_usd_sum, - self.indexes_to_subsidy_usd_1y_sma - .as_ref() - .unwrap() - .dateindex - .as_ref() - .unwrap(), - exit, - )?; - Ok(()) - })?; - } - - self.indexes_to_difficulty_adjustment.compute_all( - indexes, - starting_indexes, - exit, - |v| { - v.compute_percentage_change( - starting_indexes.height, - &indexer.vecs.block.height_to_difficulty, - 1, - exit, - )?; - Ok(()) - }, - )?; - - self.indexes_to_blocks_before_next_difficulty_adjustment - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform( - starting_indexes.height, - &indexes.height_to_height, - |(h, ..)| (h, StoredU32::from(h.left_before_next_diff_adj())), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_days_before_next_difficulty_adjustment - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform( - starting_indexes.height, - self.indexes_to_blocks_before_next_difficulty_adjustment - .height - .as_ref() - .unwrap(), - |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_blocks_before_next_halving.compute_all( - indexes, - starting_indexes, - exit, - |v| { - v.compute_transform( - starting_indexes.height, - &indexes.height_to_height, - |(h, ..)| (h, StoredU32::from(h.left_before_next_halving())), - exit, - )?; - Ok(()) - }, - )?; - - self.indexes_to_days_before_next_halving.compute_all( - indexes, - starting_indexes, - exit, - |v| { - v.compute_transform( - starting_indexes.height, - self.indexes_to_blocks_before_next_halving - .height - .as_ref() - .unwrap(), - |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), - exit, - )?; - Ok(()) - }, - )?; - - self.indexes_to_hash_price_ths - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.height, - &self.height_to_24h_coinbase_usd_sum, - self.indexes_to_hash_rate.height.u(), - |(i, coinbase_sum, hashrate, ..)| { - (i, (*coinbase_sum / (*hashrate / ONE_TERA_HASH)).into()) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_price_phs - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform( - starting_indexes.height, - self.indexes_to_hash_price_ths.height.u(), - |(i, price, ..)| (i, (*price * 1000.0).into()), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_value_ths - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.height, - &self.height_to_24h_coinbase_sum, - self.indexes_to_hash_rate.height.u(), - |(i, coinbase_sum, hashrate, ..)| { - ( - i, - (*coinbase_sum as f64 / (*hashrate / ONE_TERA_HASH)).into(), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_value_phs - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_transform( - starting_indexes.height, - self.indexes_to_hash_value_ths.height.u(), - |(i, value, ..)| (i, (*value * 1000.0).into()), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_price_ths_min - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_all_time_low_( - starting_indexes.height, - self.indexes_to_hash_price_ths.height.u(), - exit, - true, - )?; - Ok(()) - })?; - - self.indexes_to_hash_price_phs_min - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_all_time_low_( - starting_indexes.height, - self.indexes_to_hash_price_phs.height.u(), - exit, - true, - )?; - Ok(()) - })?; - - self.indexes_to_hash_value_ths_min - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_all_time_low_( - starting_indexes.height, - self.indexes_to_hash_value_ths.height.u(), - exit, - true, - )?; - Ok(()) - })?; - - self.indexes_to_hash_value_phs_min - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_all_time_low_( - starting_indexes.height, - self.indexes_to_hash_value_phs.height.u(), - exit, - true, - )?; - Ok(()) - })?; - - self.indexes_to_hash_price_rebound - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_percentage_difference( - starting_indexes.height, - self.indexes_to_hash_price_phs.height.u(), - self.indexes_to_hash_price_phs_min.height.u(), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_hash_value_rebound - .compute_all(indexes, starting_indexes, exit, |v| { - v.compute_percentage_difference( - starting_indexes.height, - self.indexes_to_hash_value_phs.height.u(), - self.indexes_to_hash_value_phs_min.height.u(), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_annualized_volume - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_sent_sum.sats.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_annualized_volume_btc - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - self.indexes_to_sent_sum.bitcoin.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_tx_btc_velocity - .compute_all(starting_indexes, exit, |v| { - v.compute_divide( - starting_indexes.dateindex, - self.indexes_to_annualized_volume_btc - .dateindex - .as_ref() - .unwrap(), - self.indexes_to_subsidy - .bitcoin - .dateindex - .unwrap_cumulative(), - exit, - )?; - Ok(()) - })?; - - if let Some(indexes_to_sent_sum) = self.indexes_to_sent_sum.dollars.as_ref() { - self.indexes_to_annualized_volume_usd - .compute_all(starting_indexes, exit, |v| { - v.compute_sum( - starting_indexes.dateindex, - indexes_to_sent_sum.dateindex.unwrap_sum(), - 365, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_tx_usd_velocity - .compute_all(starting_indexes, exit, |v| { - v.compute_divide( - starting_indexes.dateindex, - self.indexes_to_annualized_volume_usd - .dateindex - .as_ref() - .unwrap(), - self.indexes_to_subsidy - .dollars - .as_ref() - .unwrap() - .dateindex - .unwrap_cumulative(), - exit, - )?; - Ok(()) - })?; - } - - self.indexes_to_tx_per_sec - .compute_all(starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.dateindex, - self.indexes_to_tx_count.dateindex.unwrap_sum(), - &indexes.dateindex_to_date, - |(i, tx_count, date, ..)| { - ( - i, - (*tx_count as f64 / (date.completion() * ONE_DAY_IN_SEC_F64)).into(), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_inputs_per_sec - .compute_all(starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.dateindex, - self.indexes_to_input_count.dateindex.unwrap_sum(), - &indexes.dateindex_to_date, - |(i, tx_count, date, ..)| { - ( - i, - (*tx_count as f64 / (date.completion() * ONE_DAY_IN_SEC_F64)).into(), - ) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_outputs_per_sec - .compute_all(starting_indexes, exit, |v| { - v.compute_transform2( - starting_indexes.dateindex, - self.indexes_to_output_count.dateindex.unwrap_sum(), - &indexes.dateindex_to_date, - |(i, tx_count, date, ..)| { - ( - i, - (*tx_count as f64 / (date.completion() * ONE_DAY_IN_SEC_F64)).into(), - ) - }, - exit, - )?; - Ok(()) - })?; - - Ok(()) - } } diff --git a/crates/brk_computer/src/chain/epoch/compute.rs b/crates/brk_computer/src/chain/epoch/compute.rs new file mode 100644 index 000000000..4d2004687 --- /dev/null +++ b/crates/brk_computer/src/chain/epoch/compute.rs @@ -0,0 +1,85 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::Timestamp; +use vecdb::{Exit, TypedVecIterator}; + +use super::Vecs; +use crate::{Indexes, indexes}; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + self.timeindexes_to_timestamp + .compute_all(starting_indexes, exit, |vec| { + vec.compute_transform( + starting_indexes.dateindex, + &indexes.time.dateindex_to_date, + |(di, d, ..)| (di, Timestamp::from(d)), + exit, + )?; + Ok(()) + })?; + + let mut height_to_timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?; + + self.difficultyepoch_to_timestamp.compute_transform( + starting_indexes.difficultyepoch, + &indexes.block.difficultyepoch_to_first_height, + |(i, h, ..)| (i, height_to_timestamp_iter.get_unwrap(h)), + exit, + )?; + + self.halvingepoch_to_timestamp.compute_transform( + starting_indexes.halvingepoch, + &indexes.block.halvingepoch_to_first_height, + |(i, h, ..)| (i, height_to_timestamp_iter.get_unwrap(h)), + exit, + )?; + + let mut height_to_difficultyepoch_iter = + indexes.block.height_to_difficultyepoch.into_iter(); + self.indexes_to_difficultyepoch + .compute_all(starting_indexes, exit, |vec| { + let mut height_count_iter = indexes.time.dateindex_to_height_count.into_iter(); + vec.compute_transform( + starting_indexes.dateindex, + &indexes.time.dateindex_to_first_height, + |(di, height, ..)| { + ( + di, + height_to_difficultyepoch_iter + .get_unwrap(height + (*height_count_iter.get_unwrap(di) - 1)), + ) + }, + exit, + )?; + Ok(()) + })?; + + let mut height_to_halvingepoch_iter = indexes.block.height_to_halvingepoch.into_iter(); + self.indexes_to_halvingepoch + .compute_all(starting_indexes, exit, |vec| { + let mut height_count_iter = indexes.time.dateindex_to_height_count.into_iter(); + vec.compute_transform( + starting_indexes.dateindex, + &indexes.time.dateindex_to_first_height, + |(di, height, ..)| { + ( + di, + height_to_halvingepoch_iter + .get_unwrap(height + (*height_count_iter.get_unwrap(di) - 1)), + ) + }, + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/epoch/import.rs b/crates/brk_computer/src/chain/epoch/import.rs new file mode 100644 index 000000000..ee9dcd141 --- /dev/null +++ b/crates/brk_computer/src/chain/epoch/import.rs @@ -0,0 +1,45 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec}; + +use super::Vecs; +use crate::{ + grouped::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, + indexes, +}; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + let v0 = Version::ZERO; + let last = || VecBuilderOptions::default().add_last(); + + Ok(Self { + difficultyepoch_to_timestamp: EagerVec::forced_import(db, "timestamp", version + v0)?, + halvingepoch_to_timestamp: EagerVec::forced_import(db, "timestamp", version + v0)?, + timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import( + db, + "timestamp", + Source::Compute, + version + v0, + indexes, + VecBuilderOptions::default().add_first(), + )?, + indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import( + db, + "difficultyepoch", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import( + db, + "halvingepoch", + Source::Compute, + version + v0, + indexes, + last(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/epoch/mod.rs b/crates/brk_computer/src/chain/epoch/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/epoch/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/epoch/vecs.rs b/crates/brk_computer/src/chain/epoch/vecs.rs new file mode 100644 index 000000000..cf87f4948 --- /dev/null +++ b/crates/brk_computer/src/chain/epoch/vecs.rs @@ -0,0 +1,15 @@ +use brk_traversable::Traversable; +use brk_types::{DifficultyEpoch, HalvingEpoch, Timestamp}; +use vecdb::{EagerVec, PcoVec}; + +use crate::grouped::ComputedVecsFromDateIndex; + +/// Epoch and timestamp metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub difficultyepoch_to_timestamp: EagerVec>, + pub halvingepoch_to_timestamp: EagerVec>, + pub timeindexes_to_timestamp: ComputedVecsFromDateIndex, + pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex, + pub indexes_to_halvingepoch: ComputedVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/chain/import.rs b/crates/brk_computer/src/chain/import.rs index 5cf18ddf7..ab8a8f450 100644 --- a/crates/brk_computer/src/chain/import.rs +++ b/crates/brk_computer/src/chain/import.rs @@ -3,24 +3,14 @@ use std::path::Path; use brk_error::Result; use brk_indexer::Indexer; use brk_traversable::Traversable; -use brk_types::{StoredBool, StoredU64, TxIndex, Version, Weight}; -use vecdb::{ - Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1, LazyVecFrom2, PAGE_SIZE, - VecIndex, -}; +use brk_types::Version; +use vecdb::{Database, PAGE_SIZE}; -use crate::{ - grouped::{ - ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromDateIndex, - ComputedVecsFromHeight, ComputedVecsFromTxindex, Source, VecBuilderOptions, - }, - indexes, price, -}; +use crate::{indexes, price}; use super::{ - TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DECADE, TARGET_BLOCKS_PER_MONTH, - TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK, - TARGET_BLOCKS_PER_YEAR, Vecs, + BlockVecs, CoinbaseVecs, EpochVecs, MiningVecs, OutputTypeVecs, TransactionVecs, Vecs, + VolumeVecs, }; impl Vecs { @@ -35,470 +25,25 @@ impl Vecs { db.set_min_len(PAGE_SIZE * 50_000_000)?; let version = parent_version + Version::ZERO; - let compute_dollars = price.is_some(); - let v0 = Version::ZERO; - let v2 = Version::TWO; - let v4 = Version::new(4); - let v5 = Version::new(5); - macro_rules! eager { - ($name:expr) => { - EagerVec::forced_import(&db, $name, version + v0)? - }; - ($name:expr, $v:expr) => { - EagerVec::forced_import(&db, $name, version + $v)? - }; - } - macro_rules! computed_h { - ($name:expr, $source:expr, $opts:expr) => { - ComputedVecsFromHeight::forced_import( - &db, - $name, - $source, - version + v0, - indexes, - $opts, - )? - }; - ($name:expr, $source:expr, $v:expr, $opts:expr) => { - ComputedVecsFromHeight::forced_import( - &db, - $name, - $source, - version + $v, - indexes, - $opts, - )? - }; - } - macro_rules! computed_di { - ($name:expr, $opts:expr) => { - ComputedVecsFromDateIndex::forced_import( - &db, - $name, - Source::Compute, - version + v0, - indexes, - $opts, - )? - }; - ($name:expr, $v:expr, $opts:expr) => { - ComputedVecsFromDateIndex::forced_import( - &db, - $name, - Source::Compute, - version + $v, - indexes, - $opts, - )? - }; - } - macro_rules! computed_tx { - ($name:expr, $source:expr, $opts:expr) => { - ComputedVecsFromTxindex::forced_import( - &db, - $name, - $source, - version + v0, - indexes, - $opts, - )? - }; - } - let last = || VecBuilderOptions::default().add_last(); - let sum = || VecBuilderOptions::default().add_sum(); - let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); - let stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - }; - let full_stats = || { - VecBuilderOptions::default() - .add_average() - .add_minmax() - .add_percentiles() - .add_sum() - .add_cumulative() - }; - - let txindex_to_weight = LazyVecFrom2::init( - "weight", - version + Version::ZERO, - indexer.vecs.tx.txindex_to_base_size.boxed_clone(), - indexer.vecs.tx.txindex_to_total_size.boxed_clone(), - |index: TxIndex, txindex_to_base_size_iter, txindex_to_total_size_iter| { - let index = index.to_usize(); - txindex_to_base_size_iter.get_at(index).map(|base_size| { - let total_size = txindex_to_total_size_iter.get_at_unwrap(index); - - // This is the exact definition of a weight unit, as defined by BIP-141 (quote above). - let wu = usize::from(base_size) * 3 + usize::from(total_size); - - Weight::from(bitcoin::Weight::from_wu_usize(wu)) - }) - }, - ); - - let txindex_to_vsize = LazyVecFrom1::init( - "vsize", - version + Version::ZERO, - txindex_to_weight.boxed_clone(), - |index: TxIndex, iter| iter.get(index).map(brk_types::VSize::from), - ); - - let txindex_to_is_coinbase = LazyVecFrom2::init( - "is_coinbase", - version + Version::ZERO, - indexer.vecs.tx.txindex_to_height.boxed_clone(), - indexer.vecs.tx.height_to_first_txindex.boxed_clone(), - |index: TxIndex, txindex_to_height_iter, height_to_first_txindex_iter| { - txindex_to_height_iter.get(index).map(|height| { - let txindex = height_to_first_txindex_iter.get_unwrap(height); - StoredBool::from(index == txindex) - }) - }, - ); - - let txindex_to_input_value = eager!("input_value"); - let txindex_to_output_value = eager!("output_value"); - let txindex_to_fee = eager!("fee"); - let txindex_to_fee_rate = eager!("fee_rate"); - - let dateindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.dateindex_to_dateindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DAY)), - ); - let weekindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.weekindex_to_weekindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_WEEK)), - ); - let monthindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.monthindex_to_monthindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_MONTH)), - ); - let quarterindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.quarterindex_to_quarterindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_QUARTER)), - ); - let semesterindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.semesterindex_to_semesterindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_SEMESTER)), - ); - let yearindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.yearindex_to_yearindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_YEAR)), - ); - let decadeindex_to_block_count_target = LazyVecFrom1::init( - "block_count_target", - version + Version::ZERO, - indexes.decadeindex_to_decadeindex.boxed_clone(), - |_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DECADE)), - ); - - let height_to_interval = eager!("interval"); - let height_to_vbytes = eager!("vbytes"); + let block = BlockVecs::forced_import(&db, version, indexer, indexes)?; + let epoch = EpochVecs::forced_import(&db, version, indexes)?; + let mining = MiningVecs::forced_import(&db, version, indexer, indexes)?; + let coinbase = CoinbaseVecs::forced_import(&db, version, indexes, compute_dollars)?; + let transaction = TransactionVecs::forced_import(&db, version, indexer, indexes, price)?; + let output_type = OutputTypeVecs::forced_import(&db, version, indexes)?; + let volume = VolumeVecs::forced_import(&db, version, indexes, compute_dollars)?; let this = Self { - dateindex_to_block_count_target, - weekindex_to_block_count_target, - monthindex_to_block_count_target, - quarterindex_to_block_count_target, - semesterindex_to_block_count_target, - yearindex_to_block_count_target, - decadeindex_to_block_count_target, - timeindexes_to_timestamp: computed_di!( - "timestamp", - VecBuilderOptions::default().add_first() - ), - indexes_to_block_interval: computed_h!( - "block_interval", - Source::Vec(height_to_interval.boxed_clone()), - stats() - ), - indexes_to_block_count: computed_h!("block_count", Source::Compute, sum_cum()), - indexes_to_1w_block_count: computed_di!("1w_block_count", last()), - indexes_to_1m_block_count: computed_di!("1m_block_count", last()), - indexes_to_1y_block_count: computed_di!("1y_block_count", last()), - indexes_to_block_weight: computed_h!( - "block_weight", - Source::Vec(indexer.vecs.block.height_to_weight.boxed_clone()), - full_stats() - ), - indexes_to_block_size: computed_h!( - "block_size", - Source::Vec(indexer.vecs.block.height_to_total_size.boxed_clone()), - full_stats() - ), - height_to_24h_block_count: eager!("24h_block_count"), - height_to_24h_coinbase_sum: eager!("24h_coinbase_sum"), - height_to_24h_coinbase_usd_sum: eager!("24h_coinbase_usd_sum"), - indexes_to_block_vbytes: computed_h!( - "block_vbytes", - Source::Vec(height_to_vbytes.boxed_clone()), - full_stats() - ), - difficultyepoch_to_timestamp: eager!("timestamp"), - halvingepoch_to_timestamp: eager!("timestamp"), - - dateindex_to_fee_dominance: eager!("fee_dominance"), - dateindex_to_subsidy_dominance: eager!("subsidy_dominance"), - indexes_to_difficulty: computed_h!( - "difficulty", - Source::Vec(indexer.vecs.block.height_to_difficulty.boxed_clone()), - last() - ), - height_to_interval, - height_to_vbytes, - indexes_to_difficultyepoch: computed_di!("difficultyepoch", last()), - indexes_to_halvingepoch: computed_di!("halvingepoch", last()), - indexes_to_tx_count: computed_h!("tx_count", Source::Compute, full_stats()), - indexes_to_input_count: computed_tx!( - "input_count", - Source::Vec(indexes.txindex_to_input_count.boxed_clone()), - full_stats() - ), - indexes_to_output_count: computed_tx!( - "output_count", - Source::Vec(indexes.txindex_to_output_count.boxed_clone()), - full_stats() - ), - indexes_to_tx_v1: computed_h!("tx_v1", Source::Compute, sum_cum()), - indexes_to_tx_v2: computed_h!("tx_v2", Source::Compute, sum_cum()), - indexes_to_tx_v3: computed_h!("tx_v3", Source::Compute, sum_cum()), - indexes_to_sent_sum: ComputedValueVecsFromHeight::forced_import( - &db, - "sent_sum", - Source::Compute, - version + Version::ZERO, - VecBuilderOptions::default().add_sum(), - compute_dollars, - indexes, - )?, - indexes_to_fee: ComputedValueVecsFromTxindex::forced_import( - &db, - "fee", - indexer, - indexes, - Source::Vec(txindex_to_fee.boxed_clone()), - version + Version::ZERO, - price, - VecBuilderOptions::default() - .add_sum() - .add_cumulative() - .add_percentiles() - .add_minmax() - .add_average(), - )?, - indexes_to_fee_rate: computed_tx!( - "fee_rate", - Source::Vec(txindex_to_fee_rate.boxed_clone()), - stats() - ), - indexes_to_tx_vsize: computed_tx!( - "tx_vsize", - Source::Vec(txindex_to_vsize.boxed_clone()), - stats() - ), - indexes_to_tx_weight: computed_tx!( - "tx_weight", - Source::Vec(txindex_to_weight.boxed_clone()), - stats() - ), - indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import( - &db, - "subsidy", - Source::Compute, - version + Version::ZERO, - VecBuilderOptions::default() - .add_percentiles() - .add_sum() - .add_cumulative() - .add_minmax() - .add_average(), - compute_dollars, - indexes, - )?, - indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import( - &db, - "coinbase", - Source::Compute, - version + Version::ZERO, - VecBuilderOptions::default() - .add_sum() - .add_cumulative() - .add_percentiles() - .add_minmax() - .add_average(), - compute_dollars, - indexes, - )?, - indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight::forced_import( - &db, - "unclaimed_rewards", - Source::Compute, - version + Version::ZERO, - VecBuilderOptions::default().add_sum().add_cumulative(), - compute_dollars, - indexes, - )?, - indexes_to_p2a_count: computed_h!("p2a_count", Source::Compute, full_stats()), - indexes_to_p2ms_count: computed_h!("p2ms_count", Source::Compute, full_stats()), - indexes_to_p2pk33_count: computed_h!("p2pk33_count", Source::Compute, full_stats()), - indexes_to_p2pk65_count: computed_h!("p2pk65_count", Source::Compute, full_stats()), - indexes_to_p2pkh_count: computed_h!("p2pkh_count", Source::Compute, full_stats()), - indexes_to_p2sh_count: computed_h!("p2sh_count", Source::Compute, full_stats()), - indexes_to_p2tr_count: computed_h!("p2tr_count", Source::Compute, full_stats()), - indexes_to_p2wpkh_count: computed_h!("p2wpkh_count", Source::Compute, full_stats()), - indexes_to_p2wsh_count: computed_h!("p2wsh_count", Source::Compute, full_stats()), - indexes_to_opreturn_count: computed_h!("opreturn_count", Source::Compute, full_stats()), - indexes_to_unknownoutput_count: computed_h!( - "unknownoutput_count", - Source::Compute, - full_stats() - ), - indexes_to_emptyoutput_count: computed_h!( - "emptyoutput_count", - Source::Compute, - full_stats() - ), - indexes_to_exact_utxo_count: computed_h!("exact_utxo_count", Source::Compute, last()), - indexes_to_subsidy_usd_1y_sma: compute_dollars - .then(|| { - ComputedVecsFromDateIndex::forced_import( - &db, - "subsidy_usd_1y_sma", - Source::Compute, - version + v0, - indexes, - last(), - ) - }) - .transpose()?, - indexes_to_puell_multiple: compute_dollars - .then(|| { - ComputedVecsFromDateIndex::forced_import( - &db, - "puell_multiple", - Source::Compute, - version + v0, - indexes, - last(), - ) - }) - .transpose()?, - indexes_to_hash_rate: computed_h!("hash_rate", Source::Compute, v5, last()), - indexes_to_hash_rate_1w_sma: computed_di!("hash_rate_1w_sma", last()), - indexes_to_hash_rate_1m_sma: computed_di!("hash_rate_1m_sma", last()), - indexes_to_hash_rate_2m_sma: computed_di!("hash_rate_2m_sma", last()), - indexes_to_hash_rate_1y_sma: computed_di!("hash_rate_1y_sma", last()), - indexes_to_difficulty_as_hash: computed_h!( - "difficulty_as_hash", - Source::Compute, - last() - ), - indexes_to_difficulty_adjustment: computed_h!( - "difficulty_adjustment", - Source::Compute, - sum() - ), - indexes_to_blocks_before_next_difficulty_adjustment: computed_h!( - "blocks_before_next_difficulty_adjustment", - Source::Compute, - v2, - last() - ), - indexes_to_days_before_next_difficulty_adjustment: computed_h!( - "days_before_next_difficulty_adjustment", - Source::Compute, - v2, - last() - ), - indexes_to_blocks_before_next_halving: computed_h!( - "blocks_before_next_halving", - Source::Compute, - v2, - last() - ), - indexes_to_days_before_next_halving: computed_h!( - "days_before_next_halving", - Source::Compute, - v2, - last() - ), - indexes_to_hash_price_ths: computed_h!("hash_price_ths", Source::Compute, v4, last()), - indexes_to_hash_price_phs: computed_h!("hash_price_phs", Source::Compute, v4, last()), - indexes_to_hash_value_ths: computed_h!("hash_value_ths", Source::Compute, v4, last()), - indexes_to_hash_value_phs: computed_h!("hash_value_phs", Source::Compute, v4, last()), - indexes_to_hash_price_ths_min: computed_h!( - "hash_price_ths_min", - Source::Compute, - v4, - last() - ), - indexes_to_hash_price_phs_min: computed_h!( - "hash_price_phs_min", - Source::Compute, - v4, - last() - ), - indexes_to_hash_price_rebound: computed_h!( - "hash_price_rebound", - Source::Compute, - v4, - last() - ), - indexes_to_hash_value_ths_min: computed_h!( - "hash_value_ths_min", - Source::Compute, - v4, - last() - ), - indexes_to_hash_value_phs_min: computed_h!( - "hash_value_phs_min", - Source::Compute, - v4, - last() - ), - indexes_to_hash_value_rebound: computed_h!( - "hash_value_rebound", - Source::Compute, - v4, - last() - ), - indexes_to_inflation_rate: computed_di!("inflation_rate", last()), - indexes_to_annualized_volume: computed_di!("annualized_volume", last()), - indexes_to_annualized_volume_btc: computed_di!("annualized_volume_btc", last()), - indexes_to_annualized_volume_usd: computed_di!("annualized_volume_usd", last()), - indexes_to_tx_btc_velocity: computed_di!("tx_btc_velocity", last()), - indexes_to_tx_usd_velocity: computed_di!("tx_usd_velocity", last()), - indexes_to_tx_per_sec: computed_di!("tx_per_sec", v2, last()), - indexes_to_outputs_per_sec: computed_di!("outputs_per_sec", v2, last()), - indexes_to_inputs_per_sec: computed_di!("inputs_per_sec", v2, last()), - - txindex_to_is_coinbase, - txindex_to_input_value, - txindex_to_output_value, - txindex_to_fee, - txindex_to_fee_rate, - txindex_to_vsize, - txindex_to_weight, - db, + block, + epoch, + mining, + coinbase, + transaction, + output_type, + volume, }; this.db.retain_regions( diff --git a/crates/brk_computer/src/chain/mining/compute.rs b/crates/brk_computer/src/chain/mining/compute.rs new file mode 100644 index 000000000..2298d97ee --- /dev/null +++ b/crates/brk_computer/src/chain/mining/compute.rs @@ -0,0 +1,301 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{StoredF32, StoredF64, StoredU32}; +use vecdb::Exit; + +use super::Vecs; +use crate::{ + chain::{block, coinbase, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F32, TARGET_BLOCKS_PER_DAY_F64}, + indexes, + utils::OptionExt, + Indexes, +}; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + block_vecs: &block::Vecs, + coinbase_vecs: &coinbase::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + self.indexes_to_difficulty.compute_rest( + indexes, + starting_indexes, + exit, + Some(&indexer.vecs.block.height_to_difficulty), + )?; + + self.indexes_to_difficulty_as_hash + .compute_all(indexes, starting_indexes, exit, |v| { + let multiplier = 2.0_f64.powi(32) / 600.0; + v.compute_transform( + starting_indexes.height, + &indexer.vecs.block.height_to_difficulty, + |(i, v, ..)| (i, StoredF32::from(*v * multiplier)), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_rate + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.height, + &block_vecs.height_to_24h_block_count, + self.indexes_to_difficulty_as_hash.height.u(), + |(i, block_count_sum, difficulty_as_hash, ..)| { + ( + i, + StoredF64::from( + (f64::from(block_count_sum) / TARGET_BLOCKS_PER_DAY_F64) + * f64::from(difficulty_as_hash), + ), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_rate_1w_sma + .compute_all(starting_indexes, exit, |v| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.unwrap_last(), + 7, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_rate_1m_sma + .compute_all(starting_indexes, exit, |v| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.unwrap_last(), + 30, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_rate_2m_sma + .compute_all(starting_indexes, exit, |v| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.unwrap_last(), + 2 * 30, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_rate_1y_sma + .compute_all(starting_indexes, exit, |v| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.unwrap_last(), + 365, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_difficulty_adjustment.compute_all( + indexes, + starting_indexes, + exit, + |v| { + v.compute_percentage_change( + starting_indexes.height, + &indexer.vecs.block.height_to_difficulty, + 1, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_blocks_before_next_difficulty_adjustment + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform( + starting_indexes.height, + &indexes.block.height_to_height, + |(h, ..)| (h, StoredU32::from(h.left_before_next_diff_adj())), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_days_before_next_difficulty_adjustment + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform( + starting_indexes.height, + self.indexes_to_blocks_before_next_difficulty_adjustment + .height + .as_ref() + .unwrap(), + |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_blocks_before_next_halving.compute_all( + indexes, + starting_indexes, + exit, + |v| { + v.compute_transform( + starting_indexes.height, + &indexes.block.height_to_height, + |(h, ..)| (h, StoredU32::from(h.left_before_next_halving())), + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_days_before_next_halving.compute_all( + indexes, + starting_indexes, + exit, + |v| { + v.compute_transform( + starting_indexes.height, + self.indexes_to_blocks_before_next_halving + .height + .as_ref() + .unwrap(), + |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_hash_price_ths + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.height, + &coinbase_vecs.height_to_24h_coinbase_usd_sum, + self.indexes_to_hash_rate.height.u(), + |(i, coinbase_sum, hashrate, ..)| { + (i, (*coinbase_sum / (*hashrate / ONE_TERA_HASH)).into()) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_phs + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform( + starting_indexes.height, + self.indexes_to_hash_price_ths.height.u(), + |(i, price, ..)| (i, (*price * 1000.0).into()), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_ths + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.height, + &coinbase_vecs.height_to_24h_coinbase_sum, + self.indexes_to_hash_rate.height.u(), + |(i, coinbase_sum, hashrate, ..)| { + ( + i, + (*coinbase_sum as f64 / (*hashrate / ONE_TERA_HASH)).into(), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_phs + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_transform( + starting_indexes.height, + self.indexes_to_hash_value_ths.height.u(), + |(i, value, ..)| (i, (*value * 1000.0).into()), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_ths_min + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.height, + self.indexes_to_hash_price_ths.height.u(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_phs_min + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.height, + self.indexes_to_hash_price_phs.height.u(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_ths_min + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.height, + self.indexes_to_hash_value_ths.height.u(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_phs_min + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.height, + self.indexes_to_hash_value_phs.height.u(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_rebound + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_percentage_difference( + starting_indexes.height, + self.indexes_to_hash_price_phs.height.u(), + self.indexes_to_hash_price_phs_min.height.u(), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_rebound + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_percentage_difference( + starting_indexes.height, + self.indexes_to_hash_value_phs.height.u(), + self.indexes_to_hash_value_phs_min.height.u(), + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/mining/import.rs b/crates/brk_computer/src/chain/mining/import.rs new file mode 100644 index 000000000..505ee2241 --- /dev/null +++ b/crates/brk_computer/src/chain/mining/import.rs @@ -0,0 +1,208 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::Version; +use vecdb::{Database, IterableCloneableVec}; + +use super::Vecs; +use crate::{ + grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions}, + indexes, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexer: &Indexer, + indexes: &indexes::Vecs, + ) -> Result { + let v0 = Version::ZERO; + let v2 = Version::TWO; + let v4 = Version::new(4); + let v5 = Version::new(5); + + let last = || VecBuilderOptions::default().add_last(); + let sum = || VecBuilderOptions::default().add_sum(); + + Ok(Self { + indexes_to_hash_rate: ComputedVecsFromHeight::forced_import( + db, + "hash_rate", + Source::Compute, + version + v5, + indexes, + last(), + )?, + indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex::forced_import( + db, + "hash_rate_1w_sma", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex::forced_import( + db, + "hash_rate_1m_sma", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex::forced_import( + db, + "hash_rate_2m_sma", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex::forced_import( + db, + "hash_rate_1y_sma", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_hash_price_ths: ComputedVecsFromHeight::forced_import( + db, + "hash_price_ths", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_price_ths_min: ComputedVecsFromHeight::forced_import( + db, + "hash_price_ths_min", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_price_phs: ComputedVecsFromHeight::forced_import( + db, + "hash_price_phs", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_price_phs_min: ComputedVecsFromHeight::forced_import( + db, + "hash_price_phs_min", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_price_rebound: ComputedVecsFromHeight::forced_import( + db, + "hash_price_rebound", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_value_ths: ComputedVecsFromHeight::forced_import( + db, + "hash_value_ths", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_value_ths_min: ComputedVecsFromHeight::forced_import( + db, + "hash_value_ths_min", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_value_phs: ComputedVecsFromHeight::forced_import( + db, + "hash_value_phs", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_value_phs_min: ComputedVecsFromHeight::forced_import( + db, + "hash_value_phs_min", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_hash_value_rebound: ComputedVecsFromHeight::forced_import( + db, + "hash_value_rebound", + Source::Compute, + version + v4, + indexes, + last(), + )?, + indexes_to_difficulty: ComputedVecsFromHeight::forced_import( + db, + "difficulty", + Source::Vec(indexer.vecs.block.height_to_difficulty.boxed_clone()), + version + v0, + indexes, + last(), + )?, + indexes_to_difficulty_as_hash: ComputedVecsFromHeight::forced_import( + db, + "difficulty_as_hash", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_difficulty_adjustment: ComputedVecsFromHeight::forced_import( + db, + "difficulty_adjustment", + Source::Compute, + version + v0, + indexes, + sum(), + )?, + indexes_to_blocks_before_next_difficulty_adjustment: + ComputedVecsFromHeight::forced_import( + db, + "blocks_before_next_difficulty_adjustment", + Source::Compute, + version + v2, + indexes, + last(), + )?, + indexes_to_days_before_next_difficulty_adjustment: + ComputedVecsFromHeight::forced_import( + db, + "days_before_next_difficulty_adjustment", + Source::Compute, + version + v2, + indexes, + last(), + )?, + indexes_to_blocks_before_next_halving: ComputedVecsFromHeight::forced_import( + db, + "blocks_before_next_halving", + Source::Compute, + version + v2, + indexes, + last(), + )?, + indexes_to_days_before_next_halving: ComputedVecsFromHeight::forced_import( + db, + "days_before_next_halving", + Source::Compute, + version + v2, + indexes, + last(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/mining/mod.rs b/crates/brk_computer/src/chain/mining/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/mining/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/mining/vecs.rs b/crates/brk_computer/src/chain/mining/vecs.rs new file mode 100644 index 000000000..b11ef72ae --- /dev/null +++ b/crates/brk_computer/src/chain/mining/vecs.rs @@ -0,0 +1,31 @@ +use brk_traversable::Traversable; +use brk_types::{StoredF32, StoredF64, StoredU32}; + +use crate::grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight}; + +/// Mining-related metrics: hash rate, hash price, hash value, difficulty +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_hash_rate: ComputedVecsFromHeight, + pub indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_price_ths: ComputedVecsFromHeight, + pub indexes_to_hash_price_ths_min: ComputedVecsFromHeight, + pub indexes_to_hash_price_phs: ComputedVecsFromHeight, + pub indexes_to_hash_price_phs_min: ComputedVecsFromHeight, + pub indexes_to_hash_price_rebound: ComputedVecsFromHeight, + pub indexes_to_hash_value_ths: ComputedVecsFromHeight, + pub indexes_to_hash_value_ths_min: ComputedVecsFromHeight, + pub indexes_to_hash_value_phs: ComputedVecsFromHeight, + pub indexes_to_hash_value_phs_min: ComputedVecsFromHeight, + pub indexes_to_hash_value_rebound: ComputedVecsFromHeight, + pub indexes_to_difficulty: ComputedVecsFromHeight, + pub indexes_to_difficulty_as_hash: ComputedVecsFromHeight, + pub indexes_to_difficulty_adjustment: ComputedVecsFromHeight, + pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedVecsFromHeight, + pub indexes_to_days_before_next_difficulty_adjustment: ComputedVecsFromHeight, + pub indexes_to_blocks_before_next_halving: ComputedVecsFromHeight, + pub indexes_to_days_before_next_halving: ComputedVecsFromHeight, +} diff --git a/crates/brk_computer/src/chain/mod.rs b/crates/brk_computer/src/chain/mod.rs index 3afebb6d5..116107a62 100644 --- a/crates/brk_computer/src/chain/mod.rs +++ b/crates/brk_computer/src/chain/mod.rs @@ -1,18 +1,23 @@ +pub mod block; +pub mod coinbase; mod compute; +pub mod epoch; mod import; +pub mod mining; +pub mod output_type; +pub mod transaction; +pub mod volume; use brk_traversable::Traversable; -use brk_types::{ - Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, FeeRate, HalvingEpoch, Height, - MonthIndex, QuarterIndex, Sats, SemesterIndex, StoredBool, StoredF32, StoredF64, StoredU32, - StoredU64, Timestamp, TxIndex, VSize, WeekIndex, Weight, YearIndex, -}; -use vecdb::{Database, EagerVec, LazyVecFrom1, LazyVecFrom2, PcoVec}; +use vecdb::Database; -use crate::grouped::{ - ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromDateIndex, - ComputedVecsFromHeight, ComputedVecsFromTxindex, -}; +pub use block::Vecs as BlockVecs; +pub use coinbase::Vecs as CoinbaseVecs; +pub use epoch::Vecs as EpochVecs; +pub use mining::Vecs as MiningVecs; +pub use output_type::Vecs as OutputTypeVecs; +pub use transaction::Vecs as TransactionVecs; +pub use volume::Vecs as VolumeVecs; pub const DB_NAME: &str = "chain"; @@ -27,107 +32,16 @@ pub(crate) const TARGET_BLOCKS_PER_YEAR: u64 = 2 * TARGET_BLOCKS_PER_SEMESTER; pub(crate) const TARGET_BLOCKS_PER_DECADE: u64 = 10 * TARGET_BLOCKS_PER_YEAR; pub(crate) const ONE_TERA_HASH: f64 = 1_000_000_000_000.0; +/// Main chain metrics struct composed of sub-modules #[derive(Clone, Traversable)] pub struct Vecs { + #[traversable(skip)] pub(crate) db: Database, - - pub dateindex_to_block_count_target: LazyVecFrom1, - pub weekindex_to_block_count_target: LazyVecFrom1, - pub monthindex_to_block_count_target: - LazyVecFrom1, - pub quarterindex_to_block_count_target: - LazyVecFrom1, - pub semesterindex_to_block_count_target: - LazyVecFrom1, - pub yearindex_to_block_count_target: LazyVecFrom1, - pub decadeindex_to_block_count_target: - LazyVecFrom1, - pub height_to_interval: EagerVec>, - pub height_to_24h_block_count: EagerVec>, - pub height_to_24h_coinbase_sum: EagerVec>, - pub height_to_24h_coinbase_usd_sum: EagerVec>, - pub height_to_vbytes: EagerVec>, - pub difficultyepoch_to_timestamp: EagerVec>, - pub halvingepoch_to_timestamp: EagerVec>, - pub timeindexes_to_timestamp: ComputedVecsFromDateIndex, - pub indexes_to_block_count: ComputedVecsFromHeight, - pub indexes_to_1w_block_count: ComputedVecsFromDateIndex, - pub indexes_to_1m_block_count: ComputedVecsFromDateIndex, - pub indexes_to_1y_block_count: ComputedVecsFromDateIndex, - pub indexes_to_block_interval: ComputedVecsFromHeight, - pub indexes_to_block_size: ComputedVecsFromHeight, - pub indexes_to_block_vbytes: ComputedVecsFromHeight, - pub indexes_to_block_weight: ComputedVecsFromHeight, - pub indexes_to_difficulty: ComputedVecsFromHeight, - pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex, - pub indexes_to_halvingepoch: ComputedVecsFromDateIndex, - pub indexes_to_coinbase: ComputedValueVecsFromHeight, - pub indexes_to_emptyoutput_count: ComputedVecsFromHeight, - pub indexes_to_fee: ComputedValueVecsFromTxindex, - pub indexes_to_fee_rate: ComputedVecsFromTxindex, - /// Value == 0 when Coinbase - pub txindex_to_input_value: EagerVec>, - pub indexes_to_sent_sum: ComputedValueVecsFromHeight, - pub indexes_to_opreturn_count: ComputedVecsFromHeight, - pub txindex_to_output_value: EagerVec>, - pub indexes_to_p2a_count: ComputedVecsFromHeight, - pub indexes_to_p2ms_count: ComputedVecsFromHeight, - pub indexes_to_p2pk33_count: ComputedVecsFromHeight, - pub indexes_to_p2pk65_count: ComputedVecsFromHeight, - pub indexes_to_p2pkh_count: ComputedVecsFromHeight, - pub indexes_to_p2sh_count: ComputedVecsFromHeight, - pub indexes_to_p2tr_count: ComputedVecsFromHeight, - pub indexes_to_p2wpkh_count: ComputedVecsFromHeight, - pub indexes_to_p2wsh_count: ComputedVecsFromHeight, - pub indexes_to_subsidy: ComputedValueVecsFromHeight, - pub indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight, - pub indexes_to_tx_count: ComputedVecsFromHeight, - pub indexes_to_tx_v1: ComputedVecsFromHeight, - pub indexes_to_tx_v2: ComputedVecsFromHeight, - pub indexes_to_tx_v3: ComputedVecsFromHeight, - pub indexes_to_tx_vsize: ComputedVecsFromTxindex, - pub indexes_to_tx_weight: ComputedVecsFromTxindex, - pub indexes_to_unknownoutput_count: ComputedVecsFromHeight, - pub indexes_to_input_count: ComputedVecsFromTxindex, - pub txindex_to_is_coinbase: LazyVecFrom2, - pub indexes_to_output_count: ComputedVecsFromTxindex, - pub txindex_to_vsize: LazyVecFrom1, - pub txindex_to_weight: LazyVecFrom2, - pub txindex_to_fee: EagerVec>, - pub txindex_to_fee_rate: EagerVec>, - pub indexes_to_exact_utxo_count: ComputedVecsFromHeight, - pub dateindex_to_fee_dominance: EagerVec>, - pub dateindex_to_subsidy_dominance: EagerVec>, - pub indexes_to_subsidy_usd_1y_sma: Option>, - pub indexes_to_puell_multiple: Option>, - pub indexes_to_hash_rate: ComputedVecsFromHeight, - pub indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex, - pub indexes_to_hash_price_ths: ComputedVecsFromHeight, - pub indexes_to_hash_price_ths_min: ComputedVecsFromHeight, - pub indexes_to_hash_price_phs: ComputedVecsFromHeight, - pub indexes_to_hash_price_phs_min: ComputedVecsFromHeight, - pub indexes_to_hash_price_rebound: ComputedVecsFromHeight, - pub indexes_to_hash_value_ths: ComputedVecsFromHeight, - pub indexes_to_hash_value_ths_min: ComputedVecsFromHeight, - pub indexes_to_hash_value_phs: ComputedVecsFromHeight, - pub indexes_to_hash_value_phs_min: ComputedVecsFromHeight, - pub indexes_to_hash_value_rebound: ComputedVecsFromHeight, - pub indexes_to_difficulty_as_hash: ComputedVecsFromHeight, - pub indexes_to_difficulty_adjustment: ComputedVecsFromHeight, - pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedVecsFromHeight, - pub indexes_to_days_before_next_difficulty_adjustment: ComputedVecsFromHeight, - pub indexes_to_blocks_before_next_halving: ComputedVecsFromHeight, - pub indexes_to_days_before_next_halving: ComputedVecsFromHeight, - pub indexes_to_inflation_rate: ComputedVecsFromDateIndex, - pub indexes_to_annualized_volume: ComputedVecsFromDateIndex, - pub indexes_to_annualized_volume_btc: ComputedVecsFromDateIndex, - pub indexes_to_annualized_volume_usd: ComputedVecsFromDateIndex, - pub indexes_to_tx_btc_velocity: ComputedVecsFromDateIndex, - pub indexes_to_tx_usd_velocity: ComputedVecsFromDateIndex, - pub indexes_to_tx_per_sec: ComputedVecsFromDateIndex, - pub indexes_to_outputs_per_sec: ComputedVecsFromDateIndex, - pub indexes_to_inputs_per_sec: ComputedVecsFromDateIndex, + pub block: BlockVecs, + pub epoch: EpochVecs, + pub mining: MiningVecs, + pub coinbase: CoinbaseVecs, + pub transaction: TransactionVecs, + pub output_type: OutputTypeVecs, + pub volume: VolumeVecs, } diff --git a/crates/brk_computer/src/chain/output_type/compute.rs b/crates/brk_computer/src/chain/output_type/compute.rs new file mode 100644 index 000000000..0d1402022 --- /dev/null +++ b/crates/brk_computer/src/chain/output_type/compute.rs @@ -0,0 +1,203 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{Height, StoredU64}; +use vecdb::{Exit, TypedVecIterator}; + +use super::Vecs; +use crate::{chain::transaction, indexes, Indexes}; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + transaction_vecs: &transaction::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + self.indexes_to_p2a_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2aaddressindex, + &indexer.vecs.address.p2aaddressindex_to_p2abytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2ms_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.output.height_to_first_p2msoutputindex, + &indexer.vecs.output.p2msoutputindex_to_txindex, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2pk33_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2pk33addressindex, + &indexer.vecs.address.p2pk33addressindex_to_p2pk33bytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2pk65_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2pk65addressindex, + &indexer.vecs.address.p2pk65addressindex_to_p2pk65bytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2pkh_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2pkhaddressindex, + &indexer.vecs.address.p2pkhaddressindex_to_p2pkhbytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2sh_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2shaddressindex, + &indexer.vecs.address.p2shaddressindex_to_p2shbytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2tr_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2traddressindex, + &indexer.vecs.address.p2traddressindex_to_p2trbytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2wpkh_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2wpkhaddressindex, + &indexer.vecs.address.p2wpkhaddressindex_to_p2wpkhbytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_p2wsh_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.address.height_to_first_p2wshaddressindex, + &indexer.vecs.address.p2wshaddressindex_to_p2wshbytes, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_opreturn_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.output.height_to_first_opreturnindex, + &indexer.vecs.output.opreturnindex_to_txindex, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_unknownoutput_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.output.height_to_first_unknownoutputindex, + &indexer.vecs.output.unknownoutputindex_to_txindex, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_emptyoutput_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.output.height_to_first_emptyoutputindex, + &indexer.vecs.output.emptyoutputindex_to_txindex, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_exact_utxo_count + .compute_all(indexes, starting_indexes, exit, |v| { + let mut input_count_iter = transaction_vecs + .indexes_to_input_count + .height + .unwrap_cumulative() + .into_iter(); + let mut opreturn_count_iter = self + .indexes_to_opreturn_count + .height_extra + .unwrap_cumulative() + .into_iter(); + v.compute_transform( + starting_indexes.height, + transaction_vecs + .indexes_to_output_count + .height + .unwrap_cumulative(), + |(h, output_count, ..)| { + let input_count = input_count_iter.get_unwrap(h); + let opreturn_count = opreturn_count_iter.get_unwrap(h); + let block_count = u64::from(h + 1_usize); + // -1 > genesis output is unspendable + let mut utxo_count = + *output_count - (*input_count - block_count) - *opreturn_count - 1; + + // txid dup: e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468 + // Block 91_722 https://mempool.space/block/00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e + // Block 91_880 https://mempool.space/block/00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721 + // + // txid dup: d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599 + // Block 91_812 https://mempool.space/block/00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f + // Block 91_842 https://mempool.space/block/00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec + // + // Warning: Dups invalidate the previous coinbase according to + // https://chainquery.com/bitcoin-cli/gettxoutsetinfo + + if h >= Height::new(91_842) { + utxo_count -= 1; + } + if h >= Height::new(91_880) { + utxo_count -= 1; + } + + (h, StoredU64::from(utxo_count)) + }, + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/output_type/import.rs b/crates/brk_computer/src/chain/output_type/import.rs new file mode 100644 index 000000000..2d42843b3 --- /dev/null +++ b/crates/brk_computer/src/chain/output_type/import.rs @@ -0,0 +1,131 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::Database; + +use super::Vecs; +use crate::{ + grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions}, + indexes, +}; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + let v0 = Version::ZERO; + let last = || VecBuilderOptions::default().add_last(); + let full_stats = || { + VecBuilderOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + .add_sum() + .add_cumulative() + }; + + Ok(Self { + indexes_to_p2a_count: ComputedVecsFromHeight::forced_import( + db, + "p2a_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2ms_count: ComputedVecsFromHeight::forced_import( + db, + "p2ms_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2pk33_count: ComputedVecsFromHeight::forced_import( + db, + "p2pk33_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2pk65_count: ComputedVecsFromHeight::forced_import( + db, + "p2pk65_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2pkh_count: ComputedVecsFromHeight::forced_import( + db, + "p2pkh_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2sh_count: ComputedVecsFromHeight::forced_import( + db, + "p2sh_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2tr_count: ComputedVecsFromHeight::forced_import( + db, + "p2tr_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2wpkh_count: ComputedVecsFromHeight::forced_import( + db, + "p2wpkh_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_p2wsh_count: ComputedVecsFromHeight::forced_import( + db, + "p2wsh_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_opreturn_count: ComputedVecsFromHeight::forced_import( + db, + "opreturn_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_emptyoutput_count: ComputedVecsFromHeight::forced_import( + db, + "emptyoutput_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_unknownoutput_count: ComputedVecsFromHeight::forced_import( + db, + "unknownoutput_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_exact_utxo_count: ComputedVecsFromHeight::forced_import( + db, + "exact_utxo_count", + Source::Compute, + version + v0, + indexes, + last(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/output_type/mod.rs b/crates/brk_computer/src/chain/output_type/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/output_type/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/output_type/vecs.rs b/crates/brk_computer/src/chain/output_type/vecs.rs new file mode 100644 index 000000000..ab3dc5cd7 --- /dev/null +++ b/crates/brk_computer/src/chain/output_type/vecs.rs @@ -0,0 +1,22 @@ +use brk_traversable::Traversable; +use brk_types::StoredU64; + +use crate::grouped::ComputedVecsFromHeight; + +/// Output type count metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_p2a_count: ComputedVecsFromHeight, + pub indexes_to_p2ms_count: ComputedVecsFromHeight, + pub indexes_to_p2pk33_count: ComputedVecsFromHeight, + pub indexes_to_p2pk65_count: ComputedVecsFromHeight, + pub indexes_to_p2pkh_count: ComputedVecsFromHeight, + pub indexes_to_p2sh_count: ComputedVecsFromHeight, + pub indexes_to_p2tr_count: ComputedVecsFromHeight, + pub indexes_to_p2wpkh_count: ComputedVecsFromHeight, + pub indexes_to_p2wsh_count: ComputedVecsFromHeight, + pub indexes_to_opreturn_count: ComputedVecsFromHeight, + pub indexes_to_emptyoutput_count: ComputedVecsFromHeight, + pub indexes_to_unknownoutput_count: ComputedVecsFromHeight, + pub indexes_to_exact_utxo_count: ComputedVecsFromHeight, +} diff --git a/crates/brk_computer/src/chain/transaction/compute.rs b/crates/brk_computer/src/chain/transaction/compute.rs new file mode 100644 index 000000000..293ee2834 --- /dev/null +++ b/crates/brk_computer/src/chain/transaction/compute.rs @@ -0,0 +1,141 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{FeeRate, Sats, StoredU64, TxVersion}; +use vecdb::{Exit, TypedVecIterator, unlikely}; + +use super::Vecs; +use crate::{Indexes, grouped::ComputedVecsFromHeight, indexes, price, txins}; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + txins: &txins::Vecs, + starting_indexes: &Indexes, + price: Option<&price::Vecs>, + exit: &Exit, + ) -> Result<()> { + self.indexes_to_tx_count + .compute_all(indexes, starting_indexes, exit, |v| { + v.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.tx.height_to_first_txindex, + &indexer.vecs.tx.txindex_to_txid, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_input_count.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(&indexes.transaction.txindex_to_input_count), + )?; + + self.indexes_to_output_count.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(&indexes.transaction.txindex_to_output_count), + )?; + + let compute_indexes_to_tx_vany = + |indexes_to_tx_vany: &mut ComputedVecsFromHeight, txversion: TxVersion| { + let mut txindex_to_txversion_iter = indexer.vecs.tx.txindex_to_txversion.iter()?; + indexes_to_tx_vany.compute_all(indexes, starting_indexes, exit, |vec| { + vec.compute_filtered_count_from_indexes( + starting_indexes.height, + &indexer.vecs.tx.height_to_first_txindex, + &indexer.vecs.tx.txindex_to_txid, + |txindex| { + let v = txindex_to_txversion_iter.get_unwrap(txindex); + v == txversion + }, + exit, + )?; + Ok(()) + }) + }; + compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v1, TxVersion::ONE)?; + compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v2, TxVersion::TWO)?; + compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v3, TxVersion::THREE)?; + + self.txindex_to_input_value.compute_sum_from_indexes( + starting_indexes.txindex, + &indexer.vecs.tx.txindex_to_first_txinindex, + &indexes.transaction.txindex_to_input_count, + &txins.txinindex_to_value, + exit, + )?; + + self.txindex_to_output_value.compute_sum_from_indexes( + starting_indexes.txindex, + &indexer.vecs.tx.txindex_to_first_txoutindex, + &indexes.transaction.txindex_to_output_count, + &indexer.vecs.txout.txoutindex_to_value, + exit, + )?; + + self.txindex_to_fee.compute_transform2( + starting_indexes.txindex, + &self.txindex_to_input_value, + &self.txindex_to_output_value, + |(i, input, output, ..)| { + let fee = if unlikely(input.is_max()) { + Sats::ZERO + } else { + input - output + }; + (i, fee) + }, + exit, + )?; + + self.txindex_to_fee_rate.compute_transform2( + starting_indexes.txindex, + &self.txindex_to_fee, + &self.txindex_to_vsize, + |(txindex, fee, vsize, ..)| (txindex, FeeRate::from((fee, vsize))), + exit, + )?; + + self.indexes_to_fee.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(&self.txindex_to_fee), + price, + )?; + + self.indexes_to_fee_rate.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(&self.txindex_to_fee_rate), + )?; + + self.indexes_to_tx_weight.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(&self.txindex_to_weight), + )?; + + self.indexes_to_tx_vsize.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(&self.txindex_to_vsize), + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/transaction/import.rs b/crates/brk_computer/src/chain/transaction/import.rs new file mode 100644 index 000000000..aab812bbe --- /dev/null +++ b/crates/brk_computer/src/chain/transaction/import.rs @@ -0,0 +1,180 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{StoredBool, TxIndex, VSize, Version, Weight}; +use vecdb::{ + Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1, LazyVecFrom2, VecIndex, +}; + +use super::Vecs; +use crate::{ + grouped::{ + ComputedValueVecsFromTxindex, ComputedVecsFromHeight, ComputedVecsFromTxindex, Source, + VecBuilderOptions, + }, + indexes, price, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexer: &Indexer, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + ) -> Result { + let v0 = Version::ZERO; + + let stats = || { + VecBuilderOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + }; + let full_stats = || { + VecBuilderOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + .add_sum() + .add_cumulative() + }; + let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative(); + + let txindex_to_weight = LazyVecFrom2::init( + "weight", + version + v0, + indexer.vecs.tx.txindex_to_base_size.boxed_clone(), + indexer.vecs.tx.txindex_to_total_size.boxed_clone(), + |index: TxIndex, txindex_to_base_size_iter, txindex_to_total_size_iter| { + let index = index.to_usize(); + txindex_to_base_size_iter.get_at(index).map(|base_size| { + let total_size = txindex_to_total_size_iter.get_at_unwrap(index); + let wu = usize::from(base_size) * 3 + usize::from(total_size); + Weight::from(bitcoin::Weight::from_wu_usize(wu)) + }) + }, + ); + + let txindex_to_vsize = LazyVecFrom1::init( + "vsize", + version + v0, + txindex_to_weight.boxed_clone(), + |index: TxIndex, iter| iter.get(index).map(VSize::from), + ); + + let txindex_to_is_coinbase = LazyVecFrom2::init( + "is_coinbase", + version + v0, + indexer.vecs.tx.txindex_to_height.boxed_clone(), + indexer.vecs.tx.height_to_first_txindex.boxed_clone(), + |index: TxIndex, txindex_to_height_iter, height_to_first_txindex_iter| { + txindex_to_height_iter.get(index).map(|height| { + let txindex = height_to_first_txindex_iter.get_unwrap(height); + StoredBool::from(index == txindex) + }) + }, + ); + + let txindex_to_input_value = EagerVec::forced_import(db, "input_value", version + v0)?; + let txindex_to_output_value = EagerVec::forced_import(db, "output_value", version + v0)?; + let txindex_to_fee = EagerVec::forced_import(db, "fee", version + v0)?; + let txindex_to_fee_rate = EagerVec::forced_import(db, "fee_rate", version + v0)?; + + Ok(Self { + indexes_to_tx_count: ComputedVecsFromHeight::forced_import( + db, + "tx_count", + Source::Compute, + version + v0, + indexes, + full_stats(), + )?, + indexes_to_tx_v1: ComputedVecsFromHeight::forced_import( + db, + "tx_v1", + Source::Compute, + version + v0, + indexes, + sum_cum(), + )?, + indexes_to_tx_v2: ComputedVecsFromHeight::forced_import( + db, + "tx_v2", + Source::Compute, + version + v0, + indexes, + sum_cum(), + )?, + indexes_to_tx_v3: ComputedVecsFromHeight::forced_import( + db, + "tx_v3", + Source::Compute, + version + v0, + indexes, + sum_cum(), + )?, + indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import( + db, + "tx_vsize", + Source::Vec(txindex_to_vsize.boxed_clone()), + version + v0, + indexes, + stats(), + )?, + indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import( + db, + "tx_weight", + Source::Vec(txindex_to_weight.boxed_clone()), + version + v0, + indexes, + stats(), + )?, + indexes_to_input_count: ComputedVecsFromTxindex::forced_import( + db, + "input_count", + Source::Vec(indexes.transaction.txindex_to_input_count.boxed_clone()), + version + v0, + indexes, + full_stats(), + )?, + indexes_to_output_count: ComputedVecsFromTxindex::forced_import( + db, + "output_count", + Source::Vec(indexes.transaction.txindex_to_output_count.boxed_clone()), + version + v0, + indexes, + full_stats(), + )?, + txindex_to_is_coinbase, + txindex_to_vsize, + txindex_to_weight, + txindex_to_input_value, + txindex_to_output_value, + txindex_to_fee: txindex_to_fee.clone(), + txindex_to_fee_rate: txindex_to_fee_rate.clone(), + indexes_to_fee: ComputedValueVecsFromTxindex::forced_import( + db, + "fee", + indexer, + indexes, + Source::Vec(txindex_to_fee.boxed_clone()), + version + v0, + price, + VecBuilderOptions::default() + .add_sum() + .add_cumulative() + .add_percentiles() + .add_minmax() + .add_average(), + )?, + indexes_to_fee_rate: ComputedVecsFromTxindex::forced_import( + db, + "fee_rate", + Source::Vec(txindex_to_fee_rate.boxed_clone()), + version + v0, + indexes, + stats(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/transaction/mod.rs b/crates/brk_computer/src/chain/transaction/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/transaction/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/transaction/vecs.rs b/crates/brk_computer/src/chain/transaction/vecs.rs new file mode 100644 index 000000000..9d3607670 --- /dev/null +++ b/crates/brk_computer/src/chain/transaction/vecs.rs @@ -0,0 +1,28 @@ +use brk_traversable::Traversable; +use brk_types::{FeeRate, Height, Sats, StoredBool, StoredU32, StoredU64, TxIndex, VSize, Weight}; +use vecdb::{EagerVec, LazyVecFrom1, LazyVecFrom2, PcoVec}; + +use crate::grouped::{ComputedValueVecsFromTxindex, ComputedVecsFromHeight, ComputedVecsFromTxindex}; + +/// Transaction-related metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_tx_count: ComputedVecsFromHeight, + pub indexes_to_tx_v1: ComputedVecsFromHeight, + pub indexes_to_tx_v2: ComputedVecsFromHeight, + pub indexes_to_tx_v3: ComputedVecsFromHeight, + pub indexes_to_tx_vsize: ComputedVecsFromTxindex, + pub indexes_to_tx_weight: ComputedVecsFromTxindex, + pub indexes_to_input_count: ComputedVecsFromTxindex, + pub indexes_to_output_count: ComputedVecsFromTxindex, + pub txindex_to_is_coinbase: LazyVecFrom2, + pub txindex_to_vsize: LazyVecFrom1, + pub txindex_to_weight: LazyVecFrom2, + /// Value == 0 when Coinbase + pub txindex_to_input_value: EagerVec>, + pub txindex_to_output_value: EagerVec>, + pub txindex_to_fee: EagerVec>, + pub txindex_to_fee_rate: EagerVec>, + pub indexes_to_fee: ComputedValueVecsFromTxindex, + pub indexes_to_fee_rate: ComputedVecsFromTxindex, +} diff --git a/crates/brk_computer/src/chain/volume/compute.rs b/crates/brk_computer/src/chain/volume/compute.rs new file mode 100644 index 000000000..2ee098f15 --- /dev/null +++ b/crates/brk_computer/src/chain/volume/compute.rs @@ -0,0 +1,169 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::ONE_DAY_IN_SEC_F64; +use vecdb::Exit; + +use super::Vecs; +use crate::{ + chain::{coinbase, transaction}, + indexes, price, Indexes, +}; + +impl Vecs { + #[allow(clippy::too_many_arguments)] + pub fn compute( + &mut self, + indexer: &Indexer, + indexes: &indexes::Vecs, + transaction_vecs: &transaction::Vecs, + coinbase_vecs: &coinbase::Vecs, + starting_indexes: &Indexes, + price: Option<&price::Vecs>, + exit: &Exit, + ) -> Result<()> { + self.indexes_to_sent_sum + .compute_all(indexes, price, starting_indexes, exit, |v| { + v.compute_filtered_sum_from_indexes( + starting_indexes.height, + &indexer.vecs.tx.height_to_first_txindex, + &indexes.block.height_to_txindex_count, + &transaction_vecs.txindex_to_input_value, + |sats| !sats.is_max(), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_annualized_volume + .compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_sent_sum.sats.dateindex.unwrap_sum(), + 365, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_annualized_volume_btc + .compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + self.indexes_to_sent_sum.bitcoin.dateindex.unwrap_sum(), + 365, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_tx_btc_velocity + .compute_all(starting_indexes, exit, |v| { + v.compute_divide( + starting_indexes.dateindex, + self.indexes_to_annualized_volume_btc + .dateindex + .as_ref() + .unwrap(), + coinbase_vecs + .indexes_to_subsidy + .bitcoin + .dateindex + .unwrap_cumulative(), + exit, + )?; + Ok(()) + })?; + + if let Some(indexes_to_sent_sum) = self.indexes_to_sent_sum.dollars.as_ref() { + self.indexes_to_annualized_volume_usd + .compute_all(starting_indexes, exit, |v| { + v.compute_sum( + starting_indexes.dateindex, + indexes_to_sent_sum.dateindex.unwrap_sum(), + 365, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_tx_usd_velocity + .compute_all(starting_indexes, exit, |v| { + v.compute_divide( + starting_indexes.dateindex, + self.indexes_to_annualized_volume_usd + .dateindex + .as_ref() + .unwrap(), + coinbase_vecs + .indexes_to_subsidy + .dollars + .as_ref() + .unwrap() + .dateindex + .unwrap_cumulative(), + exit, + )?; + Ok(()) + })?; + } + + self.indexes_to_tx_per_sec + .compute_all(starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.dateindex, + transaction_vecs.indexes_to_tx_count.dateindex.unwrap_sum(), + &indexes.time.dateindex_to_date, + |(i, tx_count, date, ..)| { + ( + i, + (*tx_count as f64 / (date.completion() * ONE_DAY_IN_SEC_F64)).into(), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_inputs_per_sec + .compute_all(starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.dateindex, + transaction_vecs + .indexes_to_input_count + .dateindex + .unwrap_sum(), + &indexes.time.dateindex_to_date, + |(i, tx_count, date, ..)| { + ( + i, + (*tx_count as f64 / (date.completion() * ONE_DAY_IN_SEC_F64)).into(), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_outputs_per_sec + .compute_all(starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.dateindex, + transaction_vecs + .indexes_to_output_count + .dateindex + .unwrap_sum(), + &indexes.time.dateindex_to_date, + |(i, tx_count, date, ..)| { + ( + i, + (*tx_count as f64 / (date.completion() * ONE_DAY_IN_SEC_F64)).into(), + ) + }, + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/chain/volume/import.rs b/crates/brk_computer/src/chain/volume/import.rs new file mode 100644 index 000000000..536eddb9c --- /dev/null +++ b/crates/brk_computer/src/chain/volume/import.rs @@ -0,0 +1,98 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::Database; + +use super::Vecs; +use crate::{ + grouped::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, Source, VecBuilderOptions}, + indexes, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + compute_dollars: bool, + ) -> Result { + let v0 = Version::ZERO; + let v2 = Version::TWO; + let last = || VecBuilderOptions::default().add_last(); + + Ok(Self { + indexes_to_sent_sum: ComputedValueVecsFromHeight::forced_import( + db, + "sent_sum", + Source::Compute, + version + v0, + VecBuilderOptions::default().add_sum(), + compute_dollars, + indexes, + )?, + indexes_to_annualized_volume: ComputedVecsFromDateIndex::forced_import( + db, + "annualized_volume", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_annualized_volume_btc: ComputedVecsFromDateIndex::forced_import( + db, + "annualized_volume_btc", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_annualized_volume_usd: ComputedVecsFromDateIndex::forced_import( + db, + "annualized_volume_usd", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_tx_btc_velocity: ComputedVecsFromDateIndex::forced_import( + db, + "tx_btc_velocity", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_tx_usd_velocity: ComputedVecsFromDateIndex::forced_import( + db, + "tx_usd_velocity", + Source::Compute, + version + v0, + indexes, + last(), + )?, + indexes_to_tx_per_sec: ComputedVecsFromDateIndex::forced_import( + db, + "tx_per_sec", + Source::Compute, + version + v2, + indexes, + last(), + )?, + indexes_to_outputs_per_sec: ComputedVecsFromDateIndex::forced_import( + db, + "outputs_per_sec", + Source::Compute, + version + v2, + indexes, + last(), + )?, + indexes_to_inputs_per_sec: ComputedVecsFromDateIndex::forced_import( + db, + "inputs_per_sec", + Source::Compute, + version + v2, + indexes, + last(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/chain/volume/mod.rs b/crates/brk_computer/src/chain/volume/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/chain/volume/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/chain/volume/vecs.rs b/crates/brk_computer/src/chain/volume/vecs.rs new file mode 100644 index 000000000..b1b5c9034 --- /dev/null +++ b/crates/brk_computer/src/chain/volume/vecs.rs @@ -0,0 +1,18 @@ +use brk_traversable::Traversable; +use brk_types::{Bitcoin, Dollars, Sats, StoredF32, StoredF64}; + +use crate::grouped::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex}; + +/// Volume and velocity metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_sent_sum: ComputedValueVecsFromHeight, + pub indexes_to_annualized_volume: ComputedVecsFromDateIndex, + pub indexes_to_annualized_volume_btc: ComputedVecsFromDateIndex, + pub indexes_to_annualized_volume_usd: ComputedVecsFromDateIndex, + pub indexes_to_tx_btc_velocity: ComputedVecsFromDateIndex, + pub indexes_to_tx_usd_velocity: ComputedVecsFromDateIndex, + pub indexes_to_tx_per_sec: ComputedVecsFromDateIndex, + pub indexes_to_outputs_per_sec: ComputedVecsFromDateIndex, + pub indexes_to_inputs_per_sec: ComputedVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/cointime.rs b/crates/brk_computer/src/cointime.rs index a6c1cb4ea..1ba396223 100644 --- a/crates/brk_computer/src/cointime.rs +++ b/crates/brk_computer/src/cointime.rs @@ -341,7 +341,7 @@ impl Vecs { self.indexes_to_activity_to_vaultedness_ratio .dateindex .unwrap_last(), - chain.indexes_to_inflation_rate.dateindex.u(), + chain.coinbase.indexes_to_inflation_rate.dateindex.u(), exit, )?; Ok(()) @@ -354,7 +354,7 @@ impl Vecs { self.indexes_to_activity_to_vaultedness_ratio .dateindex .unwrap_last(), - chain.indexes_to_tx_btc_velocity.dateindex.u(), + chain.volume.indexes_to_tx_btc_velocity.dateindex.u(), exit, )?; Ok(()) @@ -383,7 +383,7 @@ impl Vecs { vec.compute_transform( starting_indexes.height, chain - .indexes_to_subsidy + .coinbase.indexes_to_subsidy .dollars .as_ref() .unwrap() @@ -575,7 +575,7 @@ impl Vecs { self.indexes_to_activity_to_vaultedness_ratio .dateindex .unwrap_last(), - chain.indexes_to_tx_usd_velocity.dateindex.u(), + chain.volume.indexes_to_tx_usd_velocity.dateindex.u(), exit, )?; Ok(()) diff --git a/crates/brk_computer/src/fetched.rs b/crates/brk_computer/src/fetched.rs index 50b076cf0..b08bf355a 100644 --- a/crates/brk_computer/src/fetched.rs +++ b/crates/brk_computer/src/fetched.rs @@ -108,6 +108,7 @@ impl Vecs { .get_unwrap(prev_i) })); indexes + .time .dateindex_to_date .iter() .enumerate() diff --git a/crates/brk_computer/src/grouped/builder_eager.rs b/crates/brk_computer/src/grouped/builder/eager.rs similarity index 99% rename from crates/brk_computer/src/grouped/builder_eager.rs rename to crates/brk_computer/src/grouped/builder/eager.rs index fd41875d2..5338d4a1f 100644 --- a/crates/brk_computer/src/grouped/builder_eager.rs +++ b/crates/brk_computer/src/grouped/builder/eager.rs @@ -9,7 +9,7 @@ use vecdb::{ use crate::utils::{OptionExt, get_percentile}; -use super::ComputedVecValue; +use super::super::ComputedVecValue; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/builder_lazy.rs b/crates/brk_computer/src/grouped/builder/lazy.rs similarity index 99% rename from crates/brk_computer/src/grouped/builder_lazy.rs rename to crates/brk_computer/src/grouped/builder/lazy.rs index 01d785fad..84abfb3e4 100644 --- a/crates/brk_computer/src/grouped/builder_lazy.rs +++ b/crates/brk_computer/src/grouped/builder/lazy.rs @@ -6,7 +6,7 @@ use vecdb::{FromCoarserIndex, IterableBoxedVec, IterableCloneableVec, LazyVecFro use crate::grouped::{EagerVecsBuilder, VecBuilderOptions}; use crate::utils::OptionExt; -use super::ComputedVecValue; +use super::super::ComputedVecValue; #[allow(clippy::type_complexity)] #[derive(Clone, Traversable)] diff --git a/crates/brk_computer/src/grouped/builder/mod.rs b/crates/brk_computer/src/grouped/builder/mod.rs new file mode 100644 index 000000000..43bac8ca2 --- /dev/null +++ b/crates/brk_computer/src/grouped/builder/mod.rs @@ -0,0 +1,9 @@ +mod eager; +mod lazy; +mod transform; +mod transform2; + +pub use eager::*; +pub use lazy::*; +pub use transform::*; +pub use transform2::*; diff --git a/crates/brk_computer/src/grouped/builder_transform.rs b/crates/brk_computer/src/grouped/builder/transform.rs similarity index 98% rename from crates/brk_computer/src/grouped/builder_transform.rs rename to crates/brk_computer/src/grouped/builder/transform.rs index aeb05db6e..d27b260ce 100644 --- a/crates/brk_computer/src/grouped/builder_transform.rs +++ b/crates/brk_computer/src/grouped/builder/transform.rs @@ -3,7 +3,11 @@ use brk_types::Version; use schemars::JsonSchema; use vecdb::{IterableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex}; -use super::{ComputedVecValue, EagerVecsBuilder, LazyVecsBuilder}; +use super::{ + super::ComputedVecValue, + eager::EagerVecsBuilder, + lazy::LazyVecsBuilder, +}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/builder_transform2.rs b/crates/brk_computer/src/grouped/builder/transform2.rs similarity index 98% rename from crates/brk_computer/src/grouped/builder_transform2.rs rename to crates/brk_computer/src/grouped/builder/transform2.rs index ed2ceadf1..88d5321d9 100644 --- a/crates/brk_computer/src/grouped/builder_transform2.rs +++ b/crates/brk_computer/src/grouped/builder/transform2.rs @@ -3,7 +3,11 @@ use brk_types::Version; use schemars::JsonSchema; use vecdb::{BinaryTransform, IterableCloneableVec, LazyVecFrom2, VecIndex}; -use super::{ComputedVecValue, EagerVecsBuilder, LazyVecsBuilder}; +use super::{ + super::ComputedVecValue, + eager::EagerVecsBuilder, + lazy::LazyVecsBuilder, +}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/computed_from_dateindex.rs b/crates/brk_computer/src/grouped/computed/from_dateindex.rs similarity index 93% rename from crates/brk_computer/src/grouped/computed_from_dateindex.rs rename to crates/brk_computer/src/grouped/computed/from_dateindex.rs index d3b2ef42e..b7be631a2 100644 --- a/crates/brk_computer/src/grouped/computed_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/computed/from_dateindex.rs @@ -11,7 +11,7 @@ use vecdb::{ use crate::{Indexes, grouped::LazyVecsBuilder, indexes, utils::OptionExt}; -use super::{ComputedVecValue, EagerVecsBuilder, Source, VecBuilderOptions}; +use crate::grouped::{ComputedVecValue, EagerVecsBuilder, Source, VecBuilderOptions}; #[derive(Clone)] pub struct ComputedVecsFromDateIndex @@ -64,7 +64,7 @@ where version + VERSION + Version::ZERO, dateindex_source.clone(), &dateindex_extra, - indexes.weekindex_to_weekindex.boxed_clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), options.into(), ), monthindex: LazyVecsBuilder::forced_import( @@ -72,7 +72,7 @@ where version + VERSION + Version::ZERO, dateindex_source.clone(), &dateindex_extra, - indexes.monthindex_to_monthindex.boxed_clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), options.into(), ), quarterindex: LazyVecsBuilder::forced_import( @@ -80,7 +80,7 @@ where version + VERSION + Version::ZERO, dateindex_source.clone(), &dateindex_extra, - indexes.quarterindex_to_quarterindex.boxed_clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), options.into(), ), semesterindex: LazyVecsBuilder::forced_import( @@ -88,7 +88,7 @@ where version + VERSION + Version::ZERO, dateindex_source.clone(), &dateindex_extra, - indexes.semesterindex_to_semesterindex.boxed_clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), options.into(), ), yearindex: LazyVecsBuilder::forced_import( @@ -96,7 +96,7 @@ where version + VERSION + Version::ZERO, dateindex_source.clone(), &dateindex_extra, - indexes.yearindex_to_yearindex.boxed_clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), options.into(), ), decadeindex: LazyVecsBuilder::forced_import( @@ -104,7 +104,7 @@ where version + VERSION + Version::ZERO, dateindex_source.clone(), &dateindex_extra, - indexes.decadeindex_to_decadeindex.boxed_clone(), + indexes.time.decadeindex_to_decadeindex.boxed_clone(), options.into(), ), dateindex, diff --git a/crates/brk_computer/src/grouped/computed/from_height/mod.rs b/crates/brk_computer/src/grouped/computed/from_height/mod.rs new file mode 100644 index 000000000..3b6a0f081 --- /dev/null +++ b/crates/brk_computer/src/grouped/computed/from_height/mod.rs @@ -0,0 +1,5 @@ +mod standard; +mod strict; + +pub use standard::*; +pub use strict::*; diff --git a/crates/brk_computer/src/grouped/computed_from_height.rs b/crates/brk_computer/src/grouped/computed/from_height/standard.rs similarity index 91% rename from crates/brk_computer/src/grouped/computed_from_height.rs rename to crates/brk_computer/src/grouped/computed/from_height/standard.rs index 737c92162..5baef01ce 100644 --- a/crates/brk_computer/src/grouped/computed_from_height.rs +++ b/crates/brk_computer/src/grouped/computed/from_height/standard.rs @@ -18,7 +18,7 @@ use crate::{ utils::OptionExt, }; -use super::{ComputedVecValue, EagerVecsBuilder, VecBuilderOptions}; +use crate::grouped::{ComputedVecValue, EagerVecsBuilder, VecBuilderOptions}; #[derive(Clone)] pub struct ComputedVecsFromHeight @@ -78,7 +78,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.weekindex_to_weekindex.boxed_clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), options.into(), ), monthindex: LazyVecsBuilder::forced_import( @@ -86,7 +86,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.monthindex_to_monthindex.boxed_clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), options.into(), ), quarterindex: LazyVecsBuilder::forced_import( @@ -94,7 +94,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.quarterindex_to_quarterindex.boxed_clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), options.into(), ), semesterindex: LazyVecsBuilder::forced_import( @@ -102,7 +102,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.semesterindex_to_semesterindex.boxed_clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), options.into(), ), yearindex: LazyVecsBuilder::forced_import( @@ -110,7 +110,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.yearindex_to_yearindex.boxed_clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), options.into(), ), decadeindex: LazyVecsBuilder::forced_import( @@ -118,7 +118,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.decadeindex_to_decadeindex.boxed_clone(), + indexes.time.decadeindex_to_decadeindex.boxed_clone(), options.into(), ), // halvingepoch: StorableVecGeneator::forced_import(db, name, version + VERSION + Version::ZERO, format, options)?, @@ -127,7 +127,7 @@ where version + VERSION + Version::ZERO, height_source, &height_extra, - indexes.difficultyepoch_to_difficultyepoch.boxed_clone(), + indexes.block.difficultyepoch_to_difficultyepoch.boxed_clone(), options.into(), ), height, @@ -166,8 +166,8 @@ where self.dateindex.compute( starting_indexes.dateindex, height, - &indexes.dateindex_to_first_height, - &indexes.dateindex_to_height_count, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, exit, )?; } else { @@ -179,8 +179,8 @@ where self.dateindex.compute( starting_indexes.dateindex, height, - &indexes.dateindex_to_first_height, - &indexes.dateindex_to_height_count, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, exit, )?; } diff --git a/crates/brk_computer/src/grouped/computed_from_height_strict.rs b/crates/brk_computer/src/grouped/computed/from_height/strict.rs similarity index 95% rename from crates/brk_computer/src/grouped/computed_from_height_strict.rs rename to crates/brk_computer/src/grouped/computed/from_height/strict.rs index a0df92424..e0fe245a4 100644 --- a/crates/brk_computer/src/grouped/computed_from_height_strict.rs +++ b/crates/brk_computer/src/grouped/computed/from_height/strict.rs @@ -9,7 +9,7 @@ use vecdb::{ use crate::{Indexes, indexes}; -use super::{ComputedVecValue, EagerVecsBuilder, LazyVecsBuilder, VecBuilderOptions}; +use crate::grouped::{ComputedVecValue, EagerVecsBuilder, LazyVecsBuilder, VecBuilderOptions}; #[derive(Clone)] pub struct ComputedVecsFromHeightStrict @@ -53,7 +53,7 @@ where version + VERSION + Version::ZERO, Some(height.boxed_clone()), &height_extra, - indexes.difficultyepoch_to_difficultyepoch.boxed_clone(), + indexes.block.difficultyepoch_to_difficultyepoch.boxed_clone(), options.into(), ), height, diff --git a/crates/brk_computer/src/grouped/computed_from_txindex.rs b/crates/brk_computer/src/grouped/computed/from_txindex.rs similarity index 95% rename from crates/brk_computer/src/grouped/computed_from_txindex.rs rename to crates/brk_computer/src/grouped/computed/from_txindex.rs index ccaebccbe..d9bbfbf9d 100644 --- a/crates/brk_computer/src/grouped/computed_from_txindex.rs +++ b/crates/brk_computer/src/grouped/computed/from_txindex.rs @@ -18,7 +18,7 @@ use crate::{ utils::OptionExt, }; -use super::{ComputedVecValue, EagerVecsBuilder, VecBuilderOptions}; +use crate::grouped::{ComputedVecValue, EagerVecsBuilder, VecBuilderOptions}; #[derive(Clone)] pub struct ComputedVecsFromTxindex @@ -72,7 +72,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.weekindex_to_weekindex.boxed_clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), options.into(), ), difficultyepoch: LazyVecsBuilder::forced_import( @@ -80,7 +80,7 @@ where version + VERSION + Version::ZERO, None, &height, - indexes.difficultyepoch_to_difficultyepoch.boxed_clone(), + indexes.block.difficultyepoch_to_difficultyepoch.boxed_clone(), options.into(), ), monthindex: LazyVecsBuilder::forced_import( @@ -88,7 +88,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.monthindex_to_monthindex.boxed_clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), options.into(), ), quarterindex: LazyVecsBuilder::forced_import( @@ -96,7 +96,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.quarterindex_to_quarterindex.boxed_clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), options.into(), ), semesterindex: LazyVecsBuilder::forced_import( @@ -104,7 +104,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.semesterindex_to_semesterindex.boxed_clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), options.into(), ), yearindex: LazyVecsBuilder::forced_import( @@ -112,7 +112,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.yearindex_to_yearindex.boxed_clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), options.into(), ), decadeindex: LazyVecsBuilder::forced_import( @@ -120,7 +120,7 @@ where version + VERSION + Version::ZERO, None, &dateindex, - indexes.decadeindex_to_decadeindex.boxed_clone(), + indexes.time.decadeindex_to_decadeindex.boxed_clone(), options.into(), ), @@ -175,7 +175,7 @@ where starting_indexes.height, txindex, &indexer.vecs.tx.height_to_first_txindex, - &indexes.height_to_txindex_count, + &indexes.block.height_to_txindex_count, exit, )?; } else { @@ -185,7 +185,7 @@ where starting_indexes.height, txindex, &indexer.vecs.tx.height_to_first_txindex, - &indexes.height_to_txindex_count, + &indexes.block.height_to_txindex_count, exit, )?; } @@ -202,8 +202,8 @@ where self.dateindex.from_aligned( starting_indexes.dateindex, &self.height, - &indexes.dateindex_to_first_height, - &indexes.dateindex_to_height_count, + &indexes.time.dateindex_to_first_height, + &indexes.time.dateindex_to_height_count, exit, )?; diff --git a/crates/brk_computer/src/grouped/computed/mod.rs b/crates/brk_computer/src/grouped/computed/mod.rs new file mode 100644 index 000000000..4d06981a1 --- /dev/null +++ b/crates/brk_computer/src/grouped/computed/mod.rs @@ -0,0 +1,9 @@ +mod from_dateindex; +mod from_height; +mod from_txindex; +mod traits; + +pub use from_dateindex::*; +pub use from_height::*; +pub use from_txindex::*; +pub use traits::*; diff --git a/crates/brk_computer/src/grouped/computed.rs b/crates/brk_computer/src/grouped/computed/traits.rs similarity index 100% rename from crates/brk_computer/src/grouped/computed.rs rename to crates/brk_computer/src/grouped/computed/traits.rs diff --git a/crates/brk_computer/src/grouped/lazy2_from_dateindex.rs b/crates/brk_computer/src/grouped/lazy/binary/from_dateindex.rs similarity index 98% rename from crates/brk_computer/src/grouped/lazy2_from_dateindex.rs rename to crates/brk_computer/src/grouped/lazy/binary/from_dateindex.rs index 715c9c46a..6080cb7d3 100644 --- a/crates/brk_computer/src/grouped/lazy2_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/lazy/binary/from_dateindex.rs @@ -5,7 +5,7 @@ use brk_types::{ use schemars::JsonSchema; use vecdb::{AnyExportableVec, BinaryTransform, IterableCloneableVec, LazyVecFrom2}; -use super::{ComputedVecValue, ComputedVecsFromDateIndex, ComputedVecsFromHeight, LazyTransform2Builder}; +use crate::grouped::{ComputedVecValue, ComputedVecsFromDateIndex, ComputedVecsFromHeight, LazyTransform2Builder}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/lazy2_from_height.rs b/crates/brk_computer/src/grouped/lazy/binary/from_height.rs similarity index 98% rename from crates/brk_computer/src/grouped/lazy2_from_height.rs rename to crates/brk_computer/src/grouped/lazy/binary/from_height.rs index 901349156..893582d44 100644 --- a/crates/brk_computer/src/grouped/lazy2_from_height.rs +++ b/crates/brk_computer/src/grouped/lazy/binary/from_height.rs @@ -6,7 +6,7 @@ use brk_types::{ use schemars::JsonSchema; use vecdb::{AnyExportableVec, BinaryTransform, IterableBoxedVec, LazyVecFrom2}; -use super::{ComputedVecValue, ComputedVecsFromHeight, LazyTransform2Builder}; +use crate::grouped::{ComputedVecValue, ComputedVecsFromHeight, LazyTransform2Builder}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/lazy/binary/mod.rs b/crates/brk_computer/src/grouped/lazy/binary/mod.rs new file mode 100644 index 000000000..df9caa6e0 --- /dev/null +++ b/crates/brk_computer/src/grouped/lazy/binary/mod.rs @@ -0,0 +1,5 @@ +mod from_dateindex; +mod from_height; + +pub use from_dateindex::*; +pub use from_height::*; diff --git a/crates/brk_computer/src/grouped/lazy_from_dateindex.rs b/crates/brk_computer/src/grouped/lazy/from_dateindex.rs similarity index 98% rename from crates/brk_computer/src/grouped/lazy_from_dateindex.rs rename to crates/brk_computer/src/grouped/lazy/from_dateindex.rs index 839152fa2..8e58151a1 100644 --- a/crates/brk_computer/src/grouped/lazy_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/lazy/from_dateindex.rs @@ -5,7 +5,7 @@ use brk_types::{ use schemars::JsonSchema; use vecdb::{AnyExportableVec, IterableBoxedVec, LazyVecFrom1, UnaryTransform}; -use super::{ComputedVecValue, ComputedVecsFromDateIndex, LazyTransformBuilder}; +use crate::grouped::{ComputedVecValue, ComputedVecsFromDateIndex, LazyTransformBuilder}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/lazy_from_height.rs b/crates/brk_computer/src/grouped/lazy/from_height.rs similarity index 98% rename from crates/brk_computer/src/grouped/lazy_from_height.rs rename to crates/brk_computer/src/grouped/lazy/from_height.rs index 89ce71f3b..15557f017 100644 --- a/crates/brk_computer/src/grouped/lazy_from_height.rs +++ b/crates/brk_computer/src/grouped/lazy/from_height.rs @@ -6,7 +6,7 @@ use brk_types::{ use schemars::JsonSchema; use vecdb::{AnyExportableVec, IterableBoxedVec, LazyVecFrom1, UnaryTransform}; -use super::{ComputedVecValue, ComputedVecsFromHeight, LazyTransformBuilder}; +use crate::grouped::{ComputedVecValue, ComputedVecsFromHeight, LazyTransformBuilder}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/lazy/mod.rs b/crates/brk_computer/src/grouped/lazy/mod.rs new file mode 100644 index 000000000..9fdf54931 --- /dev/null +++ b/crates/brk_computer/src/grouped/lazy/mod.rs @@ -0,0 +1,7 @@ +mod binary; +mod from_dateindex; +mod from_height; + +pub use binary::*; +pub use from_dateindex::*; +pub use from_height::*; diff --git a/crates/brk_computer/src/grouped/mod.rs b/crates/brk_computer/src/grouped/mod.rs index 4708890da..cb700e24d 100644 --- a/crates/brk_computer/src/grouped/mod.rs +++ b/crates/brk_computer/src/grouped/mod.rs @@ -1,57 +1,15 @@ -mod builder_eager; -mod builder_lazy; -mod builder_transform; -mod builder_transform2; +mod builder; mod computed; -mod constant; -mod computed_from_dateindex; -mod computed_from_height; -mod computed_from_height_strict; -mod computed_from_txindex; -mod lazy2_from_dateindex; -mod lazy2_from_height; -mod lazy_from_dateindex; -mod lazy_from_height; -mod lazy_value_from_dateindex; -mod lazy_value_height; -mod lazy_value2_from_height; -// mod lazy_from_height_strict; -// mod lazy_from_txindex; -mod price_percentiles; -mod ratio_from_dateindex; -mod sd_from_dateindex; +mod lazy; mod source; +mod specialized; mod transforms; -mod value_from_dateindex; -mod value_from_height; -mod value_from_txindex; -mod value_height; +mod value; -pub use builder_eager::*; -pub use builder_lazy::*; -pub use builder_transform::*; -pub use builder_transform2::*; -use computed::*; -pub use constant::*; -pub use computed_from_dateindex::*; -pub use computed_from_height::*; -pub use computed_from_height_strict::*; -pub use computed_from_txindex::*; -pub use lazy_from_dateindex::*; -pub use lazy_from_height::*; -pub use lazy_value_from_dateindex::*; -pub use lazy_value_height::*; -pub use lazy_value2_from_height::*; -pub use lazy2_from_dateindex::*; -pub use lazy2_from_height::*; -// pub use lazy_from_height_strict::*; -// pub use lazy_from_txindex::*; -pub use price_percentiles::*; -pub use ratio_from_dateindex::*; -pub use sd_from_dateindex::*; +pub use builder::*; +pub use computed::*; +pub use lazy::*; pub use source::*; +pub use specialized::*; pub use transforms::*; -pub use value_from_dateindex::*; -pub use value_from_height::*; -pub use value_from_txindex::*; -pub use value_height::*; +pub use value::*; diff --git a/crates/brk_computer/src/grouped/constant.rs b/crates/brk_computer/src/grouped/specialized/constant.rs similarity index 83% rename from crates/brk_computer/src/grouped/constant.rs rename to crates/brk_computer/src/grouped/specialized/constant.rs index d20fba730..e3c9ef7de 100644 --- a/crates/brk_computer/src/grouped/constant.rs +++ b/crates/brk_computer/src/grouped/specialized/constant.rs @@ -43,42 +43,42 @@ impl ConstantVecs { height: LazyVecFrom1::transformed::( name, version, - indexes.height_to_height.boxed_clone(), + indexes.block.height_to_height.boxed_clone(), ), dateindex: LazyVecFrom1::transformed::( name, version, - indexes.dateindex_to_dateindex.boxed_clone(), + indexes.time.dateindex_to_dateindex.boxed_clone(), ), weekindex: LazyVecFrom1::transformed::( name, version, - indexes.weekindex_to_weekindex.boxed_clone(), + indexes.time.weekindex_to_weekindex.boxed_clone(), ), monthindex: LazyVecFrom1::transformed::( name, version, - indexes.monthindex_to_monthindex.boxed_clone(), + indexes.time.monthindex_to_monthindex.boxed_clone(), ), quarterindex: LazyVecFrom1::transformed::( name, version, - indexes.quarterindex_to_quarterindex.boxed_clone(), + indexes.time.quarterindex_to_quarterindex.boxed_clone(), ), semesterindex: LazyVecFrom1::transformed::( name, version, - indexes.semesterindex_to_semesterindex.boxed_clone(), + indexes.time.semesterindex_to_semesterindex.boxed_clone(), ), yearindex: LazyVecFrom1::transformed::( name, version, - indexes.yearindex_to_yearindex.boxed_clone(), + indexes.time.yearindex_to_yearindex.boxed_clone(), ), decadeindex: LazyVecFrom1::transformed::( name, version, - indexes.decadeindex_to_decadeindex.boxed_clone(), + indexes.time.decadeindex_to_decadeindex.boxed_clone(), ), } } diff --git a/crates/brk_computer/src/grouped/specialized/mod.rs b/crates/brk_computer/src/grouped/specialized/mod.rs new file mode 100644 index 000000000..1ac1eaf2a --- /dev/null +++ b/crates/brk_computer/src/grouped/specialized/mod.rs @@ -0,0 +1,9 @@ +mod constant; +mod percentiles; +mod ratio; +mod stddev; + +pub use constant::*; +pub use percentiles::*; +pub use ratio::*; +pub use stddev::*; diff --git a/crates/brk_computer/src/grouped/price_percentiles.rs b/crates/brk_computer/src/grouped/specialized/percentiles.rs similarity index 98% rename from crates/brk_computer/src/grouped/price_percentiles.rs rename to crates/brk_computer/src/grouped/specialized/percentiles.rs index 4882ce6c2..cb247be7a 100644 --- a/crates/brk_computer/src/grouped/price_percentiles.rs +++ b/crates/brk_computer/src/grouped/specialized/percentiles.rs @@ -8,7 +8,7 @@ use vecdb::{ use crate::{Indexes, indexes}; -use super::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}; +use super::super::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}; pub const PERCENTILES: [u8; 19] = [ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, diff --git a/crates/brk_computer/src/grouped/ratio_from_dateindex.rs b/crates/brk_computer/src/grouped/specialized/ratio.rs similarity index 99% rename from crates/brk_computer/src/grouped/ratio_from_dateindex.rs rename to crates/brk_computer/src/grouped/specialized/ratio.rs index aa93fc086..0a4d531b5 100644 --- a/crates/brk_computer/src/grouped/ratio_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/specialized/ratio.rs @@ -16,7 +16,7 @@ use crate::{ utils::{OptionExt, get_percentile}, }; -use super::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions}; +use super::super::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions}; #[derive(Clone, Traversable)] pub struct ComputedRatioVecsFromDateIndex { diff --git a/crates/brk_computer/src/grouped/sd_from_dateindex.rs b/crates/brk_computer/src/grouped/specialized/stddev.rs similarity index 99% rename from crates/brk_computer/src/grouped/sd_from_dateindex.rs rename to crates/brk_computer/src/grouped/specialized/stddev.rs index ff6079d7f..cb0cb7a20 100644 --- a/crates/brk_computer/src/grouped/sd_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/specialized/stddev.rs @@ -10,7 +10,7 @@ use vecdb::{ use crate::{Indexes, grouped::source::Source, indexes, price, utils::OptionExt}; -use super::{ +use super::super::{ ClosePriceTimesRatio, ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, VecBuilderOptions, }; diff --git a/crates/brk_computer/src/grouped/value_from_dateindex.rs b/crates/brk_computer/src/grouped/value/computed/from_dateindex.rs similarity index 98% rename from crates/brk_computer/src/grouped/value_from_dateindex.rs rename to crates/brk_computer/src/grouped/value/computed/from_dateindex.rs index e4a9ac484..54a3633e2 100644 --- a/crates/brk_computer/src/grouped/value_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/value/computed/from_dateindex.rs @@ -11,7 +11,7 @@ use crate::{ utils::OptionExt, }; -use super::{Source, VecBuilderOptions}; +use crate::grouped::{Source, VecBuilderOptions}; #[derive(Clone, Traversable)] pub struct ComputedValueVecsFromDateIndex { diff --git a/crates/brk_computer/src/grouped/value_from_height.rs b/crates/brk_computer/src/grouped/value/computed/from_height.rs similarity index 98% rename from crates/brk_computer/src/grouped/value_from_height.rs rename to crates/brk_computer/src/grouped/value/computed/from_height.rs index c42452fd8..52b04663e 100644 --- a/crates/brk_computer/src/grouped/value_from_height.rs +++ b/crates/brk_computer/src/grouped/value/computed/from_height.rs @@ -11,7 +11,7 @@ use crate::{ utils::OptionExt, }; -use super::{ComputedVecsFromHeight, VecBuilderOptions}; +use crate::grouped::{ComputedVecsFromHeight, VecBuilderOptions}; #[derive(Clone, Traversable)] pub struct ComputedValueVecsFromHeight { diff --git a/crates/brk_computer/src/grouped/value_from_txindex.rs b/crates/brk_computer/src/grouped/value/computed/from_txindex.rs similarity index 98% rename from crates/brk_computer/src/grouped/value_from_txindex.rs rename to crates/brk_computer/src/grouped/value/computed/from_txindex.rs index 786013cbd..d5ff34d9b 100644 --- a/crates/brk_computer/src/grouped/value_from_txindex.rs +++ b/crates/brk_computer/src/grouped/value/computed/from_txindex.rs @@ -9,7 +9,7 @@ use vecdb::{ use crate::{Indexes, grouped::Source, indexes, price, utils::OptionExt}; -use super::{ComputedVecsFromTxindex, VecBuilderOptions}; +use crate::grouped::{ComputedVecsFromTxindex, VecBuilderOptions}; #[derive(Clone, Traversable)] pub struct ComputedValueVecsFromTxindex { diff --git a/crates/brk_computer/src/grouped/value/computed/mod.rs b/crates/brk_computer/src/grouped/value/computed/mod.rs new file mode 100644 index 000000000..79c974b7f --- /dev/null +++ b/crates/brk_computer/src/grouped/value/computed/mod.rs @@ -0,0 +1,7 @@ +mod from_dateindex; +mod from_height; +mod from_txindex; + +pub use from_dateindex::*; +pub use from_height::*; +pub use from_txindex::*; diff --git a/crates/brk_computer/src/grouped/lazy_value2_from_height.rs b/crates/brk_computer/src/grouped/value/lazy/binary_from_height.rs similarity index 96% rename from crates/brk_computer/src/grouped/lazy_value2_from_height.rs rename to crates/brk_computer/src/grouped/value/lazy/binary_from_height.rs index 5659ab492..c6c7ee6fe 100644 --- a/crates/brk_computer/src/grouped/lazy_value2_from_height.rs +++ b/crates/brk_computer/src/grouped/value/lazy/binary_from_height.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::{Bitcoin, Dollars, Height, Sats, Version}; use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec}; -use super::{ComputedValueVecsFromHeight, LazyVecsFrom2FromHeight}; +use crate::grouped::{ComputedValueVecsFromHeight, LazyVecsFrom2FromHeight}; /// Lazy value vecs computed from two `ComputedValueVecsFromHeight` sources via binary transforms. /// Used for computing coinbase = subsidy + fee. diff --git a/crates/brk_computer/src/grouped/lazy_value_from_dateindex.rs b/crates/brk_computer/src/grouped/value/lazy/from_dateindex.rs similarity index 96% rename from crates/brk_computer/src/grouped/lazy_value_from_dateindex.rs rename to crates/brk_computer/src/grouped/value/lazy/from_dateindex.rs index 7e6fa14cf..1ff397267 100644 --- a/crates/brk_computer/src/grouped/lazy_value_from_dateindex.rs +++ b/crates/brk_computer/src/grouped/value/lazy/from_dateindex.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::{Bitcoin, Dollars, Sats, Version}; use vecdb::{IterableCloneableVec, UnaryTransform}; -use super::{ComputedValueVecsFromDateIndex, LazyVecsFromDateIndex}; +use crate::grouped::{ComputedValueVecsFromDateIndex, LazyVecsFromDateIndex}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/grouped/lazy_value_height.rs b/crates/brk_computer/src/grouped/value/lazy/height.rs similarity index 100% rename from crates/brk_computer/src/grouped/lazy_value_height.rs rename to crates/brk_computer/src/grouped/value/lazy/height.rs diff --git a/crates/brk_computer/src/grouped/value/lazy/mod.rs b/crates/brk_computer/src/grouped/value/lazy/mod.rs new file mode 100644 index 000000000..c0f27556a --- /dev/null +++ b/crates/brk_computer/src/grouped/value/lazy/mod.rs @@ -0,0 +1,9 @@ +mod binary_from_height; +mod from_dateindex; +mod height; +mod value_height; + +pub use binary_from_height::*; +pub use from_dateindex::*; +pub use height::*; +pub use value_height::*; diff --git a/crates/brk_computer/src/grouped/value_height.rs b/crates/brk_computer/src/grouped/value/lazy/value_height.rs similarity index 100% rename from crates/brk_computer/src/grouped/value_height.rs rename to crates/brk_computer/src/grouped/value/lazy/value_height.rs diff --git a/crates/brk_computer/src/grouped/value/mod.rs b/crates/brk_computer/src/grouped/value/mod.rs new file mode 100644 index 000000000..4e1cf831d --- /dev/null +++ b/crates/brk_computer/src/grouped/value/mod.rs @@ -0,0 +1,5 @@ +mod computed; +mod lazy; + +pub use computed::*; +pub use lazy::*; diff --git a/crates/brk_computer/src/indexes.rs b/crates/brk_computer/src/indexes.rs deleted file mode 100644 index cfd89efea..000000000 --- a/crates/brk_computer/src/indexes.rs +++ /dev/null @@ -1,667 +0,0 @@ -use std::{ops::Deref, path::Path}; - -use brk_error::Result; -use brk_indexer::Indexer; -use brk_traversable::Traversable; -use brk_types::{ - Date, DateIndex, DecadeIndex, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height, - MonthIndex, OpReturnIndex, OutPoint, P2AAddressIndex, P2ABytes, P2MSOutputIndex, - P2PK33AddressIndex, P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex, - P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex, - P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, QuarterIndex, Sats, SemesterIndex, StoredU64, - Timestamp, TxInIndex, TxIndex, TxOutIndex, Txid, UnknownOutputIndex, Version, WeekIndex, - YearIndex, -}; -use vecdb::{ - Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, LazyVecFrom1, PAGE_SIZE, PcoVec, - TypedVecIterator, -}; - -const VERSION: Version = Version::ZERO; -pub const DB_NAME: &str = "indexes"; - -#[derive(Clone, Traversable)] -pub struct Vecs { - db: Database, - - pub dateindex_to_date: EagerVec>, - pub dateindex_to_dateindex: EagerVec>, - pub dateindex_to_first_height: EagerVec>, - pub dateindex_to_height_count: EagerVec>, - pub dateindex_to_monthindex: EagerVec>, - pub dateindex_to_weekindex: EagerVec>, - pub decadeindex_to_decadeindex: EagerVec>, - pub decadeindex_to_first_yearindex: EagerVec>, - pub decadeindex_to_yearindex_count: EagerVec>, - pub difficultyepoch_to_difficultyepoch: EagerVec>, - pub difficultyepoch_to_first_height: EagerVec>, - pub difficultyepoch_to_height_count: EagerVec>, - pub emptyoutputindex_to_emptyoutputindex: - LazyVecFrom1, - pub halvingepoch_to_first_height: EagerVec>, - pub halvingepoch_to_halvingepoch: EagerVec>, - pub height_to_date: EagerVec>, - pub height_to_date_fixed: EagerVec>, - pub height_to_dateindex: EagerVec>, - pub height_to_difficultyepoch: EagerVec>, - pub height_to_halvingepoch: EagerVec>, - pub height_to_height: EagerVec>, - pub height_to_timestamp_fixed: EagerVec>, - pub height_to_txindex_count: EagerVec>, - pub monthindex_to_dateindex_count: EagerVec>, - pub monthindex_to_first_dateindex: EagerVec>, - pub monthindex_to_monthindex: EagerVec>, - pub monthindex_to_quarterindex: EagerVec>, - pub monthindex_to_semesterindex: EagerVec>, - pub monthindex_to_yearindex: EagerVec>, - pub opreturnindex_to_opreturnindex: - LazyVecFrom1, - pub p2aaddressindex_to_p2aaddressindex: - LazyVecFrom1, - pub p2msoutputindex_to_p2msoutputindex: - LazyVecFrom1, - pub p2pk33addressindex_to_p2pk33addressindex: - LazyVecFrom1, - pub p2pk65addressindex_to_p2pk65addressindex: - LazyVecFrom1, - pub p2pkhaddressindex_to_p2pkhaddressindex: - LazyVecFrom1, - pub p2shaddressindex_to_p2shaddressindex: - LazyVecFrom1, - pub p2traddressindex_to_p2traddressindex: - LazyVecFrom1, - pub p2wpkhaddressindex_to_p2wpkhaddressindex: - LazyVecFrom1, - pub p2wshaddressindex_to_p2wshaddressindex: - LazyVecFrom1, - pub quarterindex_to_first_monthindex: EagerVec>, - pub quarterindex_to_monthindex_count: EagerVec>, - pub quarterindex_to_quarterindex: EagerVec>, - pub semesterindex_to_first_monthindex: EagerVec>, - pub semesterindex_to_monthindex_count: EagerVec>, - pub semesterindex_to_semesterindex: EagerVec>, - pub txindex_to_input_count: EagerVec>, - pub txindex_to_output_count: EagerVec>, - pub txindex_to_txindex: LazyVecFrom1, - pub txinindex_to_txinindex: LazyVecFrom1, - pub txoutindex_to_txoutindex: LazyVecFrom1, - pub unknownoutputindex_to_unknownoutputindex: - LazyVecFrom1, - pub weekindex_to_dateindex_count: EagerVec>, - pub weekindex_to_first_dateindex: EagerVec>, - pub weekindex_to_weekindex: EagerVec>, - pub yearindex_to_decadeindex: EagerVec>, - pub yearindex_to_first_monthindex: EagerVec>, - pub yearindex_to_monthindex_count: EagerVec>, - pub yearindex_to_yearindex: EagerVec>, -} - -impl Vecs { - pub fn forced_import( - parent: &Path, - parent_version: Version, - indexer: &Indexer, - ) -> Result { - let db = Database::open(&parent.join(DB_NAME))?; - db.set_min_len(PAGE_SIZE * 10_000_000)?; - - let version = parent_version + VERSION; - - macro_rules! eager { - ($name:expr) => { - EagerVec::forced_import(&db, $name, version)? - }; - } - macro_rules! lazy { - ($name:expr, $source:expr) => { - LazyVecFrom1::init($name, version, $source.boxed_clone(), |index, _| { - Some(index) - }) - }; - } - - let this = Self { - txoutindex_to_txoutindex: lazy!("txoutindex", indexer.vecs.txout.txoutindex_to_value), - txinindex_to_txinindex: lazy!("txinindex", indexer.vecs.txin.txinindex_to_outpoint), - p2pk33addressindex_to_p2pk33addressindex: lazy!( - "p2pk33addressindex", - indexer.vecs.address.p2pk33addressindex_to_p2pk33bytes - ), - p2pk65addressindex_to_p2pk65addressindex: lazy!( - "p2pk65addressindex", - indexer.vecs.address.p2pk65addressindex_to_p2pk65bytes - ), - p2pkhaddressindex_to_p2pkhaddressindex: lazy!( - "p2pkhaddressindex", - indexer.vecs.address.p2pkhaddressindex_to_p2pkhbytes - ), - p2shaddressindex_to_p2shaddressindex: lazy!( - "p2shaddressindex", - indexer.vecs.address.p2shaddressindex_to_p2shbytes - ), - p2traddressindex_to_p2traddressindex: lazy!( - "p2traddressindex", - indexer.vecs.address.p2traddressindex_to_p2trbytes - ), - p2wpkhaddressindex_to_p2wpkhaddressindex: lazy!( - "p2wpkhaddressindex", - indexer.vecs.address.p2wpkhaddressindex_to_p2wpkhbytes - ), - p2wshaddressindex_to_p2wshaddressindex: lazy!( - "p2wshaddressindex", - indexer.vecs.address.p2wshaddressindex_to_p2wshbytes - ), - p2aaddressindex_to_p2aaddressindex: lazy!( - "p2aaddressindex", - indexer.vecs.address.p2aaddressindex_to_p2abytes - ), - p2msoutputindex_to_p2msoutputindex: lazy!( - "p2msoutputindex", - indexer.vecs.output.p2msoutputindex_to_txindex - ), - emptyoutputindex_to_emptyoutputindex: lazy!( - "emptyoutputindex", - indexer.vecs.output.emptyoutputindex_to_txindex - ), - unknownoutputindex_to_unknownoutputindex: lazy!( - "unknownoutputindex", - indexer.vecs.output.unknownoutputindex_to_txindex - ), - opreturnindex_to_opreturnindex: lazy!( - "opreturnindex", - indexer.vecs.output.opreturnindex_to_txindex - ), - txindex_to_txindex: lazy!("txindex", indexer.vecs.tx.txindex_to_txid), - txindex_to_input_count: eager!("input_count"), - txindex_to_output_count: eager!("output_count"), - dateindex_to_date: eager!("date"), - dateindex_to_dateindex: eager!("dateindex"), - dateindex_to_first_height: eager!("first_height"), - dateindex_to_monthindex: eager!("monthindex"), - dateindex_to_weekindex: eager!("weekindex"), - decadeindex_to_decadeindex: eager!("decadeindex"), - decadeindex_to_first_yearindex: eager!("first_yearindex"), - difficultyepoch_to_difficultyepoch: eager!("difficultyepoch"), - difficultyepoch_to_first_height: eager!("first_height"), - halvingepoch_to_first_height: eager!("first_height"), - halvingepoch_to_halvingepoch: eager!("halvingepoch"), - height_to_date: eager!("date"), - height_to_difficultyepoch: eager!("difficultyepoch"), - height_to_halvingepoch: eager!("halvingepoch"), - height_to_height: eager!("height"), - monthindex_to_first_dateindex: eager!("first_dateindex"), - monthindex_to_monthindex: eager!("monthindex"), - monthindex_to_quarterindex: eager!("quarterindex"), - monthindex_to_semesterindex: eager!("semesterindex"), - monthindex_to_yearindex: eager!("yearindex"), - quarterindex_to_first_monthindex: eager!("first_monthindex"), - semesterindex_to_first_monthindex: eager!("first_monthindex"), - weekindex_to_first_dateindex: eager!("first_dateindex"), - yearindex_to_first_monthindex: eager!("first_monthindex"), - quarterindex_to_quarterindex: eager!("quarterindex"), - semesterindex_to_semesterindex: eager!("semesterindex"), - weekindex_to_weekindex: eager!("weekindex"), - yearindex_to_decadeindex: eager!("decadeindex"), - yearindex_to_yearindex: eager!("yearindex"), - height_to_date_fixed: eager!("date_fixed"), - height_to_dateindex: eager!("dateindex"), - height_to_timestamp_fixed: eager!("timestamp_fixed"), - height_to_txindex_count: eager!("txindex_count"), - dateindex_to_height_count: eager!("height_count"), - weekindex_to_dateindex_count: eager!("dateindex_count"), - difficultyepoch_to_height_count: eager!("height_count"), - monthindex_to_dateindex_count: eager!("dateindex_count"), - quarterindex_to_monthindex_count: eager!("monthindex_count"), - semesterindex_to_monthindex_count: eager!("monthindex_count"), - yearindex_to_monthindex_count: eager!("monthindex_count"), - decadeindex_to_yearindex_count: eager!("yearindex_count"), - db, - }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - - Ok(this) - } - - pub fn compute( - &mut self, - indexer: &Indexer, - starting_indexes: brk_indexer::Indexes, - exit: &Exit, - ) -> Result { - let indexes = self.compute_(indexer, starting_indexes, exit)?; - let _lock = exit.lock(); - self.db.compact()?; - Ok(indexes) - } - - fn compute_( - &mut self, - indexer: &Indexer, - starting_indexes: brk_indexer::Indexes, - exit: &Exit, - ) -> Result { - self.txindex_to_input_count.compute_count_from_indexes( - starting_indexes.txindex, - &indexer.vecs.tx.txindex_to_first_txinindex, - &indexer.vecs.txin.txinindex_to_outpoint, - exit, - )?; - - self.txindex_to_output_count.compute_count_from_indexes( - starting_indexes.txindex, - &indexer.vecs.tx.txindex_to_first_txoutindex, - &indexer.vecs.txout.txoutindex_to_value, - exit, - )?; - - self.height_to_txindex_count.compute_count_from_indexes( - starting_indexes.height, - &indexer.vecs.tx.height_to_first_txindex, - &indexer.vecs.tx.txindex_to_txid, - exit, - )?; - - self.height_to_height.compute_from_index( - starting_indexes.height, - &indexer.vecs.block.height_to_weight, - exit, - )?; - - self.height_to_date.compute_transform( - starting_indexes.height, - &indexer.vecs.block.height_to_timestamp, - |(h, t, ..)| (h, Date::from(t)), - exit, - )?; - - let mut prev_timestamp_fixed = None; - self.height_to_timestamp_fixed.compute_transform( - starting_indexes.height, - &indexer.vecs.block.height_to_timestamp, - |(h, timestamp, height_to_timestamp_fixed_iter)| { - if prev_timestamp_fixed.is_none() - && let Some(prev_h) = h.decremented() - { - prev_timestamp_fixed.replace( - height_to_timestamp_fixed_iter - .into_iter() - .get_unwrap(prev_h), - ); - } - let timestamp_fixed = - prev_timestamp_fixed.map_or(timestamp, |prev_d| prev_d.max(timestamp)); - prev_timestamp_fixed.replace(timestamp_fixed); - (h, timestamp_fixed) - }, - exit, - )?; - - self.height_to_date_fixed.compute_transform( - starting_indexes.height, - &self.height_to_timestamp_fixed, - |(h, t, ..)| (h, Date::from(t)), - exit, - )?; - - let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default(); - - let starting_dateindex = self - .height_to_dateindex - .into_iter() - .get(decremented_starting_height) - .unwrap_or_default(); - - self.height_to_dateindex.compute_transform( - starting_indexes.height, - &self.height_to_date_fixed, - |(h, d, ..)| (h, DateIndex::try_from(d).unwrap()), - exit, - )?; - - let starting_dateindex = if let Some(dateindex) = self - .height_to_dateindex - .into_iter() - .get(decremented_starting_height) - { - starting_dateindex.min(dateindex) - } else { - starting_dateindex - }; - - self.dateindex_to_first_height.compute_coarser( - starting_indexes.height, - &self.height_to_dateindex, - exit, - )?; - - self.dateindex_to_dateindex.compute_from_index( - starting_dateindex, - &self.dateindex_to_first_height, - exit, - )?; - - self.dateindex_to_date.compute_from_index( - starting_dateindex, - &self.dateindex_to_first_height, - exit, - )?; - - self.dateindex_to_height_count.compute_count_from_indexes( - starting_dateindex, - &self.dateindex_to_first_height, - &indexer.vecs.block.height_to_weight, - exit, - )?; - - let starting_weekindex = self - .dateindex_to_weekindex - .into_iter() - .get(starting_dateindex) - .unwrap_or_default(); - - self.dateindex_to_weekindex.compute_range( - starting_dateindex, - &self.dateindex_to_dateindex, - |i| (i, WeekIndex::from(i)), - exit, - )?; - - self.weekindex_to_first_dateindex.compute_coarser( - starting_dateindex, - &self.dateindex_to_weekindex, - exit, - )?; - - self.weekindex_to_weekindex.compute_from_index( - starting_weekindex, - &self.weekindex_to_first_dateindex, - exit, - )?; - - self.weekindex_to_dateindex_count - .compute_count_from_indexes( - starting_weekindex, - &self.weekindex_to_first_dateindex, - &self.dateindex_to_date, - exit, - )?; - - let starting_difficultyepoch = self - .height_to_difficultyepoch - .into_iter() - .get(decremented_starting_height) - .unwrap_or_default(); - - self.height_to_difficultyepoch.compute_from_index( - starting_indexes.height, - &indexer.vecs.block.height_to_weight, - exit, - )?; - - self.difficultyepoch_to_first_height.compute_coarser( - starting_indexes.height, - &self.height_to_difficultyepoch, - exit, - )?; - - self.difficultyepoch_to_difficultyepoch.compute_from_index( - starting_difficultyepoch, - &self.difficultyepoch_to_first_height, - exit, - )?; - - self.difficultyepoch_to_height_count - .compute_count_from_indexes( - starting_difficultyepoch, - &self.difficultyepoch_to_first_height, - &self.height_to_date, - exit, - )?; - - let starting_monthindex = self - .dateindex_to_monthindex - .into_iter() - .get(starting_dateindex) - .unwrap_or_default(); - - self.dateindex_to_monthindex.compute_range( - starting_dateindex, - &self.dateindex_to_dateindex, - |i| (i, MonthIndex::from(i)), - exit, - )?; - - self.monthindex_to_first_dateindex.compute_coarser( - starting_dateindex, - &self.dateindex_to_monthindex, - exit, - )?; - - self.monthindex_to_monthindex.compute_from_index( - starting_monthindex, - &self.monthindex_to_first_dateindex, - exit, - )?; - - self.monthindex_to_dateindex_count - .compute_count_from_indexes( - starting_monthindex, - &self.monthindex_to_first_dateindex, - &self.dateindex_to_date, - exit, - )?; - - let starting_quarterindex = self - .monthindex_to_quarterindex - .into_iter() - .get(starting_monthindex) - .unwrap_or_default(); - - self.monthindex_to_quarterindex.compute_from_index( - starting_monthindex, - &self.monthindex_to_first_dateindex, - exit, - )?; - - self.quarterindex_to_first_monthindex.compute_coarser( - starting_monthindex, - &self.monthindex_to_quarterindex, - exit, - )?; - - // let quarter_count = self.quarterindex_to_first_monthindex.len(); - - self.quarterindex_to_quarterindex.compute_from_index( - starting_quarterindex, - &self.quarterindex_to_first_monthindex, - exit, - )?; - - self.quarterindex_to_monthindex_count - .compute_count_from_indexes( - starting_quarterindex, - &self.quarterindex_to_first_monthindex, - &self.monthindex_to_monthindex, - exit, - )?; - - let starting_semesterindex = self - .monthindex_to_semesterindex - .into_iter() - .get(starting_monthindex) - .unwrap_or_default(); - - self.monthindex_to_semesterindex.compute_from_index( - starting_monthindex, - &self.monthindex_to_first_dateindex, - exit, - )?; - - self.semesterindex_to_first_monthindex.compute_coarser( - starting_monthindex, - &self.monthindex_to_semesterindex, - exit, - )?; - - // let semester_count = self.semesterindex_to_first_monthindex.len(); - - self.semesterindex_to_semesterindex.compute_from_index( - starting_semesterindex, - &self.semesterindex_to_first_monthindex, - exit, - )?; - - self.semesterindex_to_monthindex_count - .compute_count_from_indexes( - starting_semesterindex, - &self.semesterindex_to_first_monthindex, - &self.monthindex_to_monthindex, - exit, - )?; - - let starting_yearindex = self - .monthindex_to_yearindex - .into_iter() - .get(starting_monthindex) - .unwrap_or_default(); - - self.monthindex_to_yearindex.compute_from_index( - starting_monthindex, - &self.monthindex_to_first_dateindex, - exit, - )?; - - self.yearindex_to_first_monthindex.compute_coarser( - starting_monthindex, - &self.monthindex_to_yearindex, - exit, - )?; - - self.yearindex_to_yearindex.compute_from_index( - starting_yearindex, - &self.yearindex_to_first_monthindex, - exit, - )?; - - self.yearindex_to_monthindex_count - .compute_count_from_indexes( - starting_yearindex, - &self.yearindex_to_first_monthindex, - &self.monthindex_to_monthindex, - exit, - )?; - - let starting_halvingepoch = self - .height_to_halvingepoch - .into_iter() - .get(decremented_starting_height) - .unwrap_or_default(); - - self.height_to_halvingepoch.compute_from_index( - starting_indexes.height, - &indexer.vecs.block.height_to_weight, - exit, - )?; - - self.halvingepoch_to_first_height.compute_coarser( - starting_indexes.height, - &self.height_to_halvingepoch, - exit, - )?; - - self.halvingepoch_to_halvingepoch.compute_from_index( - starting_halvingepoch, - &self.halvingepoch_to_first_height, - exit, - )?; - - let starting_decadeindex = self - .yearindex_to_decadeindex - .into_iter() - .get(starting_yearindex) - .unwrap_or_default(); - - self.yearindex_to_decadeindex.compute_from_index( - starting_yearindex, - &self.yearindex_to_first_monthindex, - exit, - )?; - - self.decadeindex_to_first_yearindex.compute_coarser( - starting_yearindex, - &self.yearindex_to_decadeindex, - exit, - )?; - - self.decadeindex_to_decadeindex.compute_from_index( - starting_decadeindex, - &self.decadeindex_to_first_yearindex, - exit, - )?; - - self.decadeindex_to_yearindex_count - .compute_count_from_indexes( - starting_decadeindex, - &self.decadeindex_to_first_yearindex, - &self.yearindex_to_yearindex, - exit, - )?; - - Ok(Indexes { - indexes: starting_indexes, - dateindex: starting_dateindex, - weekindex: starting_weekindex, - monthindex: starting_monthindex, - quarterindex: starting_quarterindex, - semesterindex: starting_semesterindex, - yearindex: starting_yearindex, - decadeindex: starting_decadeindex, - difficultyepoch: starting_difficultyepoch, - halvingepoch: starting_halvingepoch, - }) - } -} - -#[derive(Debug, Clone)] -pub struct Indexes { - indexes: brk_indexer::Indexes, - pub dateindex: DateIndex, - pub weekindex: WeekIndex, - pub monthindex: MonthIndex, - pub quarterindex: QuarterIndex, - pub semesterindex: SemesterIndex, - pub yearindex: YearIndex, - pub decadeindex: DecadeIndex, - pub difficultyepoch: DifficultyEpoch, - pub halvingepoch: HalvingEpoch, -} - -impl Indexes { - pub fn update_from_height(&mut self, height: Height, indexes: &Vecs) { - self.indexes.height = height; - self.dateindex = - DateIndex::try_from(indexes.height_to_date_fixed.into_iter().get_unwrap(height)) - .unwrap(); - self.weekindex = WeekIndex::from(self.dateindex); - self.monthindex = MonthIndex::from(self.dateindex); - self.quarterindex = QuarterIndex::from(self.monthindex); - self.semesterindex = SemesterIndex::from(self.monthindex); - self.yearindex = YearIndex::from(self.monthindex); - self.decadeindex = DecadeIndex::from(self.dateindex); - self.difficultyepoch = DifficultyEpoch::from(self.height); - self.halvingepoch = HalvingEpoch::from(self.height); - } -} - -impl Deref for Indexes { - type Target = brk_indexer::Indexes; - fn deref(&self) -> &Self::Target { - &self.indexes - } -} diff --git a/crates/brk_computer/src/indexes/address/import.rs b/crates/brk_computer/src/indexes/address/import.rs new file mode 100644 index 000000000..8e99e7c37 --- /dev/null +++ b/crates/brk_computer/src/indexes/address/import.rs @@ -0,0 +1,84 @@ +use brk_indexer::Indexer; +use brk_types::Version; +use vecdb::{IterableCloneableVec, LazyVecFrom1}; + +use super::Vecs; + +impl Vecs { + pub fn forced_import(version: Version, indexer: &Indexer) -> Self { + Self { + p2pk33addressindex_to_p2pk33addressindex: LazyVecFrom1::init( + "p2pk33addressindex", + version, + indexer.vecs.address.p2pk33addressindex_to_p2pk33bytes.boxed_clone(), + |index, _| Some(index), + ), + p2pk65addressindex_to_p2pk65addressindex: LazyVecFrom1::init( + "p2pk65addressindex", + version, + indexer.vecs.address.p2pk65addressindex_to_p2pk65bytes.boxed_clone(), + |index, _| Some(index), + ), + p2pkhaddressindex_to_p2pkhaddressindex: LazyVecFrom1::init( + "p2pkhaddressindex", + version, + indexer.vecs.address.p2pkhaddressindex_to_p2pkhbytes.boxed_clone(), + |index, _| Some(index), + ), + p2shaddressindex_to_p2shaddressindex: LazyVecFrom1::init( + "p2shaddressindex", + version, + indexer.vecs.address.p2shaddressindex_to_p2shbytes.boxed_clone(), + |index, _| Some(index), + ), + p2traddressindex_to_p2traddressindex: LazyVecFrom1::init( + "p2traddressindex", + version, + indexer.vecs.address.p2traddressindex_to_p2trbytes.boxed_clone(), + |index, _| Some(index), + ), + p2wpkhaddressindex_to_p2wpkhaddressindex: LazyVecFrom1::init( + "p2wpkhaddressindex", + version, + indexer.vecs.address.p2wpkhaddressindex_to_p2wpkhbytes.boxed_clone(), + |index, _| Some(index), + ), + p2wshaddressindex_to_p2wshaddressindex: LazyVecFrom1::init( + "p2wshaddressindex", + version, + indexer.vecs.address.p2wshaddressindex_to_p2wshbytes.boxed_clone(), + |index, _| Some(index), + ), + p2aaddressindex_to_p2aaddressindex: LazyVecFrom1::init( + "p2aaddressindex", + version, + indexer.vecs.address.p2aaddressindex_to_p2abytes.boxed_clone(), + |index, _| Some(index), + ), + p2msoutputindex_to_p2msoutputindex: LazyVecFrom1::init( + "p2msoutputindex", + version, + indexer.vecs.output.p2msoutputindex_to_txindex.boxed_clone(), + |index, _| Some(index), + ), + emptyoutputindex_to_emptyoutputindex: LazyVecFrom1::init( + "emptyoutputindex", + version, + indexer.vecs.output.emptyoutputindex_to_txindex.boxed_clone(), + |index, _| Some(index), + ), + unknownoutputindex_to_unknownoutputindex: LazyVecFrom1::init( + "unknownoutputindex", + version, + indexer.vecs.output.unknownoutputindex_to_txindex.boxed_clone(), + |index, _| Some(index), + ), + opreturnindex_to_opreturnindex: LazyVecFrom1::init( + "opreturnindex", + version, + indexer.vecs.output.opreturnindex_to_txindex.boxed_clone(), + |index, _| Some(index), + ), + } + } +} diff --git a/crates/brk_computer/src/indexes/address/mod.rs b/crates/brk_computer/src/indexes/address/mod.rs new file mode 100644 index 000000000..f8623047a --- /dev/null +++ b/crates/brk_computer/src/indexes/address/mod.rs @@ -0,0 +1,4 @@ +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/indexes/address/vecs.rs b/crates/brk_computer/src/indexes/address/vecs.rs new file mode 100644 index 000000000..6f5e115f4 --- /dev/null +++ b/crates/brk_computer/src/indexes/address/vecs.rs @@ -0,0 +1,36 @@ +use brk_traversable::Traversable; +use brk_types::{ + EmptyOutputIndex, OpReturnIndex, P2AAddressIndex, P2ABytes, P2MSOutputIndex, + P2PK33AddressIndex, P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex, + P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex, + P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, TxIndex, UnknownOutputIndex, +}; +use vecdb::LazyVecFrom1; + +#[derive(Clone, Traversable)] +pub struct Vecs { + pub emptyoutputindex_to_emptyoutputindex: + LazyVecFrom1, + pub opreturnindex_to_opreturnindex: + LazyVecFrom1, + pub p2aaddressindex_to_p2aaddressindex: + LazyVecFrom1, + pub p2msoutputindex_to_p2msoutputindex: + LazyVecFrom1, + pub p2pk33addressindex_to_p2pk33addressindex: + LazyVecFrom1, + pub p2pk65addressindex_to_p2pk65addressindex: + LazyVecFrom1, + pub p2pkhaddressindex_to_p2pkhaddressindex: + LazyVecFrom1, + pub p2shaddressindex_to_p2shaddressindex: + LazyVecFrom1, + pub p2traddressindex_to_p2traddressindex: + LazyVecFrom1, + pub p2wpkhaddressindex_to_p2wpkhaddressindex: + LazyVecFrom1, + pub p2wshaddressindex_to_p2wshaddressindex: + LazyVecFrom1, + pub unknownoutputindex_to_unknownoutputindex: + LazyVecFrom1, +} diff --git a/crates/brk_computer/src/indexes/block/compute.rs b/crates/brk_computer/src/indexes/block/compute.rs new file mode 100644 index 000000000..32039aa16 --- /dev/null +++ b/crates/brk_computer/src/indexes/block/compute.rs @@ -0,0 +1,149 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{Date, DateIndex, DifficultyEpoch, HalvingEpoch}; +use vecdb::{Exit, TypedVecIterator}; + +use super::Vecs; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + starting_indexes: &brk_indexer::Indexes, + exit: &Exit, + ) -> Result<(DateIndex, DifficultyEpoch, HalvingEpoch)> { + self.height_to_txindex_count.compute_count_from_indexes( + starting_indexes.height, + &indexer.vecs.tx.height_to_first_txindex, + &indexer.vecs.tx.txindex_to_txid, + exit, + )?; + + self.height_to_height.compute_from_index( + starting_indexes.height, + &indexer.vecs.block.height_to_weight, + exit, + )?; + + self.height_to_date.compute_transform( + starting_indexes.height, + &indexer.vecs.block.height_to_timestamp, + |(h, t, ..)| (h, Date::from(t)), + exit, + )?; + + let mut prev_timestamp_fixed = None; + self.height_to_timestamp_fixed.compute_transform( + starting_indexes.height, + &indexer.vecs.block.height_to_timestamp, + |(h, timestamp, height_to_timestamp_fixed_iter)| { + if prev_timestamp_fixed.is_none() + && let Some(prev_h) = h.decremented() + { + prev_timestamp_fixed.replace( + height_to_timestamp_fixed_iter + .into_iter() + .get_unwrap(prev_h), + ); + } + let timestamp_fixed = + prev_timestamp_fixed.map_or(timestamp, |prev_d| prev_d.max(timestamp)); + prev_timestamp_fixed.replace(timestamp_fixed); + (h, timestamp_fixed) + }, + exit, + )?; + + self.height_to_date_fixed.compute_transform( + starting_indexes.height, + &self.height_to_timestamp_fixed, + |(h, t, ..)| (h, Date::from(t)), + exit, + )?; + + let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default(); + + // DateIndex (computed before time module needs it) + let starting_dateindex = self + .height_to_dateindex + .into_iter() + .get(decremented_starting_height) + .unwrap_or_default(); + + self.height_to_dateindex.compute_transform( + starting_indexes.height, + &self.height_to_date_fixed, + |(h, d, ..)| (h, DateIndex::try_from(d).unwrap()), + exit, + )?; + + let starting_dateindex = if let Some(dateindex) = self + .height_to_dateindex + .into_iter() + .get(decremented_starting_height) + { + starting_dateindex.min(dateindex) + } else { + starting_dateindex + }; + + // Difficulty epoch + let starting_difficultyepoch = self + .height_to_difficultyepoch + .into_iter() + .get(decremented_starting_height) + .unwrap_or_default(); + + self.height_to_difficultyepoch.compute_from_index( + starting_indexes.height, + &indexer.vecs.block.height_to_weight, + exit, + )?; + + self.difficultyepoch_to_first_height.compute_coarser( + starting_indexes.height, + &self.height_to_difficultyepoch, + exit, + )?; + + self.difficultyepoch_to_difficultyepoch.compute_from_index( + starting_difficultyepoch, + &self.difficultyepoch_to_first_height, + exit, + )?; + + self.difficultyepoch_to_height_count.compute_count_from_indexes( + starting_difficultyepoch, + &self.difficultyepoch_to_first_height, + &self.height_to_date, + exit, + )?; + + // Halving epoch + let starting_halvingepoch = self + .height_to_halvingepoch + .into_iter() + .get(decremented_starting_height) + .unwrap_or_default(); + + self.height_to_halvingepoch.compute_from_index( + starting_indexes.height, + &indexer.vecs.block.height_to_weight, + exit, + )?; + + self.halvingepoch_to_first_height.compute_coarser( + starting_indexes.height, + &self.height_to_halvingepoch, + exit, + )?; + + self.halvingepoch_to_halvingepoch.compute_from_index( + starting_halvingepoch, + &self.halvingepoch_to_first_height, + exit, + )?; + + Ok((starting_dateindex, starting_difficultyepoch, starting_halvingepoch)) + } +} diff --git a/crates/brk_computer/src/indexes/block/import.rs b/crates/brk_computer/src/indexes/block/import.rs new file mode 100644 index 000000000..6e2b38038 --- /dev/null +++ b/crates/brk_computer/src/indexes/block/import.rs @@ -0,0 +1,25 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec}; + +use super::Vecs; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version) -> Result { + Ok(Self { + height_to_date: EagerVec::forced_import(db, "date", version)?, + height_to_date_fixed: EagerVec::forced_import(db, "date_fixed", version)?, + height_to_dateindex: EagerVec::forced_import(db, "dateindex", version)?, + height_to_difficultyepoch: EagerVec::forced_import(db, "difficultyepoch", version)?, + height_to_halvingepoch: EagerVec::forced_import(db, "halvingepoch", version)?, + height_to_height: EagerVec::forced_import(db, "height", version)?, + height_to_timestamp_fixed: EagerVec::forced_import(db, "timestamp_fixed", version)?, + height_to_txindex_count: EagerVec::forced_import(db, "txindex_count", version)?, + difficultyepoch_to_difficultyepoch: EagerVec::forced_import(db, "difficultyepoch", version)?, + difficultyepoch_to_first_height: EagerVec::forced_import(db, "first_height", version)?, + difficultyepoch_to_height_count: EagerVec::forced_import(db, "height_count", version)?, + halvingepoch_to_first_height: EagerVec::forced_import(db, "first_height", version)?, + halvingepoch_to_halvingepoch: EagerVec::forced_import(db, "halvingepoch", version)?, + }) + } +} diff --git a/crates/brk_computer/src/indexes/block/mod.rs b/crates/brk_computer/src/indexes/block/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/indexes/block/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/indexes/block/vecs.rs b/crates/brk_computer/src/indexes/block/vecs.rs new file mode 100644 index 000000000..7185b6376 --- /dev/null +++ b/crates/brk_computer/src/indexes/block/vecs.rs @@ -0,0 +1,20 @@ +use brk_traversable::Traversable; +use brk_types::{Date, DateIndex, DifficultyEpoch, HalvingEpoch, Height, StoredU64, Timestamp}; +use vecdb::{EagerVec, PcoVec}; + +#[derive(Clone, Traversable)] +pub struct Vecs { + pub height_to_date: EagerVec>, + pub height_to_date_fixed: EagerVec>, + pub height_to_dateindex: EagerVec>, + pub height_to_difficultyepoch: EagerVec>, + pub height_to_halvingepoch: EagerVec>, + pub height_to_height: EagerVec>, + pub height_to_timestamp_fixed: EagerVec>, + pub height_to_txindex_count: EagerVec>, + pub difficultyepoch_to_difficultyepoch: EagerVec>, + pub difficultyepoch_to_first_height: EagerVec>, + pub difficultyepoch_to_height_count: EagerVec>, + pub halvingepoch_to_first_height: EagerVec>, + pub halvingepoch_to_halvingepoch: EagerVec>, +} diff --git a/crates/brk_computer/src/indexes/mod.rs b/crates/brk_computer/src/indexes/mod.rs new file mode 100644 index 000000000..a56de7a27 --- /dev/null +++ b/crates/brk_computer/src/indexes/mod.rs @@ -0,0 +1,149 @@ +mod address; +mod block; +mod time; +mod transaction; + +use std::{ops::Deref, path::Path}; + +use brk_error::Result; +use brk_indexer::Indexer; +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, DifficultyEpoch, HalvingEpoch, Height, MonthIndex, QuarterIndex, + SemesterIndex, Version, WeekIndex, YearIndex, +}; +use vecdb::{Database, Exit, PAGE_SIZE, TypedVecIterator}; + +pub use address::Vecs as AddressVecs; +pub use block::Vecs as BlockVecs; +pub use time::Vecs as TimeVecs; +pub use transaction::Vecs as TransactionVecs; + +const VERSION: Version = Version::ZERO; +pub const DB_NAME: &str = "indexes"; + +#[derive(Clone, Traversable)] +pub struct Vecs { + db: Database, + pub address: AddressVecs, + pub block: BlockVecs, + pub time: TimeVecs, + pub transaction: TransactionVecs, +} + +impl Vecs { + pub fn forced_import( + parent: &Path, + parent_version: Version, + indexer: &Indexer, + ) -> Result { + let db = Database::open(&parent.join(DB_NAME))?; + db.set_min_len(PAGE_SIZE * 10_000_000)?; + + let version = parent_version + VERSION; + + let this = Self { + address: AddressVecs::forced_import(version, indexer), + block: BlockVecs::forced_import(&db, version)?, + time: TimeVecs::forced_import(&db, version)?, + transaction: TransactionVecs::forced_import(&db, version, indexer)?, + db, + }; + + this.db.retain_regions( + this.iter_any_exportable() + .flat_map(|v| v.region_names()) + .collect(), + )?; + this.db.compact()?; + + Ok(this) + } + + pub fn compute( + &mut self, + indexer: &Indexer, + starting_indexes: brk_indexer::Indexes, + exit: &Exit, + ) -> Result { + let indexes = self.compute_(indexer, starting_indexes, exit)?; + let _lock = exit.lock(); + self.db.compact()?; + Ok(indexes) + } + + fn compute_( + &mut self, + indexer: &Indexer, + starting_indexes: brk_indexer::Indexes, + exit: &Exit, + ) -> Result { + // Transaction indexes + self.transaction.compute(indexer, &starting_indexes, exit)?; + + // Block indexes (height, dateindex, difficultyepoch, halvingepoch) + let (starting_dateindex, starting_difficultyepoch, starting_halvingepoch) = + self.block.compute(indexer, &starting_indexes, exit)?; + + // Time indexes (depends on block.height_to_dateindex) + let time_indexes = self + .time + .compute(indexer, &starting_indexes, starting_dateindex, &self.block, exit)?; + + Ok(Indexes { + indexes: starting_indexes, + dateindex: time_indexes.dateindex, + weekindex: time_indexes.weekindex, + monthindex: time_indexes.monthindex, + quarterindex: time_indexes.quarterindex, + semesterindex: time_indexes.semesterindex, + yearindex: time_indexes.yearindex, + decadeindex: time_indexes.decadeindex, + difficultyepoch: starting_difficultyepoch, + halvingepoch: starting_halvingepoch, + }) + } +} + +#[derive(Debug, Clone)] +pub struct Indexes { + indexes: brk_indexer::Indexes, + pub dateindex: DateIndex, + pub weekindex: WeekIndex, + pub monthindex: MonthIndex, + pub quarterindex: QuarterIndex, + pub semesterindex: SemesterIndex, + pub yearindex: YearIndex, + pub decadeindex: DecadeIndex, + pub difficultyepoch: DifficultyEpoch, + pub halvingepoch: HalvingEpoch, +} + +impl Indexes { + pub fn update_from_height(&mut self, height: Height, indexes: &Vecs) { + self.indexes.height = height; + self.dateindex = DateIndex::try_from( + indexes + .block + .height_to_date_fixed + .into_iter() + .get_unwrap(height), + ) + .unwrap(); + self.weekindex = WeekIndex::from(self.dateindex); + self.monthindex = MonthIndex::from(self.dateindex); + self.quarterindex = QuarterIndex::from(self.monthindex); + self.semesterindex = SemesterIndex::from(self.monthindex); + self.yearindex = YearIndex::from(self.monthindex); + self.decadeindex = DecadeIndex::from(self.dateindex); + self.difficultyepoch = DifficultyEpoch::from(self.height); + self.halvingepoch = HalvingEpoch::from(self.height); + } +} + +impl Deref for Indexes { + type Target = brk_indexer::Indexes; + fn deref(&self) -> &Self::Target { + &self.indexes + } +} diff --git a/crates/brk_computer/src/indexes/time/compute.rs b/crates/brk_computer/src/indexes/time/compute.rs new file mode 100644 index 000000000..189a52397 --- /dev/null +++ b/crates/brk_computer/src/indexes/time/compute.rs @@ -0,0 +1,246 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::{DateIndex, MonthIndex, WeekIndex}; +use vecdb::{Exit, TypedVecIterator}; + +use super::{super::block, vecs::StartingTimeIndexes, Vecs}; + +impl Vecs { + pub fn compute( + &mut self, + indexer: &Indexer, + starting_indexes: &brk_indexer::Indexes, + starting_dateindex: DateIndex, + block_vecs: &block::Vecs, + exit: &Exit, + ) -> Result { + self.dateindex_to_first_height.compute_coarser( + starting_indexes.height, + &block_vecs.height_to_dateindex, + exit, + )?; + + self.dateindex_to_dateindex.compute_from_index( + starting_dateindex, + &self.dateindex_to_first_height, + exit, + )?; + + self.dateindex_to_date.compute_from_index( + starting_dateindex, + &self.dateindex_to_first_height, + exit, + )?; + + self.dateindex_to_height_count.compute_count_from_indexes( + starting_dateindex, + &self.dateindex_to_first_height, + &indexer.vecs.block.height_to_weight, + exit, + )?; + + // Week + let starting_weekindex = self + .dateindex_to_weekindex + .into_iter() + .get(starting_dateindex) + .unwrap_or_default(); + + self.dateindex_to_weekindex.compute_range( + starting_dateindex, + &self.dateindex_to_dateindex, + |i| (i, WeekIndex::from(i)), + exit, + )?; + + self.weekindex_to_first_dateindex.compute_coarser( + starting_dateindex, + &self.dateindex_to_weekindex, + exit, + )?; + + self.weekindex_to_weekindex.compute_from_index( + starting_weekindex, + &self.weekindex_to_first_dateindex, + exit, + )?; + + self.weekindex_to_dateindex_count.compute_count_from_indexes( + starting_weekindex, + &self.weekindex_to_first_dateindex, + &self.dateindex_to_date, + exit, + )?; + + // Month + let starting_monthindex = self + .dateindex_to_monthindex + .into_iter() + .get(starting_dateindex) + .unwrap_or_default(); + + self.dateindex_to_monthindex.compute_range( + starting_dateindex, + &self.dateindex_to_dateindex, + |i| (i, MonthIndex::from(i)), + exit, + )?; + + self.monthindex_to_first_dateindex.compute_coarser( + starting_dateindex, + &self.dateindex_to_monthindex, + exit, + )?; + + self.monthindex_to_monthindex.compute_from_index( + starting_monthindex, + &self.monthindex_to_first_dateindex, + exit, + )?; + + self.monthindex_to_dateindex_count.compute_count_from_indexes( + starting_monthindex, + &self.monthindex_to_first_dateindex, + &self.dateindex_to_date, + exit, + )?; + + // Quarter + let starting_quarterindex = self + .monthindex_to_quarterindex + .into_iter() + .get(starting_monthindex) + .unwrap_or_default(); + + self.monthindex_to_quarterindex.compute_from_index( + starting_monthindex, + &self.monthindex_to_first_dateindex, + exit, + )?; + + self.quarterindex_to_first_monthindex.compute_coarser( + starting_monthindex, + &self.monthindex_to_quarterindex, + exit, + )?; + + self.quarterindex_to_quarterindex.compute_from_index( + starting_quarterindex, + &self.quarterindex_to_first_monthindex, + exit, + )?; + + self.quarterindex_to_monthindex_count.compute_count_from_indexes( + starting_quarterindex, + &self.quarterindex_to_first_monthindex, + &self.monthindex_to_monthindex, + exit, + )?; + + // Semester + let starting_semesterindex = self + .monthindex_to_semesterindex + .into_iter() + .get(starting_monthindex) + .unwrap_or_default(); + + self.monthindex_to_semesterindex.compute_from_index( + starting_monthindex, + &self.monthindex_to_first_dateindex, + exit, + )?; + + self.semesterindex_to_first_monthindex.compute_coarser( + starting_monthindex, + &self.monthindex_to_semesterindex, + exit, + )?; + + self.semesterindex_to_semesterindex.compute_from_index( + starting_semesterindex, + &self.semesterindex_to_first_monthindex, + exit, + )?; + + self.semesterindex_to_monthindex_count.compute_count_from_indexes( + starting_semesterindex, + &self.semesterindex_to_first_monthindex, + &self.monthindex_to_monthindex, + exit, + )?; + + // Year + let starting_yearindex = self + .monthindex_to_yearindex + .into_iter() + .get(starting_monthindex) + .unwrap_or_default(); + + self.monthindex_to_yearindex.compute_from_index( + starting_monthindex, + &self.monthindex_to_first_dateindex, + exit, + )?; + + self.yearindex_to_first_monthindex.compute_coarser( + starting_monthindex, + &self.monthindex_to_yearindex, + exit, + )?; + + self.yearindex_to_yearindex.compute_from_index( + starting_yearindex, + &self.yearindex_to_first_monthindex, + exit, + )?; + + self.yearindex_to_monthindex_count.compute_count_from_indexes( + starting_yearindex, + &self.yearindex_to_first_monthindex, + &self.monthindex_to_monthindex, + exit, + )?; + + // Decade + let starting_decadeindex = self + .yearindex_to_decadeindex + .into_iter() + .get(starting_yearindex) + .unwrap_or_default(); + + self.yearindex_to_decadeindex.compute_from_index( + starting_yearindex, + &self.yearindex_to_first_monthindex, + exit, + )?; + + self.decadeindex_to_first_yearindex.compute_coarser( + starting_yearindex, + &self.yearindex_to_decadeindex, + exit, + )?; + + self.decadeindex_to_decadeindex.compute_from_index( + starting_decadeindex, + &self.decadeindex_to_first_yearindex, + exit, + )?; + + self.decadeindex_to_yearindex_count.compute_count_from_indexes( + starting_decadeindex, + &self.decadeindex_to_first_yearindex, + &self.yearindex_to_yearindex, + exit, + )?; + + Ok(StartingTimeIndexes { + dateindex: starting_dateindex, + weekindex: starting_weekindex, + monthindex: starting_monthindex, + quarterindex: starting_quarterindex, + semesterindex: starting_semesterindex, + yearindex: starting_yearindex, + decadeindex: starting_decadeindex, + }) + } +} diff --git a/crates/brk_computer/src/indexes/time/import.rs b/crates/brk_computer/src/indexes/time/import.rs new file mode 100644 index 000000000..4cbc44dae --- /dev/null +++ b/crates/brk_computer/src/indexes/time/import.rs @@ -0,0 +1,40 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec}; + +use super::Vecs; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version) -> Result { + Ok(Self { + dateindex_to_date: EagerVec::forced_import(db, "date", version)?, + dateindex_to_dateindex: EagerVec::forced_import(db, "dateindex", version)?, + dateindex_to_first_height: EagerVec::forced_import(db, "first_height", version)?, + dateindex_to_height_count: EagerVec::forced_import(db, "height_count", version)?, + dateindex_to_monthindex: EagerVec::forced_import(db, "monthindex", version)?, + dateindex_to_weekindex: EagerVec::forced_import(db, "weekindex", version)?, + weekindex_to_dateindex_count: EagerVec::forced_import(db, "dateindex_count", version)?, + weekindex_to_first_dateindex: EagerVec::forced_import(db, "first_dateindex", version)?, + weekindex_to_weekindex: EagerVec::forced_import(db, "weekindex", version)?, + monthindex_to_dateindex_count: EagerVec::forced_import(db, "dateindex_count", version)?, + monthindex_to_first_dateindex: EagerVec::forced_import(db, "first_dateindex", version)?, + monthindex_to_monthindex: EagerVec::forced_import(db, "monthindex", version)?, + monthindex_to_quarterindex: EagerVec::forced_import(db, "quarterindex", version)?, + monthindex_to_semesterindex: EagerVec::forced_import(db, "semesterindex", version)?, + monthindex_to_yearindex: EagerVec::forced_import(db, "yearindex", version)?, + quarterindex_to_first_monthindex: EagerVec::forced_import(db, "first_monthindex", version)?, + quarterindex_to_monthindex_count: EagerVec::forced_import(db, "monthindex_count", version)?, + quarterindex_to_quarterindex: EagerVec::forced_import(db, "quarterindex", version)?, + semesterindex_to_first_monthindex: EagerVec::forced_import(db, "first_monthindex", version)?, + semesterindex_to_monthindex_count: EagerVec::forced_import(db, "monthindex_count", version)?, + semesterindex_to_semesterindex: EagerVec::forced_import(db, "semesterindex", version)?, + yearindex_to_decadeindex: EagerVec::forced_import(db, "decadeindex", version)?, + yearindex_to_first_monthindex: EagerVec::forced_import(db, "first_monthindex", version)?, + yearindex_to_monthindex_count: EagerVec::forced_import(db, "monthindex_count", version)?, + yearindex_to_yearindex: EagerVec::forced_import(db, "yearindex", version)?, + decadeindex_to_decadeindex: EagerVec::forced_import(db, "decadeindex", version)?, + decadeindex_to_first_yearindex: EagerVec::forced_import(db, "first_yearindex", version)?, + decadeindex_to_yearindex_count: EagerVec::forced_import(db, "yearindex_count", version)?, + }) + } +} diff --git a/crates/brk_computer/src/indexes/time/mod.rs b/crates/brk_computer/src/indexes/time/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/indexes/time/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/indexes/time/vecs.rs b/crates/brk_computer/src/indexes/time/vecs.rs new file mode 100644 index 000000000..58d284069 --- /dev/null +++ b/crates/brk_computer/src/indexes/time/vecs.rs @@ -0,0 +1,48 @@ +use brk_traversable::Traversable; +use brk_types::{ + Date, DateIndex, DecadeIndex, Height, MonthIndex, QuarterIndex, SemesterIndex, StoredU64, + WeekIndex, YearIndex, +}; +use vecdb::{EagerVec, PcoVec}; + +#[derive(Clone, Traversable)] +pub struct Vecs { + pub dateindex_to_date: EagerVec>, + pub dateindex_to_dateindex: EagerVec>, + pub dateindex_to_first_height: EagerVec>, + pub dateindex_to_height_count: EagerVec>, + pub dateindex_to_monthindex: EagerVec>, + pub dateindex_to_weekindex: EagerVec>, + pub weekindex_to_dateindex_count: EagerVec>, + pub weekindex_to_first_dateindex: EagerVec>, + pub weekindex_to_weekindex: EagerVec>, + pub monthindex_to_dateindex_count: EagerVec>, + pub monthindex_to_first_dateindex: EagerVec>, + pub monthindex_to_monthindex: EagerVec>, + pub monthindex_to_quarterindex: EagerVec>, + pub monthindex_to_semesterindex: EagerVec>, + pub monthindex_to_yearindex: EagerVec>, + pub quarterindex_to_first_monthindex: EagerVec>, + pub quarterindex_to_monthindex_count: EagerVec>, + pub quarterindex_to_quarterindex: EagerVec>, + pub semesterindex_to_first_monthindex: EagerVec>, + pub semesterindex_to_monthindex_count: EagerVec>, + pub semesterindex_to_semesterindex: EagerVec>, + pub yearindex_to_decadeindex: EagerVec>, + pub yearindex_to_first_monthindex: EagerVec>, + pub yearindex_to_monthindex_count: EagerVec>, + pub yearindex_to_yearindex: EagerVec>, + pub decadeindex_to_decadeindex: EagerVec>, + pub decadeindex_to_first_yearindex: EagerVec>, + pub decadeindex_to_yearindex_count: EagerVec>, +} + +pub struct StartingTimeIndexes { + pub dateindex: DateIndex, + pub weekindex: WeekIndex, + pub monthindex: MonthIndex, + pub quarterindex: QuarterIndex, + pub semesterindex: SemesterIndex, + pub yearindex: YearIndex, + pub decadeindex: DecadeIndex, +} diff --git a/crates/brk_computer/src/indexes/transaction/compute.rs b/crates/brk_computer/src/indexes/transaction/compute.rs new file mode 100644 index 000000000..f30401e63 --- /dev/null +++ b/crates/brk_computer/src/indexes/transaction/compute.rs @@ -0,0 +1,25 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use vecdb::Exit; + +use super::Vecs; + +impl Vecs { + pub fn compute(&mut self, indexer: &Indexer, starting_indexes: &brk_indexer::Indexes, exit: &Exit) -> Result<()> { + self.txindex_to_input_count.compute_count_from_indexes( + starting_indexes.txindex, + &indexer.vecs.tx.txindex_to_first_txinindex, + &indexer.vecs.txin.txinindex_to_outpoint, + exit, + )?; + + self.txindex_to_output_count.compute_count_from_indexes( + starting_indexes.txindex, + &indexer.vecs.tx.txindex_to_first_txoutindex, + &indexer.vecs.txout.txoutindex_to_value, + exit, + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/indexes/transaction/import.rs b/crates/brk_computer/src/indexes/transaction/import.rs new file mode 100644 index 000000000..9dfe8fcca --- /dev/null +++ b/crates/brk_computer/src/indexes/transaction/import.rs @@ -0,0 +1,33 @@ +use brk_error::Result; +use brk_indexer::Indexer; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1}; + +use super::Vecs; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version, indexer: &Indexer) -> Result { + Ok(Self { + txindex_to_input_count: EagerVec::forced_import(db, "input_count", version)?, + txindex_to_output_count: EagerVec::forced_import(db, "output_count", version)?, + txindex_to_txindex: LazyVecFrom1::init( + "txindex", + version, + indexer.vecs.tx.txindex_to_txid.boxed_clone(), + |index, _| Some(index), + ), + txinindex_to_txinindex: LazyVecFrom1::init( + "txinindex", + version, + indexer.vecs.txin.txinindex_to_outpoint.boxed_clone(), + |index, _| Some(index), + ), + txoutindex_to_txoutindex: LazyVecFrom1::init( + "txoutindex", + version, + indexer.vecs.txout.txoutindex_to_value.boxed_clone(), + |index, _| Some(index), + ), + }) + } +} diff --git a/crates/brk_computer/src/indexes/transaction/mod.rs b/crates/brk_computer/src/indexes/transaction/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/indexes/transaction/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/indexes/transaction/vecs.rs b/crates/brk_computer/src/indexes/transaction/vecs.rs new file mode 100644 index 000000000..c610e69b4 --- /dev/null +++ b/crates/brk_computer/src/indexes/transaction/vecs.rs @@ -0,0 +1,12 @@ +use brk_traversable::Traversable; +use brk_types::{OutPoint, Sats, StoredU64, TxInIndex, TxIndex, TxOutIndex, Txid}; +use vecdb::{EagerVec, LazyVecFrom1, PcoVec}; + +#[derive(Clone, Traversable)] +pub struct Vecs { + pub txindex_to_input_count: EagerVec>, + pub txindex_to_output_count: EagerVec>, + pub txindex_to_txindex: LazyVecFrom1, + pub txinindex_to_txinindex: LazyVecFrom1, + pub txoutindex_to_txoutindex: LazyVecFrom1, +} diff --git a/crates/brk_computer/src/market/ath/compute.rs b/crates/brk_computer/src/market/ath/compute.rs new file mode 100644 index 000000000..b68b24928 --- /dev/null +++ b/crates/brk_computer/src/market/ath/compute.rs @@ -0,0 +1,93 @@ +use brk_error::Result; +use brk_types::StoredU16; +use vecdb::{Exit, GenericStoredVec, TypedVecIterator, VecIndex}; + +use super::Vecs; +use crate::{Indexes, price, traits::ComputeDrawdown, utils::OptionExt}; + +impl Vecs { + pub fn compute( + &mut self, + price: &price::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + self.height_to_price_ath.compute_all_time_high( + starting_indexes.height, + &price.chainindexes_to_price_high.height, + exit, + )?; + + self.height_to_price_drawdown.compute_drawdown( + starting_indexes.height, + &price.chainindexes_to_price_close.height, + &self.height_to_price_ath, + exit, + )?; + + self.indexes_to_price_ath + .compute_all(starting_indexes, exit, |v| { + v.compute_all_time_high( + starting_indexes.dateindex, + price.timeindexes_to_price_high.dateindex.u(), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_days_since_price_ath + .compute_all(starting_indexes, exit, |v| { + let mut high_iter = price.timeindexes_to_price_high.dateindex.u().into_iter(); + let mut prev = None; + v.compute_transform( + starting_indexes.dateindex, + self.indexes_to_price_ath.dateindex.u(), + |(i, ath, slf)| { + if prev.is_none() { + let i = i.to_usize(); + prev.replace(if i > 0 { + slf.get_pushed_or_read_at_unwrap_once(i - 1) + } else { + StoredU16::default() + }); + } + let days = if *high_iter.get_unwrap(i) == ath { + StoredU16::default() + } else { + prev.unwrap() + StoredU16::new(1) + }; + prev.replace(days); + (i, days) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_max_days_between_price_aths + .compute_all(starting_indexes, exit, |v| { + let mut prev = None; + v.compute_transform( + starting_indexes.dateindex, + self.indexes_to_days_since_price_ath.dateindex.u(), + |(i, days, slf)| { + if prev.is_none() { + let i = i.to_usize(); + prev.replace(if i > 0 { + slf.get_pushed_or_read_at_unwrap_once(i - 1) + } else { + StoredU16::ZERO + }); + } + let max = prev.unwrap().max(days); + prev.replace(max); + (i, max) + }, + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/market/ath/import.rs b/crates/brk_computer/src/market/ath/import.rs new file mode 100644 index 000000000..9802e6514 --- /dev/null +++ b/crates/brk_computer/src/market/ath/import.rs @@ -0,0 +1,78 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec}; + +use super::Vecs; +use crate::{ + grouped::{ + ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, LazyVecsFromDateIndex, + PercentageDiffCloseDollars, Source, StoredU16ToYears, VecBuilderOptions, + }, + indexes, price, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + price: &price::Vecs, + ) -> Result { + let v0 = Version::ZERO; + let last = VecBuilderOptions::default().add_last(); + + let indexes_to_price_ath = ComputedVecsFromDateIndex::forced_import( + db, + "price_ath", + Source::Compute, + version + v0, + indexes, + last, + )?; + + let indexes_to_max_days_between_price_aths = ComputedVecsFromDateIndex::forced_import( + db, + "max_days_between_price_aths", + Source::Compute, + version + v0, + indexes, + last, + )?; + + let indexes_to_max_years_between_price_aths = + LazyVecsFromDateIndex::from_computed::( + "max_years_between_price_aths", + version + v0, + indexes_to_max_days_between_price_aths + .dateindex + .as_ref() + .map(|v| v.boxed_clone()), + &indexes_to_max_days_between_price_aths, + ); + + let indexes_to_price_drawdown = + LazyVecsFrom2FromDateIndex::from_computed::( + "price_drawdown", + version + v0, + &price.timeindexes_to_price_close, + &indexes_to_price_ath, + ); + + Ok(Self { + height_to_price_ath: EagerVec::forced_import(db, "price_ath", version + v0)?, + height_to_price_drawdown: EagerVec::forced_import(db, "price_drawdown", version + v0)?, + indexes_to_price_ath, + indexes_to_price_drawdown, + indexes_to_days_since_price_ath: ComputedVecsFromDateIndex::forced_import( + db, + "days_since_price_ath", + Source::Compute, + version + v0, + indexes, + last, + )?, + indexes_to_max_days_between_price_aths, + indexes_to_max_years_between_price_aths, + }) + } +} diff --git a/crates/brk_computer/src/market/ath/mod.rs b/crates/brk_computer/src/market/ath/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/market/ath/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/market/ath/vecs.rs b/crates/brk_computer/src/market/ath/vecs.rs new file mode 100644 index 000000000..5b7785b50 --- /dev/null +++ b/crates/brk_computer/src/market/ath/vecs.rs @@ -0,0 +1,19 @@ +use brk_traversable::Traversable; +use brk_types::{Close, Dollars, Height, StoredF32, StoredU16}; +use vecdb::{EagerVec, PcoVec}; + +use crate::grouped::{ + ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, LazyVecsFromDateIndex, +}; + +/// All-time high related metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub height_to_price_ath: EagerVec>, + pub height_to_price_drawdown: EagerVec>, + pub indexes_to_price_ath: ComputedVecsFromDateIndex, + pub indexes_to_price_drawdown: LazyVecsFrom2FromDateIndex, Dollars>, + pub indexes_to_days_since_price_ath: ComputedVecsFromDateIndex, + pub indexes_to_max_days_between_price_aths: ComputedVecsFromDateIndex, + pub indexes_to_max_years_between_price_aths: LazyVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/market/compute.rs b/crates/brk_computer/src/market/compute.rs index 3646bc278..aa25cc2e8 100644 --- a/crates/brk_computer/src/market/compute.rs +++ b/crates/brk_computer/src/market/compute.rs @@ -1,14 +1,8 @@ -use std::thread; - use brk_error::Result; -use brk_types::{Date, DateIndex, StoredF32, StoredU16}; -use vecdb::{Exit, GenericStoredVec, TypedVecIterator, VecIndex}; +use vecdb::Exit; -use crate::{ - Indexes, price, - traits::{ComputeDCAAveragePriceViaLen, ComputeDCAStackViaLen, ComputeDrawdown}, - utils::OptionExt, -}; +use crate::{price, Indexes}; +use crate::utils::OptionExt; use super::Vecs; @@ -19,636 +13,30 @@ impl Vecs { starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { - self.compute_(price, starting_indexes, exit)?; + // ATH metrics (independent) + self.ath.compute(price, starting_indexes, exit)?; + + // History metrics (independent) + self.history.compute(price, starting_indexes, exit)?; + + // Volatility metrics (depends on history._1d_price_returns) + self.volatility.compute( + starting_indexes, + exit, + self.history._1d_price_returns.dateindex.u(), + )?; + + // Range metrics (independent) + self.range.compute(price, starting_indexes, exit)?; + + // Moving average metrics (independent) + self.moving_average.compute(price, starting_indexes, exit)?; + + // DCA metrics + self.dca.compute(price, starting_indexes, exit)?; + let _lock = exit.lock(); self.db.compact()?; Ok(()) } - - fn compute_( - &mut self, - price: &price::Vecs, - starting_indexes: &Indexes, - exit: &Exit, - ) -> Result<()> { - self.height_to_price_ath.compute_all_time_high( - starting_indexes.height, - &price.chainindexes_to_price_high.height, - exit, - )?; - self.height_to_price_drawdown.compute_drawdown( - starting_indexes.height, - &price.chainindexes_to_price_close.height, - &self.height_to_price_ath, - exit, - )?; - - self.indexes_to_price_ath - .compute_all(starting_indexes, exit, |v| { - v.compute_all_time_high( - starting_indexes.dateindex, - price.timeindexes_to_price_high.dateindex.u(), - exit, - )?; - Ok(()) - })?; - - self.indexes_to_days_since_price_ath - .compute_all(starting_indexes, exit, |v| { - let mut high_iter = price.timeindexes_to_price_high.dateindex.u().into_iter(); - let mut prev = None; - v.compute_transform( - starting_indexes.dateindex, - self.indexes_to_price_ath.dateindex.u(), - |(i, ath, slf)| { - if prev.is_none() { - let i = i.to_usize(); - prev.replace(if i > 0 { - slf.get_pushed_or_read_at_unwrap_once(i - 1) - } else { - StoredU16::default() - }); - } - let days = if *high_iter.get_unwrap(i) == ath { - StoredU16::default() - } else { - prev.unwrap() + StoredU16::new(1) - }; - prev.replace(days); - (i, days) - }, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_max_days_between_price_aths - .compute_all(starting_indexes, exit, |v| { - let mut prev = None; - v.compute_transform( - starting_indexes.dateindex, - self.indexes_to_days_since_price_ath.dateindex.u(), - |(i, days, slf)| { - if prev.is_none() { - let i = i.to_usize(); - prev.replace(if i > 0 { - slf.get_pushed_or_read_at_unwrap_once(i - 1) - } else { - StoredU16::ZERO - }); - } - let max = prev.unwrap().max(days); - prev.replace(max); - (i, max) - }, - exit, - )?; - Ok(()) - })?; - - [ - (1, &mut self.price_1d_ago, &self._1d_price_returns, None), - (7, &mut self.price_1w_ago, &self._1w_price_returns, None), - (30, &mut self.price_1m_ago, &self._1m_price_returns, None), - ( - 3 * 30, - &mut self.price_3m_ago, - &self._3m_price_returns, - None, - ), - ( - 6 * 30, - &mut self.price_6m_ago, - &self._6m_price_returns, - None, - ), - (365, &mut self.price_1y_ago, &self._1y_price_returns, None), - ( - 2 * 365, - &mut self.price_2y_ago, - &self._2y_price_returns, - Some(&mut self._2y_cagr), - ), - ( - 3 * 365, - &mut self.price_3y_ago, - &self._3y_price_returns, - Some(&mut self._3y_cagr), - ), - ( - 4 * 365, - &mut self.price_4y_ago, - &self._4y_price_returns, - Some(&mut self._4y_cagr), - ), - ( - 5 * 365, - &mut self.price_5y_ago, - &self._5y_price_returns, - Some(&mut self._5y_cagr), - ), - ( - 6 * 365, - &mut self.price_6y_ago, - &self._6y_price_returns, - Some(&mut self._6y_cagr), - ), - ( - 8 * 365, - &mut self.price_8y_ago, - &self._8y_price_returns, - Some(&mut self._8y_cagr), - ), - ( - 10 * 365, - &mut self.price_10y_ago, - &self._10y_price_returns, - Some(&mut self._10y_cagr), - ), - ] - .into_iter() - .try_for_each(|(days, ago, returns, cagr)| -> Result<()> { - ago.compute_all(starting_indexes, exit, |v| { - v.compute_previous_value( - starting_indexes.dateindex, - price.timeindexes_to_price_close.dateindex.u(), - days, - exit, - )?; - Ok(()) - })?; - - if let Some(cagr) = cagr { - cagr.compute_all(starting_indexes, exit, |v| { - v.compute_cagr( - starting_indexes.dateindex, - returns.dateindex.u(), - days, - exit, - )?; - Ok(()) - })?; - } - - Ok(()) - })?; - - [ - ( - 7, - &mut self._1w_dca_stack, - &mut self._1w_dca_avg_price, - &self._1w_dca_returns, - None, - ), - ( - 30, - &mut self._1m_dca_stack, - &mut self._1m_dca_avg_price, - &self._1m_dca_returns, - None, - ), - ( - 3 * 30, - &mut self._3m_dca_stack, - &mut self._3m_dca_avg_price, - &self._3m_dca_returns, - None, - ), - ( - 6 * 30, - &mut self._6m_dca_stack, - &mut self._6m_dca_avg_price, - &self._6m_dca_returns, - None, - ), - ( - 365, - &mut self._1y_dca_stack, - &mut self._1y_dca_avg_price, - &self._1y_dca_returns, - None, - ), - ( - 2 * 365, - &mut self._2y_dca_stack, - &mut self._2y_dca_avg_price, - &self._2y_dca_returns, - Some(&mut self._2y_dca_cagr), - ), - ( - 3 * 365, - &mut self._3y_dca_stack, - &mut self._3y_dca_avg_price, - &self._3y_dca_returns, - Some(&mut self._3y_dca_cagr), - ), - ( - 4 * 365, - &mut self._4y_dca_stack, - &mut self._4y_dca_avg_price, - &self._4y_dca_returns, - Some(&mut self._4y_dca_cagr), - ), - ( - 5 * 365, - &mut self._5y_dca_stack, - &mut self._5y_dca_avg_price, - &self._5y_dca_returns, - Some(&mut self._5y_dca_cagr), - ), - ( - 6 * 365, - &mut self._6y_dca_stack, - &mut self._6y_dca_avg_price, - &self._6y_dca_returns, - Some(&mut self._6y_dca_cagr), - ), - ( - 8 * 365, - &mut self._8y_dca_stack, - &mut self._8y_dca_avg_price, - &self._8y_dca_returns, - Some(&mut self._8y_dca_cagr), - ), - ( - 10 * 365, - &mut self._10y_dca_stack, - &mut self._10y_dca_avg_price, - &self._10y_dca_returns, - Some(&mut self._10y_dca_cagr), - ), - ] - .into_iter() - .try_for_each( - |(days, dca_stack, dca_avg_price, dca_returns, dca_cagr)| -> Result<()> { - dca_stack.compute_all(starting_indexes, exit, |v| { - v.compute_dca_stack_via_len( - starting_indexes.dateindex, - price.timeindexes_to_price_close.dateindex.u(), - days, - exit, - )?; - Ok(()) - })?; - - dca_avg_price.compute_all(starting_indexes, exit, |v| { - v.compute_dca_avg_price_via_len( - starting_indexes.dateindex, - dca_stack.dateindex.u(), - days, - exit, - )?; - Ok(()) - })?; - - if let Some(dca_cagr) = dca_cagr { - dca_cagr.compute_all(starting_indexes, exit, |v| { - v.compute_cagr( - starting_indexes.dateindex, - dca_returns.dateindex.u(), - days, - exit, - )?; - Ok(()) - })?; - } - - Ok(()) - }, - )?; - - [ - ( - 2015, - &mut self.dca_class_2015_avg_price, - &mut self.dca_class_2015_stack, - ), - ( - 2016, - &mut self.dca_class_2016_avg_price, - &mut self.dca_class_2016_stack, - ), - ( - 2017, - &mut self.dca_class_2017_avg_price, - &mut self.dca_class_2017_stack, - ), - ( - 2018, - &mut self.dca_class_2018_avg_price, - &mut self.dca_class_2018_stack, - ), - ( - 2019, - &mut self.dca_class_2019_avg_price, - &mut self.dca_class_2019_stack, - ), - ( - 2020, - &mut self.dca_class_2020_avg_price, - &mut self.dca_class_2020_stack, - ), - ( - 2021, - &mut self.dca_class_2021_avg_price, - &mut self.dca_class_2021_stack, - ), - ( - 2022, - &mut self.dca_class_2022_avg_price, - &mut self.dca_class_2022_stack, - ), - ( - 2023, - &mut self.dca_class_2023_avg_price, - &mut self.dca_class_2023_stack, - ), - ( - 2024, - &mut self.dca_class_2024_avg_price, - &mut self.dca_class_2024_stack, - ), - ( - 2025, - &mut self.dca_class_2025_avg_price, - &mut self.dca_class_2025_stack, - ), - ] - .into_iter() - .try_for_each(|(year, avg_price, stack)| -> Result<()> { - let dateindex = DateIndex::try_from(Date::new(year, 1, 1)).unwrap(); - - stack.compute_all(starting_indexes, exit, |v| { - v.compute_dca_stack_via_from( - starting_indexes.dateindex, - price.timeindexes_to_price_close.dateindex.u(), - dateindex, - exit, - )?; - Ok(()) - })?; - - avg_price.compute_all(starting_indexes, exit, |v| { - v.compute_dca_avg_price_via_from( - starting_indexes.dateindex, - stack.dateindex.u(), - dateindex, - exit, - )?; - Ok(()) - })?; - - Ok(()) - })?; - - thread::scope(|s| -> Result<()> { - [ - ( - &mut self.indexes_to_price_1w_sma, - &mut self.indexes_to_price_1w_ema, - 7, - ), - ( - &mut self.indexes_to_price_8d_sma, - &mut self.indexes_to_price_8d_ema, - 8, - ), - ( - &mut self.indexes_to_price_13d_sma, - &mut self.indexes_to_price_13d_ema, - 13, - ), - ( - &mut self.indexes_to_price_21d_sma, - &mut self.indexes_to_price_21d_ema, - 21, - ), - ( - &mut self.indexes_to_price_1m_sma, - &mut self.indexes_to_price_1m_ema, - 30, - ), - ( - &mut self.indexes_to_price_34d_sma, - &mut self.indexes_to_price_34d_ema, - 34, - ), - ( - &mut self.indexes_to_price_55d_sma, - &mut self.indexes_to_price_55d_ema, - 55, - ), - ( - &mut self.indexes_to_price_89d_sma, - &mut self.indexes_to_price_89d_ema, - 89, - ), - ( - &mut self.indexes_to_price_144d_sma, - &mut self.indexes_to_price_144d_ema, - 144, - ), - ( - &mut self.indexes_to_price_200d_sma, - &mut self.indexes_to_price_200d_ema, - 200, - ), - ( - &mut self.indexes_to_price_1y_sma, - &mut self.indexes_to_price_1y_ema, - 365, - ), - ( - &mut self.indexes_to_price_2y_sma, - &mut self.indexes_to_price_2y_ema, - 2 * 365, - ), - ( - &mut self.indexes_to_price_200w_sma, - &mut self.indexes_to_price_200w_ema, - 200 * 7, - ), - ( - &mut self.indexes_to_price_4y_sma, - &mut self.indexes_to_price_4y_ema, - 4 * 365, - ), - ] - .into_iter() - .for_each(|(sma, ema, days)| { - s.spawn(move || -> Result<()> { - sma.compute_all(price, starting_indexes, exit, |v| { - v.compute_sma( - starting_indexes.dateindex, - price.timeindexes_to_price_close.dateindex.u(), - days, - exit, - )?; - Ok(()) - })?; - - ema.compute_all(price, starting_indexes, exit, |v| { - v.compute_ema( - starting_indexes.dateindex, - price.timeindexes_to_price_close.dateindex.u(), - days, - exit, - )?; - Ok(()) - }) - }); - }); - Ok(()) - })?; - - self.indexes_to_1d_returns_1w_sd.compute_all( - starting_indexes, - exit, - self._1d_price_returns.dateindex.u(), - )?; - self.indexes_to_1d_returns_1m_sd.compute_all( - starting_indexes, - exit, - self._1d_price_returns.dateindex.u(), - )?; - self.indexes_to_1d_returns_1y_sd.compute_all( - starting_indexes, - exit, - self._1d_price_returns.dateindex.u(), - )?; - - self.dateindex_to_price_true_range.compute_transform3( - starting_indexes.dateindex, - price.timeindexes_to_price_open.dateindex.u(), - price.timeindexes_to_price_high.dateindex.u(), - price.timeindexes_to_price_low.dateindex.u(), - |(i, open, high, low, ..)| { - let high_min_low = **high - **low; - let high_min_open = (**high - **open).abs(); - let low_min_open = (**low - **open).abs(); - (i, high_min_low.max(high_min_open).max(low_min_open).into()) - }, - exit, - )?; - - self.dateindex_to_price_true_range_2w_sum.compute_sum( - starting_indexes.dateindex, - &self.dateindex_to_price_true_range, - 14, - exit, - )?; - - self.indexes_to_price_1w_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max( - starting_indexes.dateindex, - price.timeindexes_to_price_high.dateindex.u(), - 7, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_1w_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min( - starting_indexes.dateindex, - price.timeindexes_to_price_low.dateindex.u(), - 7, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_2w_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max( - starting_indexes.dateindex, - price.timeindexes_to_price_high.dateindex.u(), - 14, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_2w_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min( - starting_indexes.dateindex, - price.timeindexes_to_price_low.dateindex.u(), - 14, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_1m_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max( - starting_indexes.dateindex, - price.timeindexes_to_price_high.dateindex.u(), - 30, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_1m_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min( - starting_indexes.dateindex, - price.timeindexes_to_price_low.dateindex.u(), - 30, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_1y_max - .compute_all(starting_indexes, exit, |v| { - v.compute_max( - starting_indexes.dateindex, - price.timeindexes_to_price_high.dateindex.u(), - 365, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_1y_min - .compute_all(starting_indexes, exit, |v| { - v.compute_min( - starting_indexes.dateindex, - price.timeindexes_to_price_low.dateindex.u(), - 365, - exit, - )?; - Ok(()) - })?; - - self.indexes_to_price_2w_choppiness_index - .compute_all(starting_indexes, exit, |v| { - let n = 14; - let log10n = (n as f32).log10(); - v.compute_transform3( - starting_indexes.dateindex, - &self.dateindex_to_price_true_range_2w_sum, - self.indexes_to_price_2w_max.dateindex.u(), - self.indexes_to_price_2w_min.dateindex.u(), - |(i, tr_sum, max, min, ..)| { - ( - i, - StoredF32::from( - 100.0 * (*tr_sum / (*max - *min) as f32).log10() / log10n, - ), - ) - }, - exit, - )?; - Ok(()) - })?; - - Ok(()) - } } diff --git a/crates/brk_computer/src/market/dca/compute.rs b/crates/brk_computer/src/market/dca/compute.rs new file mode 100644 index 000000000..dc70e8e75 --- /dev/null +++ b/crates/brk_computer/src/market/dca/compute.rs @@ -0,0 +1,364 @@ +use brk_error::Result; +use brk_types::{Date, DateIndex}; +use vecdb::Exit; + +use super::Vecs; +use crate::{ + price, + traits::{ComputeDCAAveragePriceViaLen, ComputeDCAStackViaLen}, + utils::OptionExt, + Indexes, +}; + +impl Vecs { + pub fn compute( + &mut self, + price: &price::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + let close = price.timeindexes_to_price_close.dateindex.u(); + + // DCA by period - stack and avg_price + self._1w_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 7, exit)?; + Ok(()) + })?; + self._1w_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._1w_dca_stack.dateindex.u(), + 7, + exit, + )?; + Ok(()) + })?; + + self._1m_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 30, exit)?; + Ok(()) + })?; + self._1m_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._1m_dca_stack.dateindex.u(), + 30, + exit, + )?; + Ok(()) + })?; + + self._3m_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 3 * 30, exit)?; + Ok(()) + })?; + self._3m_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._3m_dca_stack.dateindex.u(), + 3 * 30, + exit, + )?; + Ok(()) + })?; + + self._6m_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 6 * 30, exit)?; + Ok(()) + })?; + self._6m_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._6m_dca_stack.dateindex.u(), + 6 * 30, + exit, + )?; + Ok(()) + })?; + + self._1y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 365, exit)?; + Ok(()) + })?; + self._1y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._1y_dca_stack.dateindex.u(), + 365, + exit, + )?; + Ok(()) + })?; + + self._2y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 2 * 365, exit)?; + Ok(()) + })?; + self._2y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._2y_dca_stack.dateindex.u(), + 2 * 365, + exit, + )?; + Ok(()) + })?; + + self._3y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 3 * 365, exit)?; + Ok(()) + })?; + self._3y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._3y_dca_stack.dateindex.u(), + 3 * 365, + exit, + )?; + Ok(()) + })?; + + self._4y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 4 * 365, exit)?; + Ok(()) + })?; + self._4y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._4y_dca_stack.dateindex.u(), + 4 * 365, + exit, + )?; + Ok(()) + })?; + + self._5y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 5 * 365, exit)?; + Ok(()) + })?; + self._5y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._5y_dca_stack.dateindex.u(), + 5 * 365, + exit, + )?; + Ok(()) + })?; + + self._6y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 6 * 365, exit)?; + Ok(()) + })?; + self._6y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._6y_dca_stack.dateindex.u(), + 6 * 365, + exit, + )?; + Ok(()) + })?; + + self._8y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 8 * 365, exit)?; + Ok(()) + })?; + self._8y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._8y_dca_stack.dateindex.u(), + 8 * 365, + exit, + )?; + Ok(()) + })?; + + self._10y_dca_stack + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_len(starting_indexes.dateindex, close, 10 * 365, exit)?; + Ok(()) + })?; + self._10y_dca_avg_price + .compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_len( + starting_indexes.dateindex, + self._10y_dca_stack.dateindex.u(), + 10 * 365, + exit, + )?; + Ok(()) + })?; + + // DCA by period - CAGR (computed from returns) + self._2y_dca_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._2y_dca_returns.dateindex.u(), + 2 * 365, + exit, + )?; + Ok(()) + })?; + self._3y_dca_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._3y_dca_returns.dateindex.u(), + 3 * 365, + exit, + )?; + Ok(()) + })?; + self._4y_dca_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._4y_dca_returns.dateindex.u(), + 4 * 365, + exit, + )?; + Ok(()) + })?; + self._5y_dca_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._5y_dca_returns.dateindex.u(), + 5 * 365, + exit, + )?; + Ok(()) + })?; + self._6y_dca_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._6y_dca_returns.dateindex.u(), + 6 * 365, + exit, + )?; + Ok(()) + })?; + self._8y_dca_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._8y_dca_returns.dateindex.u(), + 8 * 365, + exit, + )?; + Ok(()) + })?; + self._10y_dca_cagr + .compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._10y_dca_returns.dateindex.u(), + 10 * 365, + exit, + )?; + Ok(()) + })?; + + // DCA by year class - stack and avg_price + // Each year class computes DCA from Jan 1 of that year + [ + ( + 2025, + &mut self.dca_class_2025_stack, + &mut self.dca_class_2025_avg_price, + ), + ( + 2024, + &mut self.dca_class_2024_stack, + &mut self.dca_class_2024_avg_price, + ), + ( + 2023, + &mut self.dca_class_2023_stack, + &mut self.dca_class_2023_avg_price, + ), + ( + 2022, + &mut self.dca_class_2022_stack, + &mut self.dca_class_2022_avg_price, + ), + ( + 2021, + &mut self.dca_class_2021_stack, + &mut self.dca_class_2021_avg_price, + ), + ( + 2020, + &mut self.dca_class_2020_stack, + &mut self.dca_class_2020_avg_price, + ), + ( + 2019, + &mut self.dca_class_2019_stack, + &mut self.dca_class_2019_avg_price, + ), + ( + 2018, + &mut self.dca_class_2018_stack, + &mut self.dca_class_2018_avg_price, + ), + ( + 2017, + &mut self.dca_class_2017_stack, + &mut self.dca_class_2017_avg_price, + ), + ( + 2016, + &mut self.dca_class_2016_stack, + &mut self.dca_class_2016_avg_price, + ), + ( + 2015, + &mut self.dca_class_2015_stack, + &mut self.dca_class_2015_avg_price, + ), + ] + .into_iter() + .try_for_each(|(year, stack, avg_price)| -> Result<()> { + let dateindex = DateIndex::try_from(Date::new(year, 1, 1)).unwrap(); + + stack.compute_all(starting_indexes, exit, |v| { + v.compute_dca_stack_via_from(starting_indexes.dateindex, close, dateindex, exit)?; + Ok(()) + })?; + + avg_price.compute_all(starting_indexes, exit, |v| { + v.compute_dca_avg_price_via_from( + starting_indexes.dateindex, + stack.dateindex.u(), + dateindex, + exit, + )?; + Ok(()) + })?; + + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/market/dca/import.rs b/crates/brk_computer/src/market/dca/import.rs new file mode 100644 index 000000000..cfc424b17 --- /dev/null +++ b/crates/brk_computer/src/market/dca/import.rs @@ -0,0 +1,697 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::Database; + +use super::Vecs; +use crate::{ + grouped::{ + ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, PercentageDiffCloseDollars, Source, + VecBuilderOptions, + }, + indexes, price, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + price: &price::Vecs, + ) -> Result { + let v0 = Version::ZERO; + let last = VecBuilderOptions::default().add_last(); + + // DCA by period - stack + let _1w_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "1w_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _1m_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "1m_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _3m_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "3m_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _6m_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "6m_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _1y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "1y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _2y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "2y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _3y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "3y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _4y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "4y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _5y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "5y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _6y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "6y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _8y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "8y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _10y_dca_stack = ComputedVecsFromDateIndex::forced_import( + db, + "10y_dca_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + + // DCA by period - avg price + let _1w_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "1w_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _1m_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "1m_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _3m_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "3m_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _6m_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "6m_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _1y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "1y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _2y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "2y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _3y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "3y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _4y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "4y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _5y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "5y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _6y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "6y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _8y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "8y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _10y_dca_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "10y_dca_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + + // DCA by period - returns (lazy) + let _1w_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "1w_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_1w_dca_avg_price, + ); + let _1m_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "1m_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_1m_dca_avg_price, + ); + let _3m_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "3m_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_3m_dca_avg_price, + ); + let _6m_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "6m_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_6m_dca_avg_price, + ); + let _1y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "1y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_1y_dca_avg_price, + ); + let _2y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "2y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_2y_dca_avg_price, + ); + let _3y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "3y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_3y_dca_avg_price, + ); + let _4y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "4y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_4y_dca_avg_price, + ); + let _5y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "5y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_5y_dca_avg_price, + ); + let _6y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "6y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_6y_dca_avg_price, + ); + let _8y_dca_returns = LazyVecsFrom2FromDateIndex::from_computed::( + "8y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_8y_dca_avg_price, + ); + let _10y_dca_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "10y_dca_returns", + version + v0, + &price.timeindexes_to_price_close, + &_10y_dca_avg_price, + ); + + // DCA by period - CAGR + let _2y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "2y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _3y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "3y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _4y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "4y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _5y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "5y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _6y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "6y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _8y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "8y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + let _10y_dca_cagr = ComputedVecsFromDateIndex::forced_import( + db, + "10y_dca_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?; + + // DCA by year class - stack + let dca_class_2025_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2025_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2024_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2024_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2023_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2023_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2022_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2022_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2021_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2021_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2020_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2020_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2019_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2019_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2018_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2018_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2017_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2017_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2016_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2016_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2015_stack = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2015_stack", + Source::Compute, + version + v0, + indexes, + last, + )?; + + // DCA by year class - avg price + let dca_class_2025_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2025_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2024_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2024_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2023_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2023_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2022_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2022_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2021_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2021_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2020_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2020_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2019_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2019_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2018_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2018_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2017_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2017_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2016_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2016_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + let dca_class_2015_avg_price = ComputedVecsFromDateIndex::forced_import( + db, + "dca_class_2015_avg_price", + Source::Compute, + version + v0, + indexes, + last, + )?; + + // DCA by year class - returns (lazy) + let dca_class_2025_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2025_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2025_avg_price, + ); + let dca_class_2024_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2024_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2024_avg_price, + ); + let dca_class_2023_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2023_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2023_avg_price, + ); + let dca_class_2022_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2022_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2022_avg_price, + ); + let dca_class_2021_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2021_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2021_avg_price, + ); + let dca_class_2020_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2020_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2020_avg_price, + ); + let dca_class_2019_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2019_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2019_avg_price, + ); + let dca_class_2018_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2018_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2018_avg_price, + ); + let dca_class_2017_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2017_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2017_avg_price, + ); + let dca_class_2016_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2016_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2016_avg_price, + ); + let dca_class_2015_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "dca_class_2015_returns", + version + v0, + &price.timeindexes_to_price_close, + &dca_class_2015_avg_price, + ); + + Ok(Self { + _1w_dca_stack, + _1m_dca_stack, + _3m_dca_stack, + _6m_dca_stack, + _1y_dca_stack, + _2y_dca_stack, + _3y_dca_stack, + _4y_dca_stack, + _5y_dca_stack, + _6y_dca_stack, + _8y_dca_stack, + _10y_dca_stack, + + _1w_dca_avg_price, + _1m_dca_avg_price, + _3m_dca_avg_price, + _6m_dca_avg_price, + _1y_dca_avg_price, + _2y_dca_avg_price, + _3y_dca_avg_price, + _4y_dca_avg_price, + _5y_dca_avg_price, + _6y_dca_avg_price, + _8y_dca_avg_price, + _10y_dca_avg_price, + + _1w_dca_returns, + _1m_dca_returns, + _3m_dca_returns, + _6m_dca_returns, + _1y_dca_returns, + _2y_dca_returns, + _3y_dca_returns, + _4y_dca_returns, + _5y_dca_returns, + _6y_dca_returns, + _8y_dca_returns, + _10y_dca_returns, + + _2y_dca_cagr, + _3y_dca_cagr, + _4y_dca_cagr, + _5y_dca_cagr, + _6y_dca_cagr, + _8y_dca_cagr, + _10y_dca_cagr, + + dca_class_2025_stack, + dca_class_2024_stack, + dca_class_2023_stack, + dca_class_2022_stack, + dca_class_2021_stack, + dca_class_2020_stack, + dca_class_2019_stack, + dca_class_2018_stack, + dca_class_2017_stack, + dca_class_2016_stack, + dca_class_2015_stack, + + dca_class_2025_avg_price, + dca_class_2024_avg_price, + dca_class_2023_avg_price, + dca_class_2022_avg_price, + dca_class_2021_avg_price, + dca_class_2020_avg_price, + dca_class_2019_avg_price, + dca_class_2018_avg_price, + dca_class_2017_avg_price, + dca_class_2016_avg_price, + dca_class_2015_avg_price, + + dca_class_2025_returns, + dca_class_2024_returns, + dca_class_2023_returns, + dca_class_2022_returns, + dca_class_2021_returns, + dca_class_2020_returns, + dca_class_2019_returns, + dca_class_2018_returns, + dca_class_2017_returns, + dca_class_2016_returns, + dca_class_2015_returns, + }) + } +} diff --git a/crates/brk_computer/src/market/dca/mod.rs b/crates/brk_computer/src/market/dca/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/market/dca/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/market/dca/vecs.rs b/crates/brk_computer/src/market/dca/vecs.rs new file mode 100644 index 000000000..4f7c27809 --- /dev/null +++ b/crates/brk_computer/src/market/dca/vecs.rs @@ -0,0 +1,98 @@ +use brk_traversable::Traversable; +use brk_types::{Close, Dollars, Sats, StoredF32}; + +use crate::grouped::{ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex}; + +/// Dollar-cost averaging metrics by time period and year class +#[derive(Clone, Traversable)] +pub struct Vecs { + // DCA by period - stack + pub _1w_dca_stack: ComputedVecsFromDateIndex, + pub _1m_dca_stack: ComputedVecsFromDateIndex, + pub _3m_dca_stack: ComputedVecsFromDateIndex, + pub _6m_dca_stack: ComputedVecsFromDateIndex, + pub _1y_dca_stack: ComputedVecsFromDateIndex, + pub _2y_dca_stack: ComputedVecsFromDateIndex, + pub _3y_dca_stack: ComputedVecsFromDateIndex, + pub _4y_dca_stack: ComputedVecsFromDateIndex, + pub _5y_dca_stack: ComputedVecsFromDateIndex, + pub _6y_dca_stack: ComputedVecsFromDateIndex, + pub _8y_dca_stack: ComputedVecsFromDateIndex, + pub _10y_dca_stack: ComputedVecsFromDateIndex, + + // DCA by period - avg price + pub _1w_dca_avg_price: ComputedVecsFromDateIndex, + pub _1m_dca_avg_price: ComputedVecsFromDateIndex, + pub _3m_dca_avg_price: ComputedVecsFromDateIndex, + pub _6m_dca_avg_price: ComputedVecsFromDateIndex, + pub _1y_dca_avg_price: ComputedVecsFromDateIndex, + pub _2y_dca_avg_price: ComputedVecsFromDateIndex, + pub _3y_dca_avg_price: ComputedVecsFromDateIndex, + pub _4y_dca_avg_price: ComputedVecsFromDateIndex, + pub _5y_dca_avg_price: ComputedVecsFromDateIndex, + pub _6y_dca_avg_price: ComputedVecsFromDateIndex, + pub _8y_dca_avg_price: ComputedVecsFromDateIndex, + pub _10y_dca_avg_price: ComputedVecsFromDateIndex, + + // DCA by period - returns (lazy) + pub _1w_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _1m_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _3m_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _6m_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _1y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _2y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _3y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _4y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _5y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _6y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _8y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _10y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, + + // DCA by period - CAGR + pub _2y_dca_cagr: ComputedVecsFromDateIndex, + pub _3y_dca_cagr: ComputedVecsFromDateIndex, + pub _4y_dca_cagr: ComputedVecsFromDateIndex, + pub _5y_dca_cagr: ComputedVecsFromDateIndex, + pub _6y_dca_cagr: ComputedVecsFromDateIndex, + pub _8y_dca_cagr: ComputedVecsFromDateIndex, + pub _10y_dca_cagr: ComputedVecsFromDateIndex, + + // DCA by year class - stack + pub dca_class_2025_stack: ComputedVecsFromDateIndex, + pub dca_class_2024_stack: ComputedVecsFromDateIndex, + pub dca_class_2023_stack: ComputedVecsFromDateIndex, + pub dca_class_2022_stack: ComputedVecsFromDateIndex, + pub dca_class_2021_stack: ComputedVecsFromDateIndex, + pub dca_class_2020_stack: ComputedVecsFromDateIndex, + pub dca_class_2019_stack: ComputedVecsFromDateIndex, + pub dca_class_2018_stack: ComputedVecsFromDateIndex, + pub dca_class_2017_stack: ComputedVecsFromDateIndex, + pub dca_class_2016_stack: ComputedVecsFromDateIndex, + pub dca_class_2015_stack: ComputedVecsFromDateIndex, + + // DCA by year class - avg price + pub dca_class_2025_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2024_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2023_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2022_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2021_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2020_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2019_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2018_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2017_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2016_avg_price: ComputedVecsFromDateIndex, + pub dca_class_2015_avg_price: ComputedVecsFromDateIndex, + + // DCA by year class - returns (lazy) + pub dca_class_2025_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2024_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2023_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2022_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2021_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2020_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2019_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2018_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2017_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2016_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub dca_class_2015_returns: LazyVecsFrom2FromDateIndex, Dollars>, +} diff --git a/crates/brk_computer/src/market/history/compute.rs b/crates/brk_computer/src/market/history/compute.rs new file mode 100644 index 000000000..403fa075e --- /dev/null +++ b/crates/brk_computer/src/market/history/compute.rs @@ -0,0 +1,149 @@ +use brk_error::Result; +use vecdb::Exit; + +use super::Vecs; +use crate::{price, utils::OptionExt, Indexes}; + +impl Vecs { + pub fn compute( + &mut self, + price: &price::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + let close = price.timeindexes_to_price_close.dateindex.u(); + + self.price_1d_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 1, exit)?; + Ok(()) + })?; + + self.price_1w_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 7, exit)?; + Ok(()) + })?; + + self.price_1m_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 30, exit)?; + Ok(()) + })?; + + self.price_3m_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 3 * 30, exit)?; + Ok(()) + })?; + + self.price_6m_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 6 * 30, exit)?; + Ok(()) + })?; + + self.price_1y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 365, exit)?; + Ok(()) + })?; + + self.price_2y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 2 * 365, exit)?; + Ok(()) + })?; + + self.price_3y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 3 * 365, exit)?; + Ok(()) + })?; + + self.price_4y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 4 * 365, exit)?; + Ok(()) + })?; + + self.price_5y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 5 * 365, exit)?; + Ok(()) + })?; + + self.price_6y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 6 * 365, exit)?; + Ok(()) + })?; + + self.price_8y_ago.compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 8 * 365, exit)?; + Ok(()) + })?; + + self.price_10y_ago + .compute_all(starting_indexes, exit, |v| { + v.compute_previous_value(starting_indexes.dateindex, close, 10 * 365, exit)?; + Ok(()) + })?; + + // CAGR computed from returns + self._2y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._2y_price_returns.dateindex.u(), + 2 * 365, + exit, + )?; + Ok(()) + })?; + self._3y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._3y_price_returns.dateindex.u(), + 3 * 365, + exit, + )?; + Ok(()) + })?; + self._4y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._4y_price_returns.dateindex.u(), + 4 * 365, + exit, + )?; + Ok(()) + })?; + self._5y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._5y_price_returns.dateindex.u(), + 5 * 365, + exit, + )?; + Ok(()) + })?; + self._6y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._6y_price_returns.dateindex.u(), + 6 * 365, + exit, + )?; + Ok(()) + })?; + self._8y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._8y_price_returns.dateindex.u(), + 8 * 365, + exit, + )?; + Ok(()) + })?; + self._10y_cagr.compute_all(starting_indexes, exit, |v| { + v.compute_cagr( + starting_indexes.dateindex, + self._10y_price_returns.dateindex.u(), + 10 * 365, + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/market/history/import.rs b/crates/brk_computer/src/market/history/import.rs new file mode 100644 index 000000000..dd2edb50b --- /dev/null +++ b/crates/brk_computer/src/market/history/import.rs @@ -0,0 +1,308 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::Database; + +use super::Vecs; +use crate::{ + grouped::{ + ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, PercentageDiffCloseDollars, Source, + VecBuilderOptions, + }, + indexes, price, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + price: &price::Vecs, + ) -> Result { + let v0 = Version::ZERO; + let last = VecBuilderOptions::default().add_last(); + + let price_1d_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_1d_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_1w_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_1w_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_1m_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_1m_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_3m_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_3m_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_6m_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_6m_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_1y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_1y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_2y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_2y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_3y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_3y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_4y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_4y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_5y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_5y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_6y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_6y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_8y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_8y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + let price_10y_ago = ComputedVecsFromDateIndex::forced_import( + db, + "price_10y_ago", + Source::Compute, + version + v0, + indexes, + last, + )?; + + let _1d_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "1d_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_1d_ago, + ); + let _1w_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "1w_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_1w_ago, + ); + let _1m_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "1m_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_1m_ago, + ); + let _3m_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "3m_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_3m_ago, + ); + let _6m_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "6m_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_6m_ago, + ); + let _1y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "1y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_1y_ago, + ); + let _2y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "2y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_2y_ago, + ); + let _3y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "3y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_3y_ago, + ); + let _4y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "4y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_4y_ago, + ); + let _5y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "5y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_5y_ago, + ); + let _6y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "6y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_6y_ago, + ); + let _8y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "8y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_8y_ago, + ); + let _10y_price_returns = + LazyVecsFrom2FromDateIndex::from_computed::( + "10y_price_returns", + version + v0, + &price.timeindexes_to_price_close, + &price_10y_ago, + ); + + Ok(Self { + price_1d_ago, + price_1w_ago, + price_1m_ago, + price_3m_ago, + price_6m_ago, + price_1y_ago, + price_2y_ago, + price_3y_ago, + price_4y_ago, + price_5y_ago, + price_6y_ago, + price_8y_ago, + price_10y_ago, + + _1d_price_returns, + _1w_price_returns, + _1m_price_returns, + _3m_price_returns, + _6m_price_returns, + _1y_price_returns, + _2y_price_returns, + _3y_price_returns, + _4y_price_returns, + _5y_price_returns, + _6y_price_returns, + _8y_price_returns, + _10y_price_returns, + + _2y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "2y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + _3y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "3y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + _4y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "4y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + _5y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "5y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + _6y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "6y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + _8y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "8y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + _10y_cagr: ComputedVecsFromDateIndex::forced_import( + db, + "10y_cagr", + Source::Compute, + version + v0, + indexes, + last, + )?, + }) + } +} diff --git a/crates/brk_computer/src/market/history/mod.rs b/crates/brk_computer/src/market/history/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/market/history/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/market/history/vecs.rs b/crates/brk_computer/src/market/history/vecs.rs new file mode 100644 index 000000000..956fac33b --- /dev/null +++ b/crates/brk_computer/src/market/history/vecs.rs @@ -0,0 +1,44 @@ +use brk_traversable::Traversable; +use brk_types::{Close, Dollars, StoredF32}; + +use crate::grouped::{ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex}; + +/// Historical price lookback, returns, and CAGR metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub price_1d_ago: ComputedVecsFromDateIndex, + pub price_1w_ago: ComputedVecsFromDateIndex, + pub price_1m_ago: ComputedVecsFromDateIndex, + pub price_3m_ago: ComputedVecsFromDateIndex, + pub price_6m_ago: ComputedVecsFromDateIndex, + pub price_1y_ago: ComputedVecsFromDateIndex, + pub price_2y_ago: ComputedVecsFromDateIndex, + pub price_3y_ago: ComputedVecsFromDateIndex, + pub price_4y_ago: ComputedVecsFromDateIndex, + pub price_5y_ago: ComputedVecsFromDateIndex, + pub price_6y_ago: ComputedVecsFromDateIndex, + pub price_8y_ago: ComputedVecsFromDateIndex, + pub price_10y_ago: ComputedVecsFromDateIndex, + + pub _1d_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _1w_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _1m_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _3m_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _6m_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _1y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _2y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _3y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _4y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _5y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _6y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _8y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub _10y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, + + pub _2y_cagr: ComputedVecsFromDateIndex, + pub _3y_cagr: ComputedVecsFromDateIndex, + pub _4y_cagr: ComputedVecsFromDateIndex, + pub _5y_cagr: ComputedVecsFromDateIndex, + pub _6y_cagr: ComputedVecsFromDateIndex, + pub _8y_cagr: ComputedVecsFromDateIndex, + pub _10y_cagr: ComputedVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/market/import.rs b/crates/brk_computer/src/market/import.rs index 67cf30b48..3537bc26c 100644 --- a/crates/brk_computer/src/market/import.rs +++ b/crates/brk_computer/src/market/import.rs @@ -3,21 +3,14 @@ use std::path::Path; use brk_error::Result; use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, PAGE_SIZE}; +use vecdb::{Database, PAGE_SIZE}; -use crate::{ - grouped::{ - ComputedRatioVecsFromDateIndex, ComputedStandardDeviationVecsFromDateIndex, - ComputedVecsFromDateIndex, DollarsTimesTenths, LazyVecsFrom2FromDateIndex, - LazyVecsFromDateIndex, PercentageDiffCloseDollars, Source, StandardDeviationVecsOptions, - StoredF32TimesSqrt30, StoredF32TimesSqrt365, StoredF32TimesSqrt7, StoredU16ToYears, - VecBuilderOptions, - }, - indexes, price, +use crate::{indexes, price}; + +use super::{ + AthVecs, DcaVecs, HistoryVecs, MovingAverageVecs, RangeVecs, Vecs, VolatilityVecs, }; -use super::Vecs; - impl Vecs { pub fn forced_import( parent_path: &Path, @@ -29,442 +22,24 @@ impl Vecs { db.set_min_len(PAGE_SIZE * 1_000_000)?; let version = parent_version + Version::ZERO; - let v0 = Version::ZERO; - let v1 = Version::ONE; - let v2 = Version::TWO; - let last = VecBuilderOptions::default().add_last(); - macro_rules! computed_di { - ($name:expr) => { - ComputedVecsFromDateIndex::forced_import( - &db, - $name, - Source::Compute, - version + v0, - indexes, - last.clone(), - )? - }; - ($name:expr, $v:expr) => { - ComputedVecsFromDateIndex::forced_import( - &db, - $name, - Source::Compute, - version + $v, - indexes, - last.clone(), - )? - }; - } - macro_rules! ratio_di { - ($name:expr) => { - ComputedRatioVecsFromDateIndex::forced_import( - &db, - $name, - None, - version + v0, - indexes, - true, - price, - )? - }; - } - macro_rules! sd_di { - ($name:expr, $window:expr, $v:expr) => { - ComputedStandardDeviationVecsFromDateIndex::forced_import( - &db, - $name, - $window, - Source::Compute, - version + $v, - indexes, - StandardDeviationVecsOptions::default(), - None, // No USD conversion for market returns - )? - }; - } - macro_rules! eager_h { - ($name:expr, $v:expr) => { - EagerVec::forced_import(&db, $name, version + $v)? - }; - } - macro_rules! eager_di { - ($name:expr, $v:expr) => { - EagerVec::forced_import(&db, $name, version + $v)? - }; - } - - let indexes_to_price_200d_sma = ratio_di!("price_200d_sma"); - let price_200d_sma_source = indexes_to_price_200d_sma.price.as_ref().unwrap(); - let indexes_to_price_200d_sma_x2_4 = LazyVecsFromDateIndex::from_computed::< - DollarsTimesTenths<24>, - >( - "price_200d_sma_x2_4", - version + v0, - price_200d_sma_source.dateindex.as_ref().map(|v| v.boxed_clone()), - price_200d_sma_source, - ); - let indexes_to_price_200d_sma_x0_8 = LazyVecsFromDateIndex::from_computed::< - DollarsTimesTenths<8>, - >( - "price_200d_sma_x0_8", - version + v0, - price_200d_sma_source.dateindex.as_ref().map(|v| v.boxed_clone()), - price_200d_sma_source, - ); - - // SD vecs need to be created before lazy volatility vecs that reference them - let indexes_to_1d_returns_1w_sd = sd_di!("1d_returns_1w_sd", 7, v1); - let indexes_to_1d_returns_1m_sd = sd_di!("1d_returns_1m_sd", 30, v1); - let indexes_to_1d_returns_1y_sd = sd_di!("1d_returns_1y_sd", 365, v1); - let indexes_to_price_1w_volatility = - LazyVecsFromDateIndex::from_computed::( - "price_1w_volatility", - version + v2, - indexes_to_1d_returns_1w_sd - .sd - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), - &indexes_to_1d_returns_1w_sd.sd, - ); - let indexes_to_price_1m_volatility = - LazyVecsFromDateIndex::from_computed::( - "price_1m_volatility", - version + v2, - indexes_to_1d_returns_1m_sd - .sd - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), - &indexes_to_1d_returns_1m_sd.sd, - ); - let indexes_to_price_1y_volatility = - LazyVecsFromDateIndex::from_computed::( - "price_1y_volatility", - version + v2, - indexes_to_1d_returns_1y_sd - .sd - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), - &indexes_to_1d_returns_1y_sd.sd, - ); - - // max_days needs to be created before lazy max_years that references it - let indexes_to_max_days_between_price_aths = computed_di!("max_days_between_price_aths"); - let indexes_to_max_years_between_price_aths = - LazyVecsFromDateIndex::from_computed::( - "max_years_between_price_aths", - version + v0, - indexes_to_max_days_between_price_aths - .dateindex - .as_ref() - .map(|v| v.boxed_clone()), - &indexes_to_max_days_between_price_aths, - ); - - // price_ath needed for lazy drawdown - let indexes_to_price_ath = computed_di!("price_ath"); - - // Lazy drawdown from (price_close, price_ath) let price = price.expect("price required for market"); - let indexes_to_price_drawdown = - LazyVecsFrom2FromDateIndex::from_computed::( - "price_drawdown", - version + v0, - &price.timeindexes_to_price_close, - &indexes_to_price_ath, - ); - // price_ago needed for lazy price_returns - let price_1d_ago = computed_di!("price_1d_ago"); - let price_1w_ago = computed_di!("price_1w_ago"); - let price_1m_ago = computed_di!("price_1m_ago"); - let price_3m_ago = computed_di!("price_3m_ago"); - let price_6m_ago = computed_di!("price_6m_ago"); - let price_1y_ago = computed_di!("price_1y_ago"); - let price_2y_ago = computed_di!("price_2y_ago"); - let price_3y_ago = computed_di!("price_3y_ago"); - let price_4y_ago = computed_di!("price_4y_ago"); - let price_5y_ago = computed_di!("price_5y_ago"); - let price_6y_ago = computed_di!("price_6y_ago"); - let price_8y_ago = computed_di!("price_8y_ago"); - let price_10y_ago = computed_di!("price_10y_ago"); - - // Lazy price_returns from (price_close, price_ago) - macro_rules! lazy_price_returns { - ($name:expr, $price_ago:expr) => { - LazyVecsFrom2FromDateIndex::from_computed::( - $name, - version + v0, - &price.timeindexes_to_price_close, - $price_ago, - ) - }; - } - - let _1d_price_returns = lazy_price_returns!("1d_price_returns", &price_1d_ago); - let _1w_price_returns = lazy_price_returns!("1w_price_returns", &price_1w_ago); - let _1m_price_returns = lazy_price_returns!("1m_price_returns", &price_1m_ago); - let _3m_price_returns = lazy_price_returns!("3m_price_returns", &price_3m_ago); - let _6m_price_returns = lazy_price_returns!("6m_price_returns", &price_6m_ago); - let _1y_price_returns = lazy_price_returns!("1y_price_returns", &price_1y_ago); - let _2y_price_returns = lazy_price_returns!("2y_price_returns", &price_2y_ago); - let _3y_price_returns = lazy_price_returns!("3y_price_returns", &price_3y_ago); - let _4y_price_returns = lazy_price_returns!("4y_price_returns", &price_4y_ago); - let _5y_price_returns = lazy_price_returns!("5y_price_returns", &price_5y_ago); - let _6y_price_returns = lazy_price_returns!("6y_price_returns", &price_6y_ago); - let _8y_price_returns = lazy_price_returns!("8y_price_returns", &price_8y_ago); - let _10y_price_returns = lazy_price_returns!("10y_price_returns", &price_10y_ago); - - // DCA avg prices needed for lazy DCA returns - let _1w_dca_avg_price = computed_di!("1w_dca_avg_price"); - let _1m_dca_avg_price = computed_di!("1m_dca_avg_price"); - let _3m_dca_avg_price = computed_di!("3m_dca_avg_price"); - let _6m_dca_avg_price = computed_di!("6m_dca_avg_price"); - let _1y_dca_avg_price = computed_di!("1y_dca_avg_price"); - let _2y_dca_avg_price = computed_di!("2y_dca_avg_price"); - let _3y_dca_avg_price = computed_di!("3y_dca_avg_price"); - let _4y_dca_avg_price = computed_di!("4y_dca_avg_price"); - let _5y_dca_avg_price = computed_di!("5y_dca_avg_price"); - let _6y_dca_avg_price = computed_di!("6y_dca_avg_price"); - let _8y_dca_avg_price = computed_di!("8y_dca_avg_price"); - let _10y_dca_avg_price = computed_di!("10y_dca_avg_price"); - - let dca_class_2025_avg_price = computed_di!("dca_class_2025_avg_price"); - let dca_class_2024_avg_price = computed_di!("dca_class_2024_avg_price"); - let dca_class_2023_avg_price = computed_di!("dca_class_2023_avg_price"); - let dca_class_2022_avg_price = computed_di!("dca_class_2022_avg_price"); - let dca_class_2021_avg_price = computed_di!("dca_class_2021_avg_price"); - let dca_class_2020_avg_price = computed_di!("dca_class_2020_avg_price"); - let dca_class_2019_avg_price = computed_di!("dca_class_2019_avg_price"); - let dca_class_2018_avg_price = computed_di!("dca_class_2018_avg_price"); - let dca_class_2017_avg_price = computed_di!("dca_class_2017_avg_price"); - let dca_class_2016_avg_price = computed_di!("dca_class_2016_avg_price"); - let dca_class_2015_avg_price = computed_di!("dca_class_2015_avg_price"); - - // Macro for creating lazy DCA returns from (price_close, dca_avg_price) - macro_rules! lazy_dca_returns { - ($name:expr, $avg_price:expr) => { - LazyVecsFrom2FromDateIndex::from_computed::( - $name, - version + v0, - &price.timeindexes_to_price_close, - $avg_price, - ) - }; - } - - let _1w_dca_returns = lazy_dca_returns!("1w_dca_returns", &_1w_dca_avg_price); - let _1m_dca_returns = lazy_dca_returns!("1m_dca_returns", &_1m_dca_avg_price); - let _3m_dca_returns = lazy_dca_returns!("3m_dca_returns", &_3m_dca_avg_price); - let _6m_dca_returns = lazy_dca_returns!("6m_dca_returns", &_6m_dca_avg_price); - let _1y_dca_returns = lazy_dca_returns!("1y_dca_returns", &_1y_dca_avg_price); - let _2y_dca_returns = lazy_dca_returns!("2y_dca_returns", &_2y_dca_avg_price); - let _3y_dca_returns = lazy_dca_returns!("3y_dca_returns", &_3y_dca_avg_price); - let _4y_dca_returns = lazy_dca_returns!("4y_dca_returns", &_4y_dca_avg_price); - let _5y_dca_returns = lazy_dca_returns!("5y_dca_returns", &_5y_dca_avg_price); - let _6y_dca_returns = lazy_dca_returns!("6y_dca_returns", &_6y_dca_avg_price); - let _8y_dca_returns = lazy_dca_returns!("8y_dca_returns", &_8y_dca_avg_price); - let _10y_dca_returns = lazy_dca_returns!("10y_dca_returns", &_10y_dca_avg_price); - - let dca_class_2025_returns = - lazy_dca_returns!("dca_class_2025_returns", &dca_class_2025_avg_price); - let dca_class_2024_returns = - lazy_dca_returns!("dca_class_2024_returns", &dca_class_2024_avg_price); - let dca_class_2023_returns = - lazy_dca_returns!("dca_class_2023_returns", &dca_class_2023_avg_price); - let dca_class_2022_returns = - lazy_dca_returns!("dca_class_2022_returns", &dca_class_2022_avg_price); - let dca_class_2021_returns = - lazy_dca_returns!("dca_class_2021_returns", &dca_class_2021_avg_price); - let dca_class_2020_returns = - lazy_dca_returns!("dca_class_2020_returns", &dca_class_2020_avg_price); - let dca_class_2019_returns = - lazy_dca_returns!("dca_class_2019_returns", &dca_class_2019_avg_price); - let dca_class_2018_returns = - lazy_dca_returns!("dca_class_2018_returns", &dca_class_2018_avg_price); - let dca_class_2017_returns = - lazy_dca_returns!("dca_class_2017_returns", &dca_class_2017_avg_price); - let dca_class_2016_returns = - lazy_dca_returns!("dca_class_2016_returns", &dca_class_2016_avg_price); - let dca_class_2015_returns = - lazy_dca_returns!("dca_class_2015_returns", &dca_class_2015_avg_price); + let ath = AthVecs::forced_import(&db, version, indexes, price)?; + let volatility = VolatilityVecs::forced_import(&db, version, indexes)?; + let range = RangeVecs::forced_import(&db, version, indexes)?; + let moving_average = MovingAverageVecs::forced_import(&db, version, indexes, Some(price))?; + let history = HistoryVecs::forced_import(&db, version, indexes, price)?; + let dca = DcaVecs::forced_import(&db, version, indexes, price)?; let this = Self { - height_to_price_ath: eager_h!("price_ath", v0), - height_to_price_drawdown: eager_h!("price_drawdown", v0), - indexes_to_price_ath, - indexes_to_price_drawdown, - indexes_to_1d_returns_1w_sd, - indexes_to_1d_returns_1m_sd, - indexes_to_1d_returns_1y_sd, - indexes_to_price_1w_volatility, - indexes_to_price_1m_volatility, - indexes_to_price_1y_volatility, - indexes_to_days_since_price_ath: computed_di!("days_since_price_ath"), - indexes_to_max_days_between_price_aths, - indexes_to_max_years_between_price_aths, - - indexes_to_price_1w_sma: ratio_di!("price_1w_sma"), - indexes_to_price_8d_sma: ratio_di!("price_8d_sma"), - indexes_to_price_13d_sma: ratio_di!("price_13d_sma"), - indexes_to_price_21d_sma: ratio_di!("price_21d_sma"), - indexes_to_price_1m_sma: ratio_di!("price_1m_sma"), - indexes_to_price_34d_sma: ratio_di!("price_34d_sma"), - indexes_to_price_55d_sma: ratio_di!("price_55d_sma"), - indexes_to_price_89d_sma: ratio_di!("price_89d_sma"), - indexes_to_price_144d_sma: ratio_di!("price_144d_sma"), - indexes_to_price_200d_sma, - indexes_to_price_1y_sma: ratio_di!("price_1y_sma"), - indexes_to_price_2y_sma: ratio_di!("price_2y_sma"), - indexes_to_price_200w_sma: ratio_di!("price_200w_sma"), - indexes_to_price_4y_sma: ratio_di!("price_4y_sma"), - - indexes_to_price_1w_ema: ratio_di!("price_1w_ema"), - indexes_to_price_8d_ema: ratio_di!("price_8d_ema"), - indexes_to_price_13d_ema: ratio_di!("price_13d_ema"), - indexes_to_price_21d_ema: ratio_di!("price_21d_ema"), - indexes_to_price_1m_ema: ratio_di!("price_1m_ema"), - indexes_to_price_34d_ema: ratio_di!("price_34d_ema"), - indexes_to_price_55d_ema: ratio_di!("price_55d_ema"), - indexes_to_price_89d_ema: ratio_di!("price_89d_ema"), - indexes_to_price_144d_ema: ratio_di!("price_144d_ema"), - indexes_to_price_200d_ema: ratio_di!("price_200d_ema"), - indexes_to_price_1y_ema: ratio_di!("price_1y_ema"), - indexes_to_price_2y_ema: ratio_di!("price_2y_ema"), - indexes_to_price_200w_ema: ratio_di!("price_200w_ema"), - indexes_to_price_4y_ema: ratio_di!("price_4y_ema"), - - _1d_price_returns, - _1w_price_returns, - _1m_price_returns, - _3m_price_returns, - _6m_price_returns, - _1y_price_returns, - _2y_price_returns, - _3y_price_returns, - _4y_price_returns, - _5y_price_returns, - _6y_price_returns, - _8y_price_returns, - _10y_price_returns, - _2y_cagr: computed_di!("2y_cagr"), - _3y_cagr: computed_di!("3y_cagr"), - _4y_cagr: computed_di!("4y_cagr"), - _5y_cagr: computed_di!("5y_cagr"), - _6y_cagr: computed_di!("6y_cagr"), - _8y_cagr: computed_di!("8y_cagr"), - _10y_cagr: computed_di!("10y_cagr"), - - _1w_dca_returns, - _1m_dca_returns, - _3m_dca_returns, - _6m_dca_returns, - _1y_dca_returns, - _2y_dca_returns, - _3y_dca_returns, - _4y_dca_returns, - _5y_dca_returns, - _6y_dca_returns, - _8y_dca_returns, - _10y_dca_returns, - _2y_dca_cagr: computed_di!("2y_dca_cagr"), - _3y_dca_cagr: computed_di!("3y_dca_cagr"), - _4y_dca_cagr: computed_di!("4y_dca_cagr"), - _5y_dca_cagr: computed_di!("5y_dca_cagr"), - _6y_dca_cagr: computed_di!("6y_dca_cagr"), - _8y_dca_cagr: computed_di!("8y_dca_cagr"), - _10y_dca_cagr: computed_di!("10y_dca_cagr"), - _1w_dca_avg_price, - _1m_dca_avg_price, - _3m_dca_avg_price, - _6m_dca_avg_price, - _1y_dca_avg_price, - _2y_dca_avg_price, - _3y_dca_avg_price, - _4y_dca_avg_price, - _5y_dca_avg_price, - _6y_dca_avg_price, - _8y_dca_avg_price, - _10y_dca_avg_price, - price_1d_ago, - price_1w_ago, - price_1m_ago, - price_3m_ago, - price_6m_ago, - price_1y_ago, - price_2y_ago, - price_3y_ago, - price_4y_ago, - price_5y_ago, - price_6y_ago, - price_8y_ago, - price_10y_ago, - _1w_dca_stack: computed_di!("1w_dca_stack"), - _1m_dca_stack: computed_di!("1m_dca_stack"), - _3m_dca_stack: computed_di!("3m_dca_stack"), - _6m_dca_stack: computed_di!("6m_dca_stack"), - _1y_dca_stack: computed_di!("1y_dca_stack"), - _2y_dca_stack: computed_di!("2y_dca_stack"), - _3y_dca_stack: computed_di!("3y_dca_stack"), - _4y_dca_stack: computed_di!("4y_dca_stack"), - _5y_dca_stack: computed_di!("5y_dca_stack"), - _6y_dca_stack: computed_di!("6y_dca_stack"), - _8y_dca_stack: computed_di!("8y_dca_stack"), - _10y_dca_stack: computed_di!("10y_dca_stack"), - - dca_class_2025_stack: computed_di!("dca_class_2025_stack"), - dca_class_2024_stack: computed_di!("dca_class_2024_stack"), - dca_class_2023_stack: computed_di!("dca_class_2023_stack"), - dca_class_2022_stack: computed_di!("dca_class_2022_stack"), - dca_class_2021_stack: computed_di!("dca_class_2021_stack"), - dca_class_2020_stack: computed_di!("dca_class_2020_stack"), - dca_class_2019_stack: computed_di!("dca_class_2019_stack"), - dca_class_2018_stack: computed_di!("dca_class_2018_stack"), - dca_class_2017_stack: computed_di!("dca_class_2017_stack"), - dca_class_2016_stack: computed_di!("dca_class_2016_stack"), - dca_class_2015_stack: computed_di!("dca_class_2015_stack"), - - dca_class_2025_avg_price, - dca_class_2024_avg_price, - dca_class_2023_avg_price, - dca_class_2022_avg_price, - dca_class_2021_avg_price, - dca_class_2020_avg_price, - dca_class_2019_avg_price, - dca_class_2018_avg_price, - dca_class_2017_avg_price, - dca_class_2016_avg_price, - dca_class_2015_avg_price, - - dca_class_2025_returns, - dca_class_2024_returns, - dca_class_2023_returns, - dca_class_2022_returns, - dca_class_2021_returns, - dca_class_2020_returns, - dca_class_2019_returns, - dca_class_2018_returns, - dca_class_2017_returns, - dca_class_2016_returns, - dca_class_2015_returns, - - indexes_to_price_200d_sma_x2_4, - indexes_to_price_200d_sma_x0_8, - dateindex_to_price_true_range: eager_di!("price_true_range", v0), - dateindex_to_price_true_range_2w_sum: eager_di!("price_true_range_2w_sum", v0), - indexes_to_price_1w_min: computed_di!("price_1w_min", v1), - indexes_to_price_1w_max: computed_di!("price_1w_max", v1), - indexes_to_price_2w_min: computed_di!("price_2w_min", v1), - indexes_to_price_2w_max: computed_di!("price_2w_max", v1), - indexes_to_price_1m_min: computed_di!("price_1m_min", v1), - indexes_to_price_1m_max: computed_di!("price_1m_max", v1), - indexes_to_price_1y_min: computed_di!("price_1y_min", v1), - indexes_to_price_1y_max: computed_di!("price_1y_max", v1), - indexes_to_price_2w_choppiness_index: computed_di!("price_2w_choppiness_index", v1), db, + ath, + volatility, + range, + moving_average, + history, + dca, }; this.db.retain_regions( diff --git a/crates/brk_computer/src/market/mod.rs b/crates/brk_computer/src/market/mod.rs index 483eec15d..9610beb02 100644 --- a/crates/brk_computer/src/market/mod.rs +++ b/crates/brk_computer/src/market/mod.rs @@ -1,194 +1,33 @@ +pub mod ath; mod compute; +pub mod dca; +pub mod history; mod import; +pub mod moving_average; +pub mod range; +pub mod volatility; use brk_traversable::Traversable; -use brk_types::{Close, DateIndex, Dollars, Height, Sats, StoredF32, StoredU16}; -use vecdb::{Database, EagerVec, PcoVec}; +use vecdb::Database; -use crate::grouped::{ - ComputedRatioVecsFromDateIndex, ComputedStandardDeviationVecsFromDateIndex, - ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, LazyVecsFromDateIndex, -}; +pub use ath::Vecs as AthVecs; +pub use dca::Vecs as DcaVecs; +pub use history::Vecs as HistoryVecs; +pub use moving_average::Vecs as MovingAverageVecs; +pub use range::Vecs as RangeVecs; +pub use volatility::Vecs as VolatilityVecs; pub const DB_NAME: &str = "market"; +/// Main market metrics struct composed of sub-modules #[derive(Clone, Traversable)] pub struct Vecs { + #[traversable(skip)] pub(crate) db: Database, - - pub height_to_price_ath: EagerVec>, - pub height_to_price_drawdown: EagerVec>, - pub indexes_to_price_ath: ComputedVecsFromDateIndex, - pub indexes_to_price_drawdown: LazyVecsFrom2FromDateIndex, Dollars>, - pub indexes_to_days_since_price_ath: ComputedVecsFromDateIndex, - pub indexes_to_max_days_between_price_aths: ComputedVecsFromDateIndex, - pub indexes_to_max_years_between_price_aths: LazyVecsFromDateIndex, - - pub indexes_to_1d_returns_1w_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_1d_returns_1m_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_1d_returns_1y_sd: ComputedStandardDeviationVecsFromDateIndex, - pub indexes_to_price_1w_volatility: LazyVecsFromDateIndex, - pub indexes_to_price_1m_volatility: LazyVecsFromDateIndex, - pub indexes_to_price_1y_volatility: LazyVecsFromDateIndex, - - pub indexes_to_price_1w_min: ComputedVecsFromDateIndex, - pub indexes_to_price_1w_max: ComputedVecsFromDateIndex, - pub indexes_to_price_2w_min: ComputedVecsFromDateIndex, - pub indexes_to_price_2w_max: ComputedVecsFromDateIndex, - pub indexes_to_price_1m_min: ComputedVecsFromDateIndex, - pub indexes_to_price_1m_max: ComputedVecsFromDateIndex, - pub indexes_to_price_1y_min: ComputedVecsFromDateIndex, - pub indexes_to_price_1y_max: ComputedVecsFromDateIndex, - - pub dateindex_to_price_true_range: EagerVec>, - pub dateindex_to_price_true_range_2w_sum: EagerVec>, - pub indexes_to_price_2w_choppiness_index: ComputedVecsFromDateIndex, - - pub indexes_to_price_1w_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_8d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_13d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_21d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1m_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_34d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_55d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_89d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_144d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200d_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1y_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_2y_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200w_sma: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_4y_sma: ComputedRatioVecsFromDateIndex, - - pub indexes_to_price_1w_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_8d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_13d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_21d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1m_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_34d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_55d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_89d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_144d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200d_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_1y_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_2y_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_200w_ema: ComputedRatioVecsFromDateIndex, - pub indexes_to_price_4y_ema: ComputedRatioVecsFromDateIndex, - - pub indexes_to_price_200d_sma_x2_4: LazyVecsFromDateIndex, - pub indexes_to_price_200d_sma_x0_8: LazyVecsFromDateIndex, - - pub price_1d_ago: ComputedVecsFromDateIndex, - pub price_1w_ago: ComputedVecsFromDateIndex, - pub price_1m_ago: ComputedVecsFromDateIndex, - pub price_3m_ago: ComputedVecsFromDateIndex, - pub price_6m_ago: ComputedVecsFromDateIndex, - pub price_1y_ago: ComputedVecsFromDateIndex, - pub price_2y_ago: ComputedVecsFromDateIndex, - pub price_3y_ago: ComputedVecsFromDateIndex, - pub price_4y_ago: ComputedVecsFromDateIndex, - pub price_5y_ago: ComputedVecsFromDateIndex, - pub price_6y_ago: ComputedVecsFromDateIndex, - pub price_8y_ago: ComputedVecsFromDateIndex, - pub price_10y_ago: ComputedVecsFromDateIndex, - - pub _1d_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _1w_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _1m_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _3m_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _6m_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _1y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _2y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _3y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _4y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _5y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _6y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _8y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _10y_price_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _2y_cagr: ComputedVecsFromDateIndex, - pub _3y_cagr: ComputedVecsFromDateIndex, - pub _4y_cagr: ComputedVecsFromDateIndex, - pub _5y_cagr: ComputedVecsFromDateIndex, - pub _6y_cagr: ComputedVecsFromDateIndex, - pub _8y_cagr: ComputedVecsFromDateIndex, - pub _10y_cagr: ComputedVecsFromDateIndex, - - pub _1w_dca_stack: ComputedVecsFromDateIndex, - pub _1m_dca_stack: ComputedVecsFromDateIndex, - pub _3m_dca_stack: ComputedVecsFromDateIndex, - pub _6m_dca_stack: ComputedVecsFromDateIndex, - pub _1y_dca_stack: ComputedVecsFromDateIndex, - pub _2y_dca_stack: ComputedVecsFromDateIndex, - pub _3y_dca_stack: ComputedVecsFromDateIndex, - pub _4y_dca_stack: ComputedVecsFromDateIndex, - pub _5y_dca_stack: ComputedVecsFromDateIndex, - pub _6y_dca_stack: ComputedVecsFromDateIndex, - pub _8y_dca_stack: ComputedVecsFromDateIndex, - pub _10y_dca_stack: ComputedVecsFromDateIndex, - pub _1w_dca_avg_price: ComputedVecsFromDateIndex, - pub _1m_dca_avg_price: ComputedVecsFromDateIndex, - pub _3m_dca_avg_price: ComputedVecsFromDateIndex, - pub _6m_dca_avg_price: ComputedVecsFromDateIndex, - pub _1y_dca_avg_price: ComputedVecsFromDateIndex, - pub _2y_dca_avg_price: ComputedVecsFromDateIndex, - pub _3y_dca_avg_price: ComputedVecsFromDateIndex, - pub _4y_dca_avg_price: ComputedVecsFromDateIndex, - pub _5y_dca_avg_price: ComputedVecsFromDateIndex, - pub _6y_dca_avg_price: ComputedVecsFromDateIndex, - pub _8y_dca_avg_price: ComputedVecsFromDateIndex, - pub _10y_dca_avg_price: ComputedVecsFromDateIndex, - pub _1w_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _1m_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _3m_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _6m_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _1y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _2y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _3y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _4y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _5y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _6y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _8y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _10y_dca_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub _2y_dca_cagr: ComputedVecsFromDateIndex, - pub _3y_dca_cagr: ComputedVecsFromDateIndex, - pub _4y_dca_cagr: ComputedVecsFromDateIndex, - pub _5y_dca_cagr: ComputedVecsFromDateIndex, - pub _6y_dca_cagr: ComputedVecsFromDateIndex, - pub _8y_dca_cagr: ComputedVecsFromDateIndex, - pub _10y_dca_cagr: ComputedVecsFromDateIndex, - - pub dca_class_2025_stack: ComputedVecsFromDateIndex, - pub dca_class_2024_stack: ComputedVecsFromDateIndex, - pub dca_class_2023_stack: ComputedVecsFromDateIndex, - pub dca_class_2022_stack: ComputedVecsFromDateIndex, - pub dca_class_2021_stack: ComputedVecsFromDateIndex, - pub dca_class_2020_stack: ComputedVecsFromDateIndex, - pub dca_class_2019_stack: ComputedVecsFromDateIndex, - pub dca_class_2018_stack: ComputedVecsFromDateIndex, - pub dca_class_2017_stack: ComputedVecsFromDateIndex, - pub dca_class_2016_stack: ComputedVecsFromDateIndex, - pub dca_class_2015_stack: ComputedVecsFromDateIndex, - - pub dca_class_2025_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2024_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2023_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2022_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2021_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2020_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2019_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2018_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2017_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2016_avg_price: ComputedVecsFromDateIndex, - pub dca_class_2015_avg_price: ComputedVecsFromDateIndex, - - pub dca_class_2025_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2024_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2023_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2022_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2021_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2020_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2019_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2018_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2017_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2016_returns: LazyVecsFrom2FromDateIndex, Dollars>, - pub dca_class_2015_returns: LazyVecsFrom2FromDateIndex, Dollars>, + pub ath: AthVecs, + pub volatility: VolatilityVecs, + pub range: RangeVecs, + pub moving_average: MovingAverageVecs, + pub history: HistoryVecs, + pub dca: DcaVecs, } diff --git a/crates/brk_computer/src/market/moving_average/compute.rs b/crates/brk_computer/src/market/moving_average/compute.rs new file mode 100644 index 000000000..f2ddecea6 --- /dev/null +++ b/crates/brk_computer/src/market/moving_average/compute.rs @@ -0,0 +1,188 @@ +use brk_error::Result; +use vecdb::Exit; + +use super::Vecs; +use crate::{price, utils::OptionExt, Indexes}; + +impl Vecs { + pub fn compute( + &mut self, + price: &price::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + let close = price.timeindexes_to_price_close.dateindex.u(); + + // SMAs + self.indexes_to_price_1w_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 7, exit)?; + Ok(()) + })?; + + self.indexes_to_price_8d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 8, exit)?; + Ok(()) + })?; + + self.indexes_to_price_13d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 13, exit)?; + Ok(()) + })?; + + self.indexes_to_price_21d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 21, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1m_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 30, exit)?; + Ok(()) + })?; + + self.indexes_to_price_34d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 34, exit)?; + Ok(()) + })?; + + self.indexes_to_price_55d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 55, exit)?; + Ok(()) + })?; + + self.indexes_to_price_89d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 89, exit)?; + Ok(()) + })?; + + self.indexes_to_price_144d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 144, exit)?; + Ok(()) + })?; + + self.indexes_to_price_200d_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 200, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1y_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 365, exit)?; + Ok(()) + })?; + + self.indexes_to_price_2y_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 2 * 365, exit)?; + Ok(()) + })?; + + self.indexes_to_price_200w_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 200 * 7, exit)?; + Ok(()) + })?; + + self.indexes_to_price_4y_sma + .compute_all(price, starting_indexes, exit, |v| { + v.compute_sma(starting_indexes.dateindex, close, 4 * 365, exit)?; + Ok(()) + })?; + + // EMAs + self.indexes_to_price_1w_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 7, exit)?; + Ok(()) + })?; + + self.indexes_to_price_8d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 8, exit)?; + Ok(()) + })?; + + self.indexes_to_price_13d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 13, exit)?; + Ok(()) + })?; + + self.indexes_to_price_21d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 21, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1m_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 30, exit)?; + Ok(()) + })?; + + self.indexes_to_price_34d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 34, exit)?; + Ok(()) + })?; + + self.indexes_to_price_55d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 55, exit)?; + Ok(()) + })?; + + self.indexes_to_price_89d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 89, exit)?; + Ok(()) + })?; + + self.indexes_to_price_144d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 144, exit)?; + Ok(()) + })?; + + self.indexes_to_price_200d_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 200, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1y_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 365, exit)?; + Ok(()) + })?; + + self.indexes_to_price_2y_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 2 * 365, exit)?; + Ok(()) + })?; + + self.indexes_to_price_200w_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 200 * 7, exit)?; + Ok(()) + })?; + + self.indexes_to_price_4y_ema + .compute_all(price, starting_indexes, exit, |v| { + v.compute_ema(starting_indexes.dateindex, close, 4 * 365, exit)?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/market/moving_average/import.rs b/crates/brk_computer/src/market/moving_average/import.rs new file mode 100644 index 000000000..c88fd02e3 --- /dev/null +++ b/crates/brk_computer/src/market/moving_average/import.rs @@ -0,0 +1,331 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, IterableCloneableVec}; + +use super::Vecs; +use crate::{ + grouped::{ComputedRatioVecsFromDateIndex, DollarsTimesTenths, LazyVecsFromDateIndex}, + indexes, price, +}; + +impl Vecs { + pub fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + price: Option<&price::Vecs>, + ) -> Result { + let v0 = Version::ZERO; + + let indexes_to_price_1w_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_1w_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_8d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_8d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_13d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_13d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_21d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_21d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_1m_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_1m_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_34d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_34d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_55d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_55d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_89d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_89d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_144d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_144d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_200d_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_200d_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_1y_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_1y_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_2y_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_2y_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_200w_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_200w_sma", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_4y_sma = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_4y_sma", + None, + version + v0, + indexes, + true, + price, + )?; + + let indexes_to_price_1w_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_1w_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_8d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_8d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_13d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_13d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_21d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_21d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_1m_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_1m_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_34d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_34d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_55d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_55d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_89d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_89d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_144d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_144d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_200d_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_200d_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_1y_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_1y_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_2y_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_2y_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_200w_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_200w_ema", + None, + version + v0, + indexes, + true, + price, + )?; + let indexes_to_price_4y_ema = ComputedRatioVecsFromDateIndex::forced_import( + db, + "price_4y_ema", + None, + version + v0, + indexes, + true, + price, + )?; + + let price_200d_sma_source = indexes_to_price_200d_sma.price.as_ref().unwrap(); + let indexes_to_price_200d_sma_x2_4 = + LazyVecsFromDateIndex::from_computed::>( + "price_200d_sma_x2_4", + version + v0, + price_200d_sma_source + .dateindex + .as_ref() + .map(|v| v.boxed_clone()), + price_200d_sma_source, + ); + let indexes_to_price_200d_sma_x0_8 = + LazyVecsFromDateIndex::from_computed::>( + "price_200d_sma_x0_8", + version + v0, + price_200d_sma_source + .dateindex + .as_ref() + .map(|v| v.boxed_clone()), + price_200d_sma_source, + ); + + Ok(Self { + indexes_to_price_1w_sma, + indexes_to_price_8d_sma, + indexes_to_price_13d_sma, + indexes_to_price_21d_sma, + indexes_to_price_1m_sma, + indexes_to_price_34d_sma, + indexes_to_price_55d_sma, + indexes_to_price_89d_sma, + indexes_to_price_144d_sma, + indexes_to_price_200d_sma, + indexes_to_price_1y_sma, + indexes_to_price_2y_sma, + indexes_to_price_200w_sma, + indexes_to_price_4y_sma, + + indexes_to_price_1w_ema, + indexes_to_price_8d_ema, + indexes_to_price_13d_ema, + indexes_to_price_21d_ema, + indexes_to_price_1m_ema, + indexes_to_price_34d_ema, + indexes_to_price_55d_ema, + indexes_to_price_89d_ema, + indexes_to_price_144d_ema, + indexes_to_price_200d_ema, + indexes_to_price_1y_ema, + indexes_to_price_2y_ema, + indexes_to_price_200w_ema, + indexes_to_price_4y_ema, + + indexes_to_price_200d_sma_x2_4, + indexes_to_price_200d_sma_x0_8, + }) + } +} diff --git a/crates/brk_computer/src/market/moving_average/mod.rs b/crates/brk_computer/src/market/moving_average/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/market/moving_average/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/market/moving_average/vecs.rs b/crates/brk_computer/src/market/moving_average/vecs.rs new file mode 100644 index 000000000..77065f164 --- /dev/null +++ b/crates/brk_computer/src/market/moving_average/vecs.rs @@ -0,0 +1,41 @@ +use brk_traversable::Traversable; +use brk_types::Dollars; + +use crate::grouped::{ComputedRatioVecsFromDateIndex, LazyVecsFromDateIndex}; + +/// Simple and exponential moving average metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_price_1w_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_8d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_13d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_21d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_1m_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_34d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_55d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_89d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_144d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_200d_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_1y_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_2y_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_200w_sma: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_4y_sma: ComputedRatioVecsFromDateIndex, + + pub indexes_to_price_1w_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_8d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_13d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_21d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_1m_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_34d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_55d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_89d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_144d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_200d_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_1y_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_2y_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_200w_ema: ComputedRatioVecsFromDateIndex, + pub indexes_to_price_4y_ema: ComputedRatioVecsFromDateIndex, + + pub indexes_to_price_200d_sma_x2_4: LazyVecsFromDateIndex, + pub indexes_to_price_200d_sma_x0_8: LazyVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/market/range/compute.rs b/crates/brk_computer/src/market/range/compute.rs new file mode 100644 index 000000000..b160f7d3b --- /dev/null +++ b/crates/brk_computer/src/market/range/compute.rs @@ -0,0 +1,112 @@ +use brk_error::Result; +use brk_types::StoredF32; +use vecdb::Exit; + +use super::Vecs; +use crate::{price, utils::OptionExt, Indexes}; + +impl Vecs { + pub fn compute( + &mut self, + price: &price::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + let open = price.timeindexes_to_price_open.dateindex.u(); + let low = price.timeindexes_to_price_low.dateindex.u(); + let high = price.timeindexes_to_price_high.dateindex.u(); + + self.indexes_to_price_1w_min + .compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 7, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1w_max + .compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 7, exit)?; + Ok(()) + })?; + + self.indexes_to_price_2w_min + .compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 14, exit)?; + Ok(()) + })?; + + self.indexes_to_price_2w_max + .compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 14, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1m_min + .compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 30, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1m_max + .compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 30, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1y_min + .compute_all(starting_indexes, exit, |v| { + v.compute_min(starting_indexes.dateindex, low, 365, exit)?; + Ok(()) + })?; + + self.indexes_to_price_1y_max + .compute_all(starting_indexes, exit, |v| { + v.compute_max(starting_indexes.dateindex, high, 365, exit)?; + Ok(()) + })?; + + self.dateindex_to_price_true_range.compute_transform3( + starting_indexes.dateindex, + open, + high, + low, + |(i, open, high, low, ..)| { + let high_min_low = **high - **low; + let high_min_open = (**high - **open).abs(); + let low_min_open = (**low - **open).abs(); + (i, high_min_low.max(high_min_open).max(low_min_open).into()) + }, + exit, + )?; + + self.dateindex_to_price_true_range_2w_sum.compute_sum( + starting_indexes.dateindex, + &self.dateindex_to_price_true_range, + 14, + exit, + )?; + + self.indexes_to_price_2w_choppiness_index + .compute_all(starting_indexes, exit, |v| { + let n = 14; + let log10n = (n as f32).log10(); + v.compute_transform3( + starting_indexes.dateindex, + &self.dateindex_to_price_true_range_2w_sum, + self.indexes_to_price_2w_max.dateindex.u(), + self.indexes_to_price_2w_min.dateindex.u(), + |(i, tr_sum, max, min, ..)| { + ( + i, + StoredF32::from( + 100.0 * (*tr_sum / (*max - *min) as f32).log10() / log10n, + ), + ) + }, + exit, + )?; + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/market/range/import.rs b/crates/brk_computer/src/market/range/import.rs new file mode 100644 index 000000000..d584faec7 --- /dev/null +++ b/crates/brk_computer/src/market/range/import.rs @@ -0,0 +1,102 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, EagerVec, ImportableVec}; + +use super::Vecs; +use crate::{ + grouped::{ComputedVecsFromDateIndex, Source, VecBuilderOptions}, + indexes, +}; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + let v0 = Version::ZERO; + let v1 = Version::ONE; + let last = VecBuilderOptions::default().add_last(); + + Ok(Self { + indexes_to_price_1w_min: ComputedVecsFromDateIndex::forced_import( + db, + "price_1w_min", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_1w_max: ComputedVecsFromDateIndex::forced_import( + db, + "price_1w_max", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_2w_min: ComputedVecsFromDateIndex::forced_import( + db, + "price_2w_min", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_2w_max: ComputedVecsFromDateIndex::forced_import( + db, + "price_2w_max", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_1m_min: ComputedVecsFromDateIndex::forced_import( + db, + "price_1m_min", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_1m_max: ComputedVecsFromDateIndex::forced_import( + db, + "price_1m_max", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_1y_min: ComputedVecsFromDateIndex::forced_import( + db, + "price_1y_min", + Source::Compute, + version + v1, + indexes, + last, + )?, + indexes_to_price_1y_max: ComputedVecsFromDateIndex::forced_import( + db, + "price_1y_max", + Source::Compute, + version + v1, + indexes, + last, + )?, + dateindex_to_price_true_range: EagerVec::forced_import( + db, + "price_true_range", + version + v0, + )?, + dateindex_to_price_true_range_2w_sum: EagerVec::forced_import( + db, + "price_true_range_2w_sum", + version + v0, + )?, + indexes_to_price_2w_choppiness_index: ComputedVecsFromDateIndex::forced_import( + db, + "price_2w_choppiness_index", + Source::Compute, + version + v1, + indexes, + VecBuilderOptions::default().add_last(), + )?, + }) + } +} diff --git a/crates/brk_computer/src/market/range/mod.rs b/crates/brk_computer/src/market/range/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/market/range/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/market/range/vecs.rs b/crates/brk_computer/src/market/range/vecs.rs new file mode 100644 index 000000000..077f4391f --- /dev/null +++ b/crates/brk_computer/src/market/range/vecs.rs @@ -0,0 +1,21 @@ +use brk_traversable::Traversable; +use brk_types::{DateIndex, Dollars, StoredF32}; +use vecdb::{EagerVec, PcoVec}; + +use crate::grouped::ComputedVecsFromDateIndex; + +/// Price range and choppiness metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_price_1w_min: ComputedVecsFromDateIndex, + pub indexes_to_price_1w_max: ComputedVecsFromDateIndex, + pub indexes_to_price_2w_min: ComputedVecsFromDateIndex, + pub indexes_to_price_2w_max: ComputedVecsFromDateIndex, + pub indexes_to_price_1m_min: ComputedVecsFromDateIndex, + pub indexes_to_price_1m_max: ComputedVecsFromDateIndex, + pub indexes_to_price_1y_min: ComputedVecsFromDateIndex, + pub indexes_to_price_1y_max: ComputedVecsFromDateIndex, + pub dateindex_to_price_true_range: EagerVec>, + pub dateindex_to_price_true_range_2w_sum: EagerVec>, + pub indexes_to_price_2w_choppiness_index: ComputedVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/market/volatility/compute.rs b/crates/brk_computer/src/market/volatility/compute.rs new file mode 100644 index 000000000..3869b4ecb --- /dev/null +++ b/crates/brk_computer/src/market/volatility/compute.rs @@ -0,0 +1,38 @@ +use brk_error::Result; +use brk_types::{DateIndex, StoredF32}; +use vecdb::{CollectableVec, Exit}; + +use super::Vecs; +use crate::Indexes; + +impl Vecs { + pub fn compute( + &mut self, + starting_indexes: &Indexes, + exit: &Exit, + _1d_price_returns_dateindex: &V, + ) -> Result<()> + where + V: CollectableVec, + { + self.indexes_to_1d_returns_1w_sd.compute_all( + starting_indexes, + exit, + _1d_price_returns_dateindex, + )?; + + self.indexes_to_1d_returns_1m_sd.compute_all( + starting_indexes, + exit, + _1d_price_returns_dateindex, + )?; + + self.indexes_to_1d_returns_1y_sd.compute_all( + starting_indexes, + exit, + _1d_price_returns_dateindex, + )?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/market/volatility/import.rs b/crates/brk_computer/src/market/volatility/import.rs new file mode 100644 index 000000000..1ed5767fa --- /dev/null +++ b/crates/brk_computer/src/market/volatility/import.rs @@ -0,0 +1,101 @@ +use brk_error::Result; +use brk_types::Version; +use vecdb::{Database, IterableCloneableVec}; + +use super::Vecs; +use crate::{ + grouped::{ + ComputedStandardDeviationVecsFromDateIndex, LazyVecsFromDateIndex, Source, + StandardDeviationVecsOptions, StoredF32TimesSqrt7, StoredF32TimesSqrt30, + StoredF32TimesSqrt365, + }, + indexes, +}; + +impl Vecs { + pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + let v1 = Version::ONE; + let v2 = Version::TWO; + + let indexes_to_1d_returns_1w_sd = + ComputedStandardDeviationVecsFromDateIndex::forced_import( + db, + "1d_returns_1w_sd", + 7, + Source::Compute, + version + v1, + indexes, + StandardDeviationVecsOptions::default(), + None, + )?; + + let indexes_to_1d_returns_1m_sd = + ComputedStandardDeviationVecsFromDateIndex::forced_import( + db, + "1d_returns_1m_sd", + 30, + Source::Compute, + version + v1, + indexes, + StandardDeviationVecsOptions::default(), + None, + )?; + + let indexes_to_1d_returns_1y_sd = + ComputedStandardDeviationVecsFromDateIndex::forced_import( + db, + "1d_returns_1y_sd", + 365, + Source::Compute, + version + v1, + indexes, + StandardDeviationVecsOptions::default(), + None, + )?; + + let indexes_to_price_1w_volatility = + LazyVecsFromDateIndex::from_computed::( + "price_1w_volatility", + version + v2, + indexes_to_1d_returns_1w_sd + .sd + .dateindex + .as_ref() + .map(|v| v.boxed_clone()), + &indexes_to_1d_returns_1w_sd.sd, + ); + + let indexes_to_price_1m_volatility = + LazyVecsFromDateIndex::from_computed::( + "price_1m_volatility", + version + v2, + indexes_to_1d_returns_1m_sd + .sd + .dateindex + .as_ref() + .map(|v| v.boxed_clone()), + &indexes_to_1d_returns_1m_sd.sd, + ); + + let indexes_to_price_1y_volatility = + LazyVecsFromDateIndex::from_computed::( + "price_1y_volatility", + version + v2, + indexes_to_1d_returns_1y_sd + .sd + .dateindex + .as_ref() + .map(|v| v.boxed_clone()), + &indexes_to_1d_returns_1y_sd.sd, + ); + + Ok(Self { + indexes_to_1d_returns_1w_sd, + indexes_to_1d_returns_1m_sd, + indexes_to_1d_returns_1y_sd, + indexes_to_price_1w_volatility, + indexes_to_price_1m_volatility, + indexes_to_price_1y_volatility, + }) + } +} diff --git a/crates/brk_computer/src/market/volatility/mod.rs b/crates/brk_computer/src/market/volatility/mod.rs new file mode 100644 index 000000000..1136f9ebd --- /dev/null +++ b/crates/brk_computer/src/market/volatility/mod.rs @@ -0,0 +1,5 @@ +mod compute; +mod import; +mod vecs; + +pub use vecs::Vecs; diff --git a/crates/brk_computer/src/market/volatility/vecs.rs b/crates/brk_computer/src/market/volatility/vecs.rs new file mode 100644 index 000000000..cf1b9b20a --- /dev/null +++ b/crates/brk_computer/src/market/volatility/vecs.rs @@ -0,0 +1,15 @@ +use brk_traversable::Traversable; +use brk_types::StoredF32; + +use crate::grouped::{ComputedStandardDeviationVecsFromDateIndex, LazyVecsFromDateIndex}; + +/// Volatility and standard deviation metrics +#[derive(Clone, Traversable)] +pub struct Vecs { + pub indexes_to_1d_returns_1w_sd: ComputedStandardDeviationVecsFromDateIndex, + pub indexes_to_1d_returns_1m_sd: ComputedStandardDeviationVecsFromDateIndex, + pub indexes_to_1d_returns_1y_sd: ComputedStandardDeviationVecsFromDateIndex, + pub indexes_to_price_1w_volatility: LazyVecsFromDateIndex, + pub indexes_to_price_1m_volatility: LazyVecsFromDateIndex, + pub indexes_to_price_1y_volatility: LazyVecsFromDateIndex, +} diff --git a/crates/brk_computer/src/pools/mod.rs b/crates/brk_computer/src/pools/mod.rs index 230d95271..b31a128ff 100644 --- a/crates/brk_computer/src/pools/mod.rs +++ b/crates/brk_computer/src/pools/mod.rs @@ -119,7 +119,7 @@ impl Vecs { let mut height_to_first_txindex_iter = indexer.vecs.tx.height_to_first_txindex.iter()?; let mut txindex_to_first_txoutindex_iter = indexer.vecs.tx.txindex_to_first_txoutindex.iter()?; - let mut txindex_to_output_count_iter = indexes.txindex_to_output_count.iter(); + let mut txindex_to_output_count_iter = indexes.transaction.txindex_to_output_count.iter(); let mut txoutindex_to_outputtype_iter = indexer.vecs.txout.txoutindex_to_outputtype.iter()?; let mut txoutindex_to_typeindex_iter = indexer.vecs.txout.txoutindex_to_typeindex.iter()?; diff --git a/crates/brk_computer/src/pools/vecs.rs b/crates/brk_computer/src/pools/vecs.rs index a13e8be72..56b9b0f33 100644 --- a/crates/brk_computer/src/pools/vecs.rs +++ b/crates/brk_computer/src/pools/vecs.rs @@ -90,7 +90,7 @@ impl Vecs { .unwrap() .boxed_clone(), chain - .indexes_to_subsidy + .coinbase.indexes_to_subsidy .sats .height .as_ref() @@ -116,7 +116,7 @@ impl Vecs { .as_ref() .unwrap() .boxed_clone(), - chain.indexes_to_fee.sats.height.unwrap_sum().boxed_clone(), + chain.transaction.indexes_to_fee.sats.height.unwrap_sum().boxed_clone(), ); let indexes_to_fee = ComputedValueVecsFromHeight::forced_import( @@ -139,13 +139,13 @@ impl Vecs { .unwrap() .boxed_clone(), chain - .indexes_to_block_count + .block.indexes_to_block_count .height .as_ref() .unwrap() .boxed_clone(), &indexes_to_blocks_mined, - &chain.indexes_to_block_count, + &chain.block.indexes_to_block_count, ), indexes_to_1d_dominance: LazyVecsFrom2FromHeight::from_computed::( &suffix("1d_dominance"), @@ -156,31 +156,31 @@ impl Vecs { .unwrap() .boxed_clone(), chain - .indexes_to_block_count + .block.indexes_to_block_count .height .as_ref() .unwrap() .boxed_clone(), &indexes_to_blocks_mined, - &chain.indexes_to_block_count, + &chain.block.indexes_to_block_count, ), indexes_to_1w_dominance: LazyVecsFrom2FromDateIndex::from_computed::( &suffix("1w_dominance"), version, &indexes_to_1w_blocks_mined, - &chain.indexes_to_1w_block_count, + &chain.block.indexes_to_1w_block_count, ), indexes_to_1m_dominance: LazyVecsFrom2FromDateIndex::from_computed::( &suffix("1m_dominance"), version, &indexes_to_1m_blocks_mined, - &chain.indexes_to_1m_block_count, + &chain.block.indexes_to_1m_block_count, ), indexes_to_1y_dominance: LazyVecsFrom2FromDateIndex::from_computed::( &suffix("1y_dominance"), version, &indexes_to_1y_blocks_mined, - &chain.indexes_to_1y_block_count, + &chain.block.indexes_to_1y_block_count, ), slug, indexes_to_blocks_mined, diff --git a/crates/brk_computer/src/stateful/address/any_address_indexes.rs b/crates/brk_computer/src/stateful/address/indexes/any.rs similarity index 100% rename from crates/brk_computer/src/stateful/address/any_address_indexes.rs rename to crates/brk_computer/src/stateful/address/indexes/any.rs diff --git a/crates/brk_computer/src/stateful/address/indexes/mod.rs b/crates/brk_computer/src/stateful/address/indexes/mod.rs new file mode 100644 index 000000000..214330daf --- /dev/null +++ b/crates/brk_computer/src/stateful/address/indexes/mod.rs @@ -0,0 +1,3 @@ +mod any; + +pub use any::*; diff --git a/crates/brk_computer/src/stateful/address/mod.rs b/crates/brk_computer/src/stateful/address/mod.rs index bf02dd114..163f325c3 100644 --- a/crates/brk_computer/src/stateful/address/mod.rs +++ b/crates/brk_computer/src/stateful/address/mod.rs @@ -1,16 +1,12 @@ mod address_count; -mod any_address_indexes; mod data; -mod height_type_vec; -mod type_index_map; -mod type_vec; +mod indexes; +mod type_map; pub use address_count::{ AddressTypeToAddressCount, AddressTypeToHeightToAddressCount, AddressTypeToIndexesToAddressCount, }; -pub use any_address_indexes::AnyAddressIndexesVecs; pub use data::AddressesDataVecs; -pub use height_type_vec::HeightToAddressTypeToVec; -pub use type_index_map::AddressTypeToTypeIndexMap; -pub use type_vec::AddressTypeToVec; +pub use indexes::AnyAddressIndexesVecs; +pub use type_map::{AddressTypeToTypeIndexMap, AddressTypeToVec, HeightToAddressTypeToVec}; diff --git a/crates/brk_computer/src/stateful/address/height_type_vec.rs b/crates/brk_computer/src/stateful/address/type_map/height_vec.rs similarity index 95% rename from crates/brk_computer/src/stateful/address/height_type_vec.rs rename to crates/brk_computer/src/stateful/address/type_map/height_vec.rs index f03cf27da..bef053b4b 100644 --- a/crates/brk_computer/src/stateful/address/height_type_vec.rs +++ b/crates/brk_computer/src/stateful/address/type_map/height_vec.rs @@ -2,7 +2,7 @@ use brk_types::Height; use derive_deref::{Deref, DerefMut}; use rustc_hash::FxHashMap; -use super::type_vec::AddressTypeToVec; +use super::vec::AddressTypeToVec; /// Hashmap from Height to AddressTypeToVec. #[derive(Debug, Default, Deref, DerefMut)] diff --git a/crates/brk_computer/src/stateful/address/type_index_map.rs b/crates/brk_computer/src/stateful/address/type_map/index_map.rs similarity index 100% rename from crates/brk_computer/src/stateful/address/type_index_map.rs rename to crates/brk_computer/src/stateful/address/type_map/index_map.rs diff --git a/crates/brk_computer/src/stateful/address/type_map/mod.rs b/crates/brk_computer/src/stateful/address/type_map/mod.rs new file mode 100644 index 000000000..398fea565 --- /dev/null +++ b/crates/brk_computer/src/stateful/address/type_map/mod.rs @@ -0,0 +1,7 @@ +mod height_vec; +mod index_map; +mod vec; + +pub use height_vec::*; +pub use index_map::*; +pub use vec::*; diff --git a/crates/brk_computer/src/stateful/address/type_vec.rs b/crates/brk_computer/src/stateful/address/type_map/vec.rs similarity index 100% rename from crates/brk_computer/src/stateful/address/type_vec.rs rename to crates/brk_computer/src/stateful/address/type_map/vec.rs diff --git a/crates/brk_computer/src/stateful/block/cache.rs b/crates/brk_computer/src/stateful/block/cache/address.rs similarity index 91% rename from crates/brk_computer/src/stateful/block/cache.rs rename to crates/brk_computer/src/stateful/block/cache/address.rs index d3fac3737..ff3a97a4c 100644 --- a/crates/brk_computer/src/stateful/block/cache.rs +++ b/crates/brk_computer/src/stateful/block/cache/address.rs @@ -2,12 +2,14 @@ use brk_grouper::ByAddressType; use brk_types::{AnyAddressDataIndexEnum, LoadedAddressData, OutputType, TypeIndex}; use vecdb::GenericStoredVec; -use super::{ - super::{ - address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs}, - compute::VecsReaders, - }, - AddressLookup, EmptyAddressDataWithSource, LoadedAddressDataWithSource, TxIndexVec, +use crate::stateful::{ + address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs}, + compute::VecsReaders, +}; + +use super::lookup::AddressLookup; +use super::super::cohort::{ + update_tx_counts, EmptyAddressDataWithSource, LoadedAddressDataWithSource, TxIndexVec, WithAddressDataSource, }; @@ -62,7 +64,7 @@ impl AddressCache { /// Update transaction counts for addresses. pub fn update_tx_counts(&mut self, txindex_vecs: AddressTypeToTypeIndexMap) { - super::update_tx_counts(&mut self.loaded, &mut self.empty, txindex_vecs); + update_tx_counts(&mut self.loaded, &mut self.empty, txindex_vecs); } /// Take the cache contents for flushing, leaving empty caches. diff --git a/crates/brk_computer/src/stateful/block/lookup.rs b/crates/brk_computer/src/stateful/block/cache/lookup.rs similarity index 97% rename from crates/brk_computer/src/stateful/block/lookup.rs rename to crates/brk_computer/src/stateful/block/cache/lookup.rs index cc8a3409f..00f825193 100644 --- a/crates/brk_computer/src/stateful/block/lookup.rs +++ b/crates/brk_computer/src/stateful/block/cache/lookup.rs @@ -1,7 +1,8 @@ use brk_types::{LoadedAddressData, OutputType, TypeIndex}; -use super::{ - super::address::AddressTypeToTypeIndexMap, +use crate::stateful::address::AddressTypeToTypeIndexMap; + +use super::super::cohort::{ EmptyAddressDataWithSource, LoadedAddressDataWithSource, WithAddressDataSource, }; diff --git a/crates/brk_computer/src/stateful/block/cache/mod.rs b/crates/brk_computer/src/stateful/block/cache/mod.rs new file mode 100644 index 000000000..e567f878a --- /dev/null +++ b/crates/brk_computer/src/stateful/block/cache/mod.rs @@ -0,0 +1,5 @@ +mod address; +mod lookup; + +pub use address::*; +pub use lookup::*; diff --git a/crates/brk_computer/src/stateful/block/address_updates.rs b/crates/brk_computer/src/stateful/block/cohort/address_updates.rs similarity index 98% rename from crates/brk_computer/src/stateful/block/address_updates.rs rename to crates/brk_computer/src/stateful/block/cohort/address_updates.rs index b1f779e1f..bea90d700 100644 --- a/crates/brk_computer/src/stateful/block/address_updates.rs +++ b/crates/brk_computer/src/stateful/block/cohort/address_updates.rs @@ -4,9 +4,10 @@ use brk_types::{ OutputType, TypeIndex, }; -use super::{EmptyAddressDataWithSource, LoadedAddressDataWithSource}; use crate::stateful::{AddressTypeToTypeIndexMap, AddressesDataVecs}; +use super::with_source::{EmptyAddressDataWithSource, LoadedAddressDataWithSource}; + /// Process loaded address data updates. /// /// Handles: diff --git a/crates/brk_computer/src/stateful/block/cohort/mod.rs b/crates/brk_computer/src/stateful/block/cohort/mod.rs new file mode 100644 index 000000000..41eb838ce --- /dev/null +++ b/crates/brk_computer/src/stateful/block/cohort/mod.rs @@ -0,0 +1,11 @@ +mod address_updates; +mod received; +mod sent; +mod tx_counts; +mod with_source; + +pub use address_updates::*; +pub use received::*; +pub use sent::*; +pub use tx_counts::*; +pub use with_source::*; diff --git a/crates/brk_computer/src/stateful/block/received.rs b/crates/brk_computer/src/stateful/block/cohort/received.rs similarity index 97% rename from crates/brk_computer/src/stateful/block/received.rs rename to crates/brk_computer/src/stateful/block/cohort/received.rs index 1db5cc935..baabb5a06 100644 --- a/crates/brk_computer/src/stateful/block/received.rs +++ b/crates/brk_computer/src/stateful/block/cohort/received.rs @@ -2,10 +2,9 @@ use brk_grouper::{AmountBucket, ByAddressType}; use brk_types::{Dollars, Sats, TypeIndex}; use rustc_hash::FxHashMap; -use super::{ - super::{address::AddressTypeToVec, cohorts::AddressCohorts}, - lookup::{AddressLookup, TrackingStatus}, -}; +use crate::stateful::{address::AddressTypeToVec, cohorts::AddressCohorts}; + +use super::super::cache::{AddressLookup, TrackingStatus}; pub fn process_received( received_data: AddressTypeToVec<(TypeIndex, Sats)>, diff --git a/crates/brk_computer/src/stateful/block/sent.rs b/crates/brk_computer/src/stateful/block/cohort/sent.rs similarity index 97% rename from crates/brk_computer/src/stateful/block/sent.rs rename to crates/brk_computer/src/stateful/block/cohort/sent.rs index 313439ed6..284e83932 100644 --- a/crates/brk_computer/src/stateful/block/sent.rs +++ b/crates/brk_computer/src/stateful/block/cohort/sent.rs @@ -3,10 +3,9 @@ use brk_grouper::{AmountBucket, ByAddressType}; use brk_types::{CheckedSub, Dollars, Height, Sats, Timestamp, TypeIndex}; use vecdb::{VecIndex, unlikely}; -use super::{ - super::{address::HeightToAddressTypeToVec, cohorts::AddressCohorts}, - lookup::AddressLookup, -}; +use crate::stateful::{address::HeightToAddressTypeToVec, cohorts::AddressCohorts}; + +use super::super::cache::AddressLookup; /// Process sent outputs for address cohorts. /// diff --git a/crates/brk_computer/src/stateful/block/tx_counts.rs b/crates/brk_computer/src/stateful/block/cohort/tx_counts.rs similarity index 94% rename from crates/brk_computer/src/stateful/block/tx_counts.rs rename to crates/brk_computer/src/stateful/block/cohort/tx_counts.rs index d7fe507c2..0656c2c9c 100644 --- a/crates/brk_computer/src/stateful/block/tx_counts.rs +++ b/crates/brk_computer/src/stateful/block/cohort/tx_counts.rs @@ -1,6 +1,6 @@ use crate::stateful::address::AddressTypeToTypeIndexMap; -use super::{EmptyAddressDataWithSource, LoadedAddressDataWithSource, TxIndexVec}; +use super::with_source::{EmptyAddressDataWithSource, LoadedAddressDataWithSource, TxIndexVec}; /// Update tx_count for addresses based on unique transactions they participated in. /// diff --git a/crates/brk_computer/src/stateful/block/with_source.rs b/crates/brk_computer/src/stateful/block/cohort/with_source.rs similarity index 100% rename from crates/brk_computer/src/stateful/block/with_source.rs rename to crates/brk_computer/src/stateful/block/cohort/with_source.rs diff --git a/crates/brk_computer/src/stateful/block/mod.rs b/crates/brk_computer/src/stateful/block/mod.rs index 00ee345ce..d5c7e483a 100644 --- a/crates/brk_computer/src/stateful/block/mod.rs +++ b/crates/brk_computer/src/stateful/block/mod.rs @@ -1,19 +1,7 @@ -mod address_updates; mod cache; -mod inputs; -mod lookup; -mod outputs; -mod received; -mod sent; -mod tx_counts; -mod with_source; +mod cohort; +mod utxo; -pub use address_updates::*; pub use cache::*; -pub use inputs::*; -pub use lookup::*; -pub use outputs::*; -pub use received::*; -pub use sent::*; -pub use tx_counts::*; -pub use with_source::*; +pub use cohort::*; +pub use utxo::*; diff --git a/crates/brk_computer/src/stateful/block/inputs.rs b/crates/brk_computer/src/stateful/block/utxo/inputs.rs similarity index 96% rename from crates/brk_computer/src/stateful/block/inputs.rs rename to crates/brk_computer/src/stateful/block/utxo/inputs.rs index 712dc7427..739e78a52 100644 --- a/crates/brk_computer/src/stateful/block/inputs.rs +++ b/crates/brk_computer/src/stateful/block/utxo/inputs.rs @@ -9,9 +9,11 @@ use crate::stateful::{ state::Transacted, }; -use super::{ - super::address::HeightToAddressTypeToVec, AddressCache, LoadedAddressDataWithSource, - TxIndexVec, load_uncached_address_data, +use crate::stateful::address::HeightToAddressTypeToVec; + +use super::super::{ + cache::{AddressCache, load_uncached_address_data}, + cohort::{LoadedAddressDataWithSource, TxIndexVec}, }; /// Result of processing inputs for a block. diff --git a/crates/brk_computer/src/stateful/block/utxo/mod.rs b/crates/brk_computer/src/stateful/block/utxo/mod.rs new file mode 100644 index 000000000..f2ec0636f --- /dev/null +++ b/crates/brk_computer/src/stateful/block/utxo/mod.rs @@ -0,0 +1,5 @@ +mod inputs; +mod outputs; + +pub use inputs::*; +pub use outputs::*; diff --git a/crates/brk_computer/src/stateful/block/outputs.rs b/crates/brk_computer/src/stateful/block/utxo/outputs.rs similarity index 93% rename from crates/brk_computer/src/stateful/block/outputs.rs rename to crates/brk_computer/src/stateful/block/utxo/outputs.rs index 781c2c674..d229fc7cd 100644 --- a/crates/brk_computer/src/stateful/block/outputs.rs +++ b/crates/brk_computer/src/stateful/block/utxo/outputs.rs @@ -2,14 +2,14 @@ use brk_grouper::ByAddressType; use brk_types::{Sats, TxIndex, TypeIndex}; use crate::stateful::{ - address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs}, + address::{AddressTypeToTypeIndexMap, AddressTypeToVec, AddressesDataVecs, AnyAddressIndexesVecs}, compute::{TxOutData, VecsReaders}, state::Transacted, }; -use super::{ - super::address::AddressTypeToVec, - load_uncached_address_data, AddressCache, LoadedAddressDataWithSource, TxIndexVec, +use super::super::{ + cache::{load_uncached_address_data, AddressCache}, + cohort::{LoadedAddressDataWithSource, TxIndexVec}, }; /// Result of processing outputs for a block. diff --git a/crates/brk_computer/src/stateful/cohorts/address_cohorts.rs b/crates/brk_computer/src/stateful/cohorts/address/groups.rs similarity index 98% rename from crates/brk_computer/src/stateful/cohorts/address_cohorts.rs rename to crates/brk_computer/src/stateful/cohorts/address/groups.rs index 0a3c9e6f5..ec6ff6f4d 100644 --- a/crates/brk_computer/src/stateful/cohorts/address_cohorts.rs +++ b/crates/brk_computer/src/stateful/cohorts/address/groups.rs @@ -12,7 +12,12 @@ use vecdb::{AnyStoredVec, Database, Exit, IterableVec}; use crate::{Indexes, indexes, price, stateful::DynCohortVecs}; -use super::{super::metrics::SupplyMetrics, AddressCohortVecs, CohortVecs}; +use crate::stateful::metrics::SupplyMetrics; + +use super::{ + super::traits::CohortVecs, + vecs::AddressCohortVecs, +}; const VERSION: Version = Version::new(0); diff --git a/crates/brk_computer/src/stateful/cohorts/address/mod.rs b/crates/brk_computer/src/stateful/cohorts/address/mod.rs new file mode 100644 index 000000000..726cbb034 --- /dev/null +++ b/crates/brk_computer/src/stateful/cohorts/address/mod.rs @@ -0,0 +1,4 @@ +mod groups; +mod vecs; + +pub use groups::*; diff --git a/crates/brk_computer/src/stateful/cohorts/address.rs b/crates/brk_computer/src/stateful/cohorts/address/vecs.rs similarity index 98% rename from crates/brk_computer/src/stateful/cohorts/address.rs rename to crates/brk_computer/src/stateful/cohorts/address/vecs.rs index 2eee9c8fa..71da5634e 100644 --- a/crates/brk_computer/src/stateful/cohorts/address.rs +++ b/crates/brk_computer/src/stateful/cohorts/address/vecs.rs @@ -17,10 +17,9 @@ use crate::{ stateful::state::AddressCohortState, }; -use super::{ - super::metrics::{CohortMetrics, ImportConfig, SupplyMetrics}, - traits::{CohortVecs, DynCohortVecs}, -}; +use crate::stateful::metrics::{CohortMetrics, ImportConfig, SupplyMetrics}; + +use super::super::traits::{CohortVecs, DynCohortVecs}; const VERSION: Version = Version::ZERO; diff --git a/crates/brk_computer/src/stateful/cohorts/mod.rs b/crates/brk_computer/src/stateful/cohorts/mod.rs index 1be24a28e..5241b3261 100644 --- a/crates/brk_computer/src/stateful/cohorts/mod.rs +++ b/crates/brk_computer/src/stateful/cohorts/mod.rs @@ -1,11 +1,7 @@ mod address; -mod address_cohorts; mod traits; mod utxo; -mod utxo_cohorts; -pub use address::AddressCohortVecs; -pub use address_cohorts::AddressCohorts; -pub use traits::{CohortVecs, DynCohortVecs}; -pub use utxo::UTXOCohortVecs; -pub use utxo_cohorts::UTXOCohorts; +pub use address::AddressCohorts; +pub use traits::DynCohortVecs; +pub use utxo::UTXOCohorts; diff --git a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/mod.rs b/crates/brk_computer/src/stateful/cohorts/utxo/groups.rs similarity index 99% rename from crates/brk_computer/src/stateful/cohorts/utxo_cohorts/mod.rs rename to crates/brk_computer/src/stateful/cohorts/utxo/groups.rs index 0a61a39a6..51a8871b3 100644 --- a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/mod.rs +++ b/crates/brk_computer/src/stateful/cohorts/utxo/groups.rs @@ -1,7 +1,3 @@ -mod receive; -mod send; -mod tick_tock; - use std::path::Path; use brk_error::Result; @@ -22,7 +18,10 @@ use crate::{ stateful::DynCohortVecs, }; -use super::{CohortVecs, UTXOCohortVecs}; +use super::{ + super::traits::CohortVecs, + vecs::UTXOCohortVecs, +}; const VERSION: Version = Version::new(0); diff --git a/crates/brk_computer/src/stateful/cohorts/utxo/mod.rs b/crates/brk_computer/src/stateful/cohorts/utxo/mod.rs new file mode 100644 index 000000000..ba23c4f16 --- /dev/null +++ b/crates/brk_computer/src/stateful/cohorts/utxo/mod.rs @@ -0,0 +1,7 @@ +mod groups; +mod receive; +mod send; +mod tick_tock; +mod vecs; + +pub use groups::*; diff --git a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/receive.rs b/crates/brk_computer/src/stateful/cohorts/utxo/receive.rs similarity index 98% rename from crates/brk_computer/src/stateful/cohorts/utxo_cohorts/receive.rs rename to crates/brk_computer/src/stateful/cohorts/utxo/receive.rs index 7a115bf78..048714e58 100644 --- a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/receive.rs +++ b/crates/brk_computer/src/stateful/cohorts/utxo/receive.rs @@ -2,7 +2,7 @@ use brk_types::{Dollars, Height, Timestamp}; use crate::stateful::state::Transacted; -use super::UTXOCohorts; +use super::groups::UTXOCohorts; impl UTXOCohorts { /// Process received outputs for this block. diff --git a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/send.rs b/crates/brk_computer/src/stateful/cohorts/utxo/send.rs similarity index 99% rename from crates/brk_computer/src/stateful/cohorts/utxo_cohorts/send.rs rename to crates/brk_computer/src/stateful/cohorts/utxo/send.rs index ffd7fb72b..70c59110f 100644 --- a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/send.rs +++ b/crates/brk_computer/src/stateful/cohorts/utxo/send.rs @@ -7,7 +7,7 @@ use crate::{ utils::OptionExt, }; -use super::UTXOCohorts; +use super::groups::UTXOCohorts; impl UTXOCohorts { /// Process spent inputs for this block. diff --git a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/tick_tock.rs b/crates/brk_computer/src/stateful/cohorts/utxo/tick_tock.rs similarity index 99% rename from crates/brk_computer/src/stateful/cohorts/utxo_cohorts/tick_tock.rs rename to crates/brk_computer/src/stateful/cohorts/utxo/tick_tock.rs index 32f5bf765..d73f4a62b 100644 --- a/crates/brk_computer/src/stateful/cohorts/utxo_cohorts/tick_tock.rs +++ b/crates/brk_computer/src/stateful/cohorts/utxo/tick_tock.rs @@ -3,7 +3,7 @@ use brk_types::{ONE_DAY_IN_SEC, Timestamp}; use crate::stateful::state::BlockState; -use super::UTXOCohorts; +use super::groups::UTXOCohorts; impl UTXOCohorts { /// Handle age transitions when processing a new block. diff --git a/crates/brk_computer/src/stateful/cohorts/utxo.rs b/crates/brk_computer/src/stateful/cohorts/utxo/vecs.rs similarity index 97% rename from crates/brk_computer/src/stateful/cohorts/utxo.rs rename to crates/brk_computer/src/stateful/cohorts/utxo/vecs.rs index 2f068102f..48992cb1b 100644 --- a/crates/brk_computer/src/stateful/cohorts/utxo.rs +++ b/crates/brk_computer/src/stateful/cohorts/utxo/vecs.rs @@ -7,12 +7,11 @@ use brk_types::{Bitcoin, DateIndex, Dollars, Height, Version}; use rayon::prelude::*; use vecdb::{AnyStoredVec, Database, Exit, IterableVec}; -use crate::{ - Indexes, indexes, price, - stateful::{CohortVecs, DynCohortVecs, state::UTXOCohortState}, -}; +use crate::{Indexes, indexes, price, stateful::state::UTXOCohortState}; -use super::super::metrics::{CohortMetrics, ImportConfig, SupplyMetrics}; +use crate::stateful::metrics::{CohortMetrics, ImportConfig, SupplyMetrics}; + +use super::super::traits::{CohortVecs, DynCohortVecs}; /// UTXO cohort with metrics and optional runtime state. #[derive(Clone, Traversable)] diff --git a/crates/brk_computer/src/stateful/compute/block_loop.rs b/crates/brk_computer/src/stateful/compute/block_loop.rs index 43775311d..caa801332 100644 --- a/crates/brk_computer/src/stateful/compute/block_loop.rs +++ b/crates/brk_computer/src/stateful/compute/block_loop.rs @@ -62,23 +62,23 @@ pub fn process_blocks( let height_to_first_txinindex = &indexer.vecs.txin.height_to_first_txinindex; // From chain (via .height.u() or .height.unwrap_sum() patterns): - let height_to_tx_count = chain.indexes_to_tx_count.height.u(); - let height_to_output_count = chain.indexes_to_output_count.height.unwrap_sum(); - let height_to_input_count = chain.indexes_to_input_count.height.unwrap_sum(); + let height_to_tx_count = chain.transaction.indexes_to_tx_count.height.u(); + let height_to_output_count = chain.transaction.indexes_to_output_count.height.unwrap_sum(); + let height_to_input_count = chain.transaction.indexes_to_input_count.height.unwrap_sum(); let height_to_unclaimed_rewards = chain - .indexes_to_unclaimed_rewards + .coinbase.indexes_to_unclaimed_rewards .sats .height .as_ref() .unwrap(); // From indexes: - let height_to_timestamp = &indexes.height_to_timestamp_fixed; - let height_to_date = &indexes.height_to_date_fixed; - let dateindex_to_first_height = &indexes.dateindex_to_first_height; - let dateindex_to_height_count = &indexes.dateindex_to_height_count; - let txindex_to_output_count = &indexes.txindex_to_output_count; - let txindex_to_input_count = &indexes.txindex_to_input_count; + let height_to_timestamp = &indexes.block.height_to_timestamp_fixed; + let height_to_date = &indexes.block.height_to_date_fixed; + let dateindex_to_first_height = &indexes.time.dateindex_to_first_height; + let dateindex_to_height_count = &indexes.time.dateindex_to_height_count; + let txindex_to_output_count = &indexes.transaction.txindex_to_output_count; + let txindex_to_input_count = &indexes.transaction.txindex_to_input_count; // From price (optional): let height_to_price = price.map(|p| &p.chainindexes_to_price_close.height); diff --git a/crates/brk_computer/src/stateful/compute/context.rs b/crates/brk_computer/src/stateful/compute/context.rs index 0666d7335..b079e506a 100644 --- a/crates/brk_computer/src/stateful/compute/context.rs +++ b/crates/brk_computer/src/stateful/compute/context.rs @@ -27,7 +27,7 @@ impl ComputeContext { price: Option<&price::Vecs>, ) -> Self { let height_to_timestamp: Vec = - indexes.height_to_timestamp_fixed.into_iter().collect(); + indexes.block.height_to_timestamp_fixed.into_iter().collect(); let height_to_price: Option> = price .map(|p| &p.chainindexes_to_price_close.height) diff --git a/crates/brk_computer/src/stateful/metrics/mod.rs b/crates/brk_computer/src/stateful/metrics/mod.rs index 619ba4fa4..df4539c2d 100644 --- a/crates/brk_computer/src/stateful/metrics/mod.rs +++ b/crates/brk_computer/src/stateful/metrics/mod.rs @@ -1,16 +1,14 @@ mod activity; mod config; -mod price_paid; +mod price; mod realized; -mod relative; mod supply; mod unrealized; pub use activity::ActivityMetrics; pub use config::ImportConfig; -pub use price_paid::PricePaidMetrics; +pub use price::{PricePaidMetrics, RelativeMetrics}; pub use realized::RealizedMetrics; -pub use relative::RelativeMetrics; pub use supply::SupplyMetrics; pub use unrealized::UnrealizedMetrics; @@ -21,7 +19,7 @@ use brk_types::{Bitcoin, DateIndex, Dollars, Height, Version}; use rayon::prelude::*; use vecdb::{AnyStoredVec, Exit, IterableVec}; -use crate::{Indexes, indexes, price, stateful::state::CohortState}; +use crate::{Indexes, indexes, price as price_vecs, stateful::state::CohortState}; /// All metrics for a cohort, organized by category. #[derive(Clone, Traversable)] @@ -262,7 +260,7 @@ impl CohortMetrics { pub fn compute_rest_part1( &mut self, indexes: &indexes::Vecs, - price: Option<&price::Vecs>, + price: Option<&price_vecs::Vecs>, starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { @@ -291,7 +289,7 @@ impl CohortMetrics { pub fn compute_rest_part2( &mut self, indexes: &indexes::Vecs, - price: Option<&price::Vecs>, + price: Option<&price_vecs::Vecs>, starting_indexes: &Indexes, height_to_supply: &impl IterableVec, height_to_market_cap: Option<&impl IterableVec>, diff --git a/crates/brk_computer/src/stateful/metrics/price/mod.rs b/crates/brk_computer/src/stateful/metrics/price/mod.rs new file mode 100644 index 000000000..f7f06ebc7 --- /dev/null +++ b/crates/brk_computer/src/stateful/metrics/price/mod.rs @@ -0,0 +1,5 @@ +mod paid; +mod relative; + +pub use paid::*; +pub use relative::*; diff --git a/crates/brk_computer/src/stateful/metrics/price_paid.rs b/crates/brk_computer/src/stateful/metrics/price/paid.rs similarity index 99% rename from crates/brk_computer/src/stateful/metrics/price_paid.rs rename to crates/brk_computer/src/stateful/metrics/price/paid.rs index 2f4d1310a..bdeb53d95 100644 --- a/crates/brk_computer/src/stateful/metrics/price_paid.rs +++ b/crates/brk_computer/src/stateful/metrics/price/paid.rs @@ -12,7 +12,7 @@ use crate::{ stateful::state::CohortState, }; -use super::ImportConfig; +use super::super::ImportConfig; /// Price paid metrics. #[derive(Clone, Traversable)] diff --git a/crates/brk_computer/src/stateful/metrics/relative.rs b/crates/brk_computer/src/stateful/metrics/price/relative.rs similarity index 99% rename from crates/brk_computer/src/stateful/metrics/relative.rs rename to crates/brk_computer/src/stateful/metrics/price/relative.rs index 4d90f6bd0..8a07bfe0c 100644 --- a/crates/brk_computer/src/stateful/metrics/relative.rs +++ b/crates/brk_computer/src/stateful/metrics/price/relative.rs @@ -8,7 +8,7 @@ use crate::grouped::{ PercentageDollarsF32, PercentageSatsF64, Ratio32, }; -use super::{ImportConfig, SupplyMetrics, UnrealizedMetrics}; +use super::super::{ImportConfig, SupplyMetrics, UnrealizedMetrics}; /// Relative metrics comparing cohort values to global values. /// All `rel_to_` vecs are lazy - computed on-demand from their sources. diff --git a/crates/brk_computer/src/stateful/metrics/supply.rs b/crates/brk_computer/src/stateful/metrics/supply.rs index 249ca0229..444ce7945 100644 --- a/crates/brk_computer/src/stateful/metrics/supply.rs +++ b/crates/brk_computer/src/stateful/metrics/supply.rs @@ -191,11 +191,11 @@ impl SupplyMetrics { self.indexes_to_supply .compute_all(price, starting_indexes, exit, |v| { let mut dateindex_to_height_count_iter = - indexes.dateindex_to_height_count.into_iter(); + indexes.time.dateindex_to_height_count.into_iter(); let mut height_to_supply_iter = self.height_to_supply.into_iter(); v.compute_transform( starting_indexes.dateindex, - &indexes.dateindex_to_first_height, + &indexes.time.dateindex_to_first_height, |(i, height, ..)| { let count = dateindex_to_height_count_iter.get_unwrap(i); if count == StoredU64::default() { diff --git a/crates/brk_computer/src/stateful/mod.rs b/crates/brk_computer/src/stateful/mod.rs index 1bed9bd15..985f7e764 100644 --- a/crates/brk_computer/src/stateful/mod.rs +++ b/crates/brk_computer/src/stateful/mod.rs @@ -13,4 +13,4 @@ pub use vecs::Vecs; pub const DB_NAME: &str = "stateful"; pub use address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs}; -pub use cohorts::{AddressCohorts, CohortVecs, DynCohortVecs, UTXOCohorts}; +pub use cohorts::{AddressCohorts, DynCohortVecs, UTXOCohorts}; diff --git a/crates/brk_computer/src/stateful/state/address_cohort.rs b/crates/brk_computer/src/stateful/state/cohort/address.rs similarity index 98% rename from crates/brk_computer/src/stateful/state/address_cohort.rs rename to crates/brk_computer/src/stateful/state/cohort/address.rs index d57c20868..c191e7da3 100644 --- a/crates/brk_computer/src/stateful/state/address_cohort.rs +++ b/crates/brk_computer/src/stateful/state/cohort/address.rs @@ -4,9 +4,10 @@ use brk_error::Result; use brk_types::{Dollars, Height, LoadedAddressData, Sats, SupplyState}; use vecdb::unlikely; -use crate::stateful::state::RealizedState; - -use super::CohortState; +use super::{ + super::cost_basis::RealizedState, + base::CohortState, +}; #[derive(Clone)] pub struct AddressCohortState { diff --git a/crates/brk_computer/src/stateful/state/cohort.rs b/crates/brk_computer/src/stateful/state/cohort/base.rs similarity index 99% rename from crates/brk_computer/src/stateful/state/cohort.rs rename to crates/brk_computer/src/stateful/state/cohort/base.rs index 0538d6b86..6a5af7e9d 100644 --- a/crates/brk_computer/src/stateful/state/cohort.rs +++ b/crates/brk_computer/src/stateful/state/cohort/base.rs @@ -5,7 +5,9 @@ use brk_types::{Dollars, Height, Sats, SupplyState}; use crate::grouped::PERCENTILES_LEN; -use super::{CachedUnrealizedState, PriceToAmount, RealizedState, UnrealizedState}; +use super::super::cost_basis::{ + CachedUnrealizedState, PriceToAmount, RealizedState, UnrealizedState, +}; /// State tracked for each cohort during computation. #[derive(Clone)] diff --git a/crates/brk_computer/src/stateful/state/cohort/mod.rs b/crates/brk_computer/src/stateful/state/cohort/mod.rs new file mode 100644 index 000000000..71b673e86 --- /dev/null +++ b/crates/brk_computer/src/stateful/state/cohort/mod.rs @@ -0,0 +1,7 @@ +mod address; +mod base; +mod utxo; + +pub use address::*; +pub use base::*; +pub use utxo::*; diff --git a/crates/brk_computer/src/stateful/state/utxo_cohort.rs b/crates/brk_computer/src/stateful/state/cohort/utxo.rs similarity index 91% rename from crates/brk_computer/src/stateful/state/utxo_cohort.rs rename to crates/brk_computer/src/stateful/state/cohort/utxo.rs index a301f272b..4c564a9f6 100644 --- a/crates/brk_computer/src/stateful/state/utxo_cohort.rs +++ b/crates/brk_computer/src/stateful/state/cohort/utxo.rs @@ -4,7 +4,10 @@ use brk_error::Result; use brk_types::{Sats, SupplyState}; use derive_deref::{Deref, DerefMut}; -use super::{CohortState, RealizedState}; +use super::{ + super::cost_basis::RealizedState, + base::CohortState, +}; #[derive(Clone, Deref, DerefMut)] pub struct UTXOCohortState(CohortState); diff --git a/crates/brk_computer/src/stateful/state/cost_basis/mod.rs b/crates/brk_computer/src/stateful/state/cost_basis/mod.rs new file mode 100644 index 000000000..ac6add388 --- /dev/null +++ b/crates/brk_computer/src/stateful/state/cost_basis/mod.rs @@ -0,0 +1,7 @@ +mod price_to_amount; +mod realized; +mod unrealized; + +pub use price_to_amount::*; +pub use realized::*; +pub use unrealized::*; diff --git a/crates/brk_computer/src/stateful/state/price_to_amount.rs b/crates/brk_computer/src/stateful/state/cost_basis/price_to_amount.rs similarity index 100% rename from crates/brk_computer/src/stateful/state/price_to_amount.rs rename to crates/brk_computer/src/stateful/state/cost_basis/price_to_amount.rs diff --git a/crates/brk_computer/src/stateful/state/realized.rs b/crates/brk_computer/src/stateful/state/cost_basis/realized.rs similarity index 100% rename from crates/brk_computer/src/stateful/state/realized.rs rename to crates/brk_computer/src/stateful/state/cost_basis/realized.rs diff --git a/crates/brk_computer/src/stateful/state/unrealized.rs b/crates/brk_computer/src/stateful/state/cost_basis/unrealized.rs similarity index 99% rename from crates/brk_computer/src/stateful/state/unrealized.rs rename to crates/brk_computer/src/stateful/state/cost_basis/unrealized.rs index e60a033dd..e391dbf85 100644 --- a/crates/brk_computer/src/stateful/state/unrealized.rs +++ b/crates/brk_computer/src/stateful/state/cost_basis/unrealized.rs @@ -3,7 +3,7 @@ use std::ops::Bound; use brk_types::{Dollars, Sats}; use vecdb::CheckedSub; -use super::PriceToAmount; +use super::price_to_amount::PriceToAmount; #[derive(Debug, Default, Clone)] pub struct UnrealizedState { diff --git a/crates/brk_computer/src/stateful/state/mod.rs b/crates/brk_computer/src/stateful/state/mod.rs index 716bf12a1..f058bfdf1 100644 --- a/crates/brk_computer/src/stateful/state/mod.rs +++ b/crates/brk_computer/src/stateful/state/mod.rs @@ -1,17 +1,9 @@ -mod address_cohort; mod block; mod cohort; -mod price_to_amount; -mod realized; +mod cost_basis; mod transacted; -mod unrealized; -mod utxo_cohort; -pub use address_cohort::*; pub use block::*; pub use cohort::*; -pub use price_to_amount::*; -pub use realized::*; +pub use cost_basis::*; pub use transacted::*; -pub use unrealized::*; -pub use utxo_cohort::*; diff --git a/crates/brk_computer/src/stateful/vecs.rs b/crates/brk_computer/src/stateful/vecs.rs index 79622909f..30bec6365 100644 --- a/crates/brk_computer/src/stateful/vecs.rs +++ b/crates/brk_computer/src/stateful/vecs.rs @@ -339,7 +339,7 @@ impl Vecs { (Height::ZERO, vec![]) } else { // Recover chain_state from stored values - let height_to_timestamp = &indexes.height_to_timestamp_fixed; + let height_to_timestamp = &indexes.block.height_to_timestamp_fixed; let height_to_price = price.map(|p| &p.chainindexes_to_price_close.height); let mut height_to_timestamp_iter = height_to_timestamp.into_iter(); diff --git a/crates/brk_query/src/impl/block/info.rs b/crates/brk_query/src/impl/block/info.rs index 84b7a1d20..3290df2fb 100644 --- a/crates/brk_query/src/impl/block/info.rs +++ b/crates/brk_query/src/impl/block/info.rs @@ -94,7 +94,7 @@ impl Query { .height_to_first_txindex .read_once(height.incremented())? } else { - TxIndex::from(computer.indexes.txindex_to_txindex.len()) + TxIndex::from(computer.indexes.transaction.txindex_to_txindex.len()) }; Ok((next_first_txindex.to_usize() - first_txindex.to_usize()) as u32) diff --git a/crates/brk_query/src/impl/block/timestamp.rs b/crates/brk_query/src/impl/block/timestamp.rs index a9d8f7d23..eea27802b 100644 --- a/crates/brk_query/src/impl/block/timestamp.rs +++ b/crates/brk_query/src/impl/block/timestamp.rs @@ -24,6 +24,7 @@ impl Query { // Get first height of the target date let first_height_of_day = computer .indexes + .time .dateindex_to_first_height .read_once(dateindex) .unwrap_or(Height::from(0usize)); diff --git a/crates/brk_query/src/impl/mining/block_fees.rs b/crates/brk_query/src/impl/mining/block_fees.rs index f38cf9788..7e27a68a4 100644 --- a/crates/brk_query/src/impl/mining/block_fees.rs +++ b/crates/brk_query/src/impl/mining/block_fees.rs @@ -17,6 +17,7 @@ impl Query { let mut fees = computer .chain + .transaction .indexes_to_fee .sats .dateindex diff --git a/crates/brk_query/src/impl/mining/block_rewards.rs b/crates/brk_query/src/impl/mining/block_rewards.rs index 226868129..35967937c 100644 --- a/crates/brk_query/src/impl/mining/block_rewards.rs +++ b/crates/brk_query/src/impl/mining/block_rewards.rs @@ -18,6 +18,7 @@ impl Query { // coinbase = subsidy + fees let mut rewards = computer .chain + .coinbase .indexes_to_coinbase .sats .dateindex diff --git a/crates/brk_query/src/impl/mining/block_sizes.rs b/crates/brk_query/src/impl/mining/block_sizes.rs index fed7e2b8a..2dda7e28c 100644 --- a/crates/brk_query/src/impl/mining/block_sizes.rs +++ b/crates/brk_query/src/impl/mining/block_sizes.rs @@ -17,12 +17,14 @@ impl Query { let mut sizes_vec = computer .chain + .block .indexes_to_block_size .dateindex .unwrap_average() .iter(); let mut weights_vec = computer .chain + .block .indexes_to_block_weight .dateindex .unwrap_average() diff --git a/crates/brk_query/src/impl/mining/dateindex_iter.rs b/crates/brk_query/src/impl/mining/dateindex_iter.rs index 0a7e07c1a..68fb96b10 100644 --- a/crates/brk_query/src/impl/mining/dateindex_iter.rs +++ b/crates/brk_query/src/impl/mining/dateindex_iter.rs @@ -14,11 +14,13 @@ impl<'a> DateIndexIter<'a> { pub fn new(computer: &'a Computer, start_height: usize, end_height: usize) -> Self { let start_di = computer .indexes + .block .height_to_dateindex .read_once(Height::from(start_height)) .unwrap_or_default(); let end_di = computer .indexes + .block .height_to_dateindex .read_once(Height::from(end_height)) .unwrap_or_default(); @@ -47,12 +49,13 @@ impl<'a> DateIndexIter<'a> { let mut timestamps = self .computer .chain + .epoch .timeindexes_to_timestamp .dateindex .as_ref() .expect("timeindexes_to_timestamp.dateindex should exist") .iter(); - let mut heights = self.computer.indexes.dateindex_to_first_height.iter(); + let mut heights = self.computer.indexes.time.dateindex_to_first_height.iter(); let mut entries = Vec::with_capacity(total / self.step + 1); let mut i = self.start_di.to_usize(); diff --git a/crates/brk_query/src/impl/mining/difficulty.rs b/crates/brk_query/src/impl/mining/difficulty.rs index af5c959ae..b92b4e9de 100644 --- a/crates/brk_query/src/impl/mining/difficulty.rs +++ b/crates/brk_query/src/impl/mining/difficulty.rs @@ -22,6 +22,7 @@ impl Query { // Get current epoch let current_epoch = computer .indexes + .block .height_to_difficultyepoch .read_once(current_height)?; let current_epoch_usize: usize = current_epoch.into(); @@ -29,6 +30,7 @@ impl Query { // Get epoch start height let epoch_start_height = computer .indexes + .block .difficultyepoch_to_first_height .read_once(current_epoch)?; let epoch_start_u32: u32 = epoch_start_height.into(); @@ -42,6 +44,7 @@ impl Query { // Get timestamps using difficultyepoch_to_timestamp for epoch start let epoch_start_timestamp = computer .chain + .epoch .difficultyepoch_to_timestamp .read_once(current_epoch)?; let current_timestamp = indexer @@ -82,6 +85,7 @@ impl Query { let prev_epoch = DifficultyEpoch::from(current_epoch_usize - 1); let prev_epoch_start = computer .indexes + .block .difficultyepoch_to_first_height .read_once(prev_epoch)?; diff --git a/crates/brk_query/src/impl/mining/epochs.rs b/crates/brk_query/src/impl/mining/epochs.rs index 3ed6bdd44..ea41f4ba8 100644 --- a/crates/brk_query/src/impl/mining/epochs.rs +++ b/crates/brk_query/src/impl/mining/epochs.rs @@ -10,19 +10,22 @@ pub fn iter_difficulty_epochs( ) -> Vec { let start_epoch = computer .indexes + .block .height_to_difficultyepoch .read_once(Height::from(start_height)) .unwrap_or_default(); let end_epoch = computer .indexes + .block .height_to_difficultyepoch .read_once(Height::from(end_height)) .unwrap_or_default(); - let mut epoch_to_height_iter = computer.indexes.difficultyepoch_to_first_height.iter(); - let mut epoch_to_timestamp_iter = computer.chain.difficultyepoch_to_timestamp.iter(); + let mut epoch_to_height_iter = computer.indexes.block.difficultyepoch_to_first_height.iter(); + let mut epoch_to_timestamp_iter = computer.chain.epoch.difficultyepoch_to_timestamp.iter(); let mut epoch_to_difficulty_iter = computer .chain + .mining .indexes_to_difficulty .difficultyepoch .unwrap_last() diff --git a/crates/brk_query/src/impl/mining/hashrate.rs b/crates/brk_query/src/impl/mining/hashrate.rs index edc3adfd4..31372ea1c 100644 --- a/crates/brk_query/src/impl/mining/hashrate.rs +++ b/crates/brk_query/src/impl/mining/hashrate.rs @@ -21,11 +21,13 @@ impl Query { // Get current hashrate let current_dateindex = computer .indexes + .block .height_to_dateindex .read_once(current_height)?; let current_hashrate = *computer .chain + .mining .indexes_to_hash_rate .dateindex .unwrap_last() @@ -41,6 +43,7 @@ impl Query { // Get hashrate entries using iterators for efficiency let start_dateindex = computer .indexes + .block .height_to_dateindex .read_once(Height::from(start))?; let end_dateindex = current_dateindex; @@ -55,6 +58,7 @@ impl Query { // Create iterators for the loop let mut hashrate_iter = computer .chain + .mining .indexes_to_hash_rate .dateindex .unwrap_last() @@ -62,6 +66,7 @@ impl Query { let mut timestamp_iter = computer .chain + .epoch .timeindexes_to_timestamp .dateindex .as_ref() diff --git a/crates/brk_query/src/impl/mining/reward_stats.rs b/crates/brk_query/src/impl/mining/reward_stats.rs index 1fae3bb52..91178cbc4 100644 --- a/crates/brk_query/src/impl/mining/reward_stats.rs +++ b/crates/brk_query/src/impl/mining/reward_stats.rs @@ -14,6 +14,7 @@ impl Query { let mut coinbase_iter = computer .chain + .coinbase .indexes_to_coinbase .sats .height @@ -22,6 +23,7 @@ impl Query { .iter(); let mut fee_iter = computer .chain + .transaction .indexes_to_fee .sats .height @@ -29,6 +31,7 @@ impl Query { .iter(); let mut tx_count_iter = computer .chain + .transaction .indexes_to_tx_count .height .as_ref()