diff --git a/crates/brk_computer/src/storage/vecs/grouped/builder.rs b/crates/brk_computer/src/storage/vecs/grouped/builder.rs index 83b3b7cb8..80141ca3d 100644 --- a/crates/brk_computer/src/storage/vecs/grouped/builder.rs +++ b/crates/brk_computer/src/storage/vecs/grouped/builder.rs @@ -176,12 +176,12 @@ where where I2: StoredIndex + StoredType + CheckedSub, { - let index = self.starting_index(max_from); - self.validate_computed_version_or_reset_file( source.version() + first_indexes.version() + count_indexes.version(), )?; + let index = self.starting_index(max_from); + let mut count_indexes_iter = count_indexes.iter(); let mut source_iter = source.iter(); diff --git a/crates/brk_computer/src/storage/vecs/market.rs b/crates/brk_computer/src/storage/vecs/market.rs index ef43aa5f4..dd9f67d0e 100644 --- a/crates/brk_computer/src/storage/vecs/market.rs +++ b/crates/brk_computer/src/storage/vecs/market.rs @@ -19,6 +19,20 @@ pub struct Vecs { pub indexes_to_days_since_ath: ComputedVecsFromDateindex, pub indexes_to_max_days_between_ath: ComputedVecsFromDateindex, pub indexes_to_max_years_between_ath: ComputedVecsFromDateindex, + + pub indexes_to_1w_sma: ComputedVecsFromDateindex, + pub indexes_to_8d_sma: ComputedVecsFromDateindex, + pub indexes_to_13d_sma: ComputedVecsFromDateindex, + pub indexes_to_21d_sma: ComputedVecsFromDateindex, + pub indexes_to_1m_sma: ComputedVecsFromDateindex, + pub indexes_to_34d_sma: ComputedVecsFromDateindex, + pub indexes_to_55d_sma: ComputedVecsFromDateindex, + pub indexes_to_89d_sma: ComputedVecsFromDateindex, + pub indexes_to_144d_sma: ComputedVecsFromDateindex, + pub indexes_to_1y_sma: ComputedVecsFromDateindex, + pub indexes_to_2y_sma: ComputedVecsFromDateindex, + pub indexes_to_200w_sma: ComputedVecsFromDateindex, + pub indexes_to_4y_sma: ComputedVecsFromDateindex, } impl Vecs { @@ -72,6 +86,98 @@ impl Vecs { compressed, StorableVecGeneatorOptions::default().add_last(), )?, + + indexes_to_1w_sma: ComputedVecsFromDateindex::forced_import( + path, + "1w_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_8d_sma: ComputedVecsFromDateindex::forced_import( + path, + "8d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_13d_sma: ComputedVecsFromDateindex::forced_import( + path, + "13d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_21d_sma: ComputedVecsFromDateindex::forced_import( + path, + "21d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_1m_sma: ComputedVecsFromDateindex::forced_import( + path, + "1m_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_34d_sma: ComputedVecsFromDateindex::forced_import( + path, + "34d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_55d_sma: ComputedVecsFromDateindex::forced_import( + path, + "55d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_89d_sma: ComputedVecsFromDateindex::forced_import( + path, + "89d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_144d_sma: ComputedVecsFromDateindex::forced_import( + path, + "144d_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_1y_sma: ComputedVecsFromDateindex::forced_import( + path, + "1y_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_2y_sma: ComputedVecsFromDateindex::forced_import( + path, + "2y_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_200w_sma: ComputedVecsFromDateindex::forced_import( + path, + "200w_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, + indexes_to_4y_sma: ComputedVecsFromDateindex::forced_import( + path, + "4y_sma", + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default().add_last(), + )?, }) } @@ -236,6 +342,201 @@ impl Vecs { }, )?; + self.indexes_to_1w_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 7, + exit, + ) + }, + )?; + + self.indexes_to_8d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 8, + exit, + ) + }, + )?; + + self.indexes_to_13d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 13, + exit, + ) + }, + )?; + + self.indexes_to_21d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 21, + exit, + ) + }, + )?; + + self.indexes_to_1m_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 30, + exit, + ) + }, + )?; + + self.indexes_to_34d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 34, + exit, + ) + }, + )?; + + self.indexes_to_55d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 55, + exit, + ) + }, + )?; + + self.indexes_to_89d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 89, + exit, + ) + }, + )?; + + self.indexes_to_144d_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 144, + exit, + ) + }, + )?; + + self.indexes_to_1y_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 365, + exit, + ) + }, + )?; + + self.indexes_to_2y_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 2 * 365, + exit, + ) + }, + )?; + + self.indexes_to_200w_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 200 * 7, + exit, + ) + }, + )?; + + self.indexes_to_4y_sma.compute( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + &fetched.timeindexes_to_close.dateindex, + 4 * 365, + exit, + ) + }, + )?; + Ok(()) } @@ -247,6 +548,19 @@ impl Vecs { self.indexes_to_days_since_ath.vecs(), self.indexes_to_max_days_between_ath.vecs(), self.indexes_to_max_years_between_ath.vecs(), + self.indexes_to_1w_sma.vecs(), + self.indexes_to_8d_sma.vecs(), + self.indexes_to_13d_sma.vecs(), + self.indexes_to_21d_sma.vecs(), + self.indexes_to_1m_sma.vecs(), + self.indexes_to_34d_sma.vecs(), + self.indexes_to_55d_sma.vecs(), + self.indexes_to_89d_sma.vecs(), + self.indexes_to_144d_sma.vecs(), + self.indexes_to_1y_sma.vecs(), + self.indexes_to_2y_sma.vecs(), + self.indexes_to_200w_sma.vecs(), + self.indexes_to_4y_sma.vecs(), ] .concat() } diff --git a/crates/brk_core/src/structs/dollars.rs b/crates/brk_core/src/structs/dollars.rs index 15d061ef9..cca63bdf4 100644 --- a/crates/brk_core/src/structs/dollars.rs +++ b/crates/brk_core/src/structs/dollars.rs @@ -4,7 +4,7 @@ use derive_deref::Deref; use serde::Serialize; use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; -use super::{Bitcoin, Cents, Sats}; +use super::{Bitcoin, Cents, Close, Sats}; #[derive( Debug, @@ -26,6 +26,12 @@ impl Dollars { pub const ZERO: Self = Self(0.0); } +impl From for Dollars { + fn from(value: f32) -> Self { + Self(value as f64) + } +} + impl From for Dollars { fn from(value: f64) -> Self { Self(value) @@ -38,12 +44,24 @@ impl From for Dollars { } } +impl From for f32 { + fn from(value: Dollars) -> Self { + value.0 as f32 + } +} + impl From for f64 { fn from(value: Dollars) -> Self { value.0 } } +impl From> for Dollars { + fn from(value: Close) -> Self { + Self(value.0) + } +} + impl From for Dollars { fn from(value: usize) -> Self { Self(value as f64) @@ -74,10 +92,28 @@ impl Ord for Dollars { } impl Mul for Dollars { - type Output = Dollars; + type Output = Self; fn mul(self, rhs: Bitcoin) -> Self::Output { Self::from(Cents::from( u128::from(Sats::from(rhs)) * u128::from(Cents::from(self)) / u128::from(Sats::ONE_BTC), )) } } + +impl From for Dollars { + fn from(value: u128) -> Self { + Self::from(Cents::from(value)) + } +} + +impl From> for u128 { + fn from(value: Close) -> Self { + u128::from(*value) + } +} + +impl From for u128 { + fn from(value: Dollars) -> Self { + u128::from(Cents::from(value)) + } +} diff --git a/crates/brk_core/src/structs/ohlc.rs b/crates/brk_core/src/structs/ohlc.rs index 6684cc724..069dd3537 100644 --- a/crates/brk_core/src/structs/ohlc.rs +++ b/crates/brk_core/src/structs/ohlc.rs @@ -453,6 +453,15 @@ where } } +impl From for Close +where + T: From, +{ + fn from(value: f32) -> Self { + Self(T::from(value)) + } +} + impl From for Close where T: From, @@ -462,6 +471,15 @@ where } } +impl From> for f32 +where + f32: From, +{ + fn from(value: Close) -> Self { + Self::from(value.0) + } +} + impl From> for f64 where f64: From, diff --git a/crates/brk_vec/src/variants/eager.rs b/crates/brk_vec/src/variants/eager.rs index 5c08a941d..78e663be4 100644 --- a/crates/brk_vec/src/variants/eager.rs +++ b/crates/brk_vec/src/variants/eager.rs @@ -2,7 +2,7 @@ use core::error; use std::{ cmp::Ordering, fmt::Debug, - ops::Add, + ops::{Add, Div}, path::{Path, PathBuf}, time::Duration, }; @@ -406,6 +406,46 @@ where self.safe_flush(exit) } + + pub fn compute_sma( + &mut self, + max_from: I, + source: &impl AnyIterableVec, + len: usize, + exit: &Exit, + ) -> Result<()> + where + T: Add + From + Div + From, + T2: StoredType, + f32: From + From, + { + self.validate_computed_version_or_reset_file( + Version::ZERO + self.inner.version() + source.version(), + )?; + + let index = max_from.min(I::from(self.len())); + let mut prev = None; + source.iter_at(index).try_for_each(|(i, value)| { + let value = value.into_inner(); + if prev.is_none() { + let i = i.unwrap_to_usize(); + prev.replace(if i > 0 { + self.into_iter().unwrap_get_inner_(i - 1) + } else { + T::from(0.0) + }); + } + let sma = T::from( + (f32::from(prev.clone().unwrap()) * (len - 1) as f32 + f32::from(value)) + / len as f32, + ); + + prev.replace(sma.clone()); + self.forced_push_at(i, sma, exit) + })?; + + self.safe_flush(exit) + } } impl EagerVec diff --git a/websites/kibo.money/scripts/main.js b/websites/kibo.money/scripts/main.js index ae7c7ad21..498296d56 100644 --- a/websites/kibo.money/scripts/main.js +++ b/websites/kibo.money/scripts/main.js @@ -730,7 +730,8 @@ function createUtils() { id.includes("close") || id.includes("ohlc") || id.includes("marketcap") || - id.includes("ath") + id.includes("ath") || + id.includes("-sma") ) { unit = "USD"; } else if (id.includes("count") || id.match(/v[1-3]/g)) { diff --git a/websites/kibo.money/scripts/options.js b/websites/kibo.money/scripts/options.js index 508ef9fba..0027e7476 100644 --- a/websites/kibo.money/scripts/options.js +++ b/websites/kibo.money/scripts/options.js @@ -510,8 +510,216 @@ function createPartialOptions(colors) { // ], // }, { - name: "By type", - tree: [], + name: "types", + tree: [ + { + name: "p2pk", + title: "Pay To Public Key Outputs", + bottom: [ + createBaseSeries({ + key: "p2pk33-count", + name: "33B Count", + }), + createBaseSeries({ + key: "p2pk33-count-sum", + name: "33B sum", + }), + createBaseSeries({ + key: "total-p2pk33-count", + name: "33B total", + }), + createBaseSeries({ + key: "p2pk65-count", + name: "65B Count", + }), + createBaseSeries({ + key: "p2pk65-count-sum", + name: "65B sum", + }), + createBaseSeries({ + key: "total-p2pk65-count", + name: "65B total", + }), + ], + }, + { + name: "p2pkh", + title: "Pay To Public Key Hash Outputs", + bottom: [ + createBaseSeries({ + key: "p2pkh-count", + name: "Count", + }), + createBaseSeries({ + key: "p2pkh-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2pkh-count", + name: "total", + }), + ], + }, + { + name: "p2ms", + title: "Pay To Multisig Outputs", + bottom: [ + createBaseSeries({ + key: "p2ms-count", + name: "Count", + }), + createBaseSeries({ + key: "p2ms-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2ms-count", + name: "total", + }), + ], + }, + { + name: "p2sh", + title: "Pay To Script Hash Outputs", + bottom: [ + createBaseSeries({ + key: "p2sh-count", + name: "Count", + }), + createBaseSeries({ + key: "p2sh-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2sh-count", + name: "total", + }), + ], + }, + { + name: "op_return", + title: "op_return outputs", + bottom: [ + createBaseSeries({ key: "opreturn-count", name: "Count" }), + createBaseSeries({ + key: "opreturn-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-opreturn-count", + name: "total", + }), + ], + }, + { + name: "p2wpkh", + title: "Pay To Witness Public Key Hash Outputs", + bottom: [ + createBaseSeries({ + key: "p2wpkh-count", + name: "Count", + }), + createBaseSeries({ + key: "p2wpkh-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2wpkh-count", + name: "total", + }), + ], + }, + { + name: "p2wsh", + title: "Pay To Witness Script Hash Outputs", + bottom: [ + createBaseSeries({ + key: "p2wsh-count", + name: "Count", + }), + createBaseSeries({ + key: "p2wsh-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2wsh-count", + name: "total", + }), + ], + }, + { + name: "p2tr", + title: "Pay To Taproot Outputs", + bottom: [ + createBaseSeries({ + key: "p2tr-count", + name: "Count", + }), + createBaseSeries({ + key: "p2tr-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2tr-count", + name: "total", + }), + ], + }, + { + name: "p2a", + title: "Pay To Anchor outputs", + bottom: [ + createBaseSeries({ + key: "p2a-count", + name: "Count", + }), + createBaseSeries({ + key: "p2a-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-p2a-count", + name: "total", + }), + ], + }, + { + name: "empty", + title: "empty outputs", + bottom: [ + createBaseSeries({ + key: "emptyoutput-count", + name: "Count", + }), + createBaseSeries({ + key: "emptyoutput-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-emptyoutput-count", + name: "total", + }), + ], + }, + { + name: "unknown", + title: "unknown outputs", + bottom: [ + createBaseSeries({ + key: "unknownoutput-count", + name: "Count", + }), + createBaseSeries({ + key: "unknownoutput-count-sum", + name: "sum", + }), + createBaseSeries({ + key: "total-unknownoutput-count", + name: "total", + }), + ], + }, + ], // title: "Transaction Output Value", // bottom: [ // createAverageSeries({ concat: "output-value" }), @@ -646,6 +854,141 @@ function createPartialOptions(colors) { }, ], }, + { + name: "Average", + tree: [ + { + name: "1 week", + title: "1 Week Market Price Moving Average", + top: [ + createBaseSeries({ + key: "1w-sma", + name: "Average", + }), + ], + }, + { + name: "8 days", + title: "8 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "8d-sma", + name: "Average", + }), + ], + }, + { + name: "13 days", + title: "13 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "13d-sma", + name: "Average", + }), + ], + }, + { + name: "21 days", + title: "21 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "21d-sma", + name: "Average", + }), + ], + }, + { + name: "1 month", + title: "1 Month Market Price Moving Average", + top: [ + createBaseSeries({ + key: "1m-sma", + name: "Average", + }), + ], + }, + { + name: "34 days", + title: "34 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "34d-sma", + name: "Average", + }), + ], + }, + { + name: "55 days", + title: "55 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "55d-sma", + name: "Average", + }), + ], + }, + { + name: "89 days", + title: "89 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "89d-sma", + name: "Average", + }), + ], + }, + { + name: "144 days", + title: "144 Days Market Price Moving Average", + top: [ + createBaseSeries({ + key: "144d-sma", + name: "Average", + }), + ], + }, + { + name: "1 year", + title: "1 year Market Price Moving Average", + top: [ + createBaseSeries({ + key: "1y-sma", + name: "Average", + }), + ], + }, + { + name: "2 year", + title: "2 year Market Price Moving Average", + top: [ + createBaseSeries({ + key: "2y-sma", + name: "Average", + }), + ], + }, + { + name: "200 weeks", + title: "200 Weeks Market Price Moving Average", + top: [ + createBaseSeries({ + key: "200w-sma", + name: "Average", + }), + ], + }, + { + name: "4 year", + title: "4 year Market Price Moving Average", + top: [ + createBaseSeries({ + key: "4y-sma", + name: "Average", + }), + ], + }, + ], + }, ], }, ], diff --git a/websites/kibo.money/scripts/vecid-to-indexes.js b/websites/kibo.money/scripts/vecid-to-indexes.js index ea6069e67..f2f021356 100644 --- a/websites/kibo.money/scripts/vecid-to-indexes.js +++ b/websites/kibo.money/scripts/vecid-to-indexes.js @@ -56,6 +56,19 @@ export function createVecIdToIndexes() { const YearIndex = /** @satisfies {YearIndex} */ (23); return /** @type {const} */ ({ + "13d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "144d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "1m-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "1w-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "1y-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "200w-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "21d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "2y-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "34d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "4y-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "55d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "89d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], + "8d-sma": [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], ath: [DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex], "base-size": [TxIndex], "block-count": [Height],