mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -2,11 +2,7 @@
|
||||
//!
|
||||
//! This crate sets mimalloc as the global allocator and provides
|
||||
//! utilities for monitoring and managing memory.
|
||||
//! ```
|
||||
|
||||
use std::{fmt, mem::MaybeUninit};
|
||||
|
||||
use log::info;
|
||||
use mimalloc::MiMalloc as Allocator;
|
||||
|
||||
#[global_allocator]
|
||||
@@ -16,131 +12,10 @@ static GLOBAL: Allocator = Allocator;
|
||||
pub struct Mimalloc;
|
||||
|
||||
impl Mimalloc {
|
||||
/// Get current mimalloc memory statistics.
|
||||
/// Very fast (~100-500ns) - uses getrusage/mach syscalls, no file I/O.
|
||||
#[inline]
|
||||
pub fn stats() -> Stats {
|
||||
let mut elapsed_msecs = MaybeUninit::uninit();
|
||||
let mut user_msecs = MaybeUninit::uninit();
|
||||
let mut system_msecs = MaybeUninit::uninit();
|
||||
let mut current_rss = MaybeUninit::uninit();
|
||||
let mut peak_rss = MaybeUninit::uninit();
|
||||
let mut current_commit = MaybeUninit::uninit();
|
||||
let mut peak_commit = MaybeUninit::uninit();
|
||||
let mut page_faults = MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
libmimalloc_sys::mi_process_info(
|
||||
elapsed_msecs.as_mut_ptr(),
|
||||
user_msecs.as_mut_ptr(),
|
||||
system_msecs.as_mut_ptr(),
|
||||
current_rss.as_mut_ptr(),
|
||||
peak_rss.as_mut_ptr(),
|
||||
current_commit.as_mut_ptr(),
|
||||
peak_commit.as_mut_ptr(),
|
||||
page_faults.as_mut_ptr(),
|
||||
);
|
||||
|
||||
Stats {
|
||||
current_rss: current_rss.assume_init(),
|
||||
peak_rss: peak_rss.assume_init(),
|
||||
current_commit: current_commit.assume_init(),
|
||||
peak_commit: peak_commit.assume_init(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Eagerly free memory back to OS.
|
||||
/// This is expensive - only call at natural pause points.
|
||||
/// Only call at natural pause points.
|
||||
#[inline]
|
||||
pub fn collect() {
|
||||
unsafe { libmimalloc_sys::mi_collect(true) }
|
||||
}
|
||||
|
||||
/// Collect if wasted memory exceeds threshold (in MB).
|
||||
/// Returns true if collection was triggered.
|
||||
pub fn collect_if_wasted_above(threshold_mb: usize) -> bool {
|
||||
let stats = Self::stats();
|
||||
|
||||
info!("Mimalloc stats: {:?}", stats);
|
||||
|
||||
if stats.wasted_mb() > threshold_mb {
|
||||
info!(
|
||||
"Mimalloc wasted {} MB (commit: {} MB, rss: {} MB), collecting...",
|
||||
stats.wasted_mb(),
|
||||
stats.commit_mb(),
|
||||
stats.rss_mb(),
|
||||
);
|
||||
Self::collect();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Force collection and return stats before/after.
|
||||
pub fn force_collect() -> (Stats, Stats) {
|
||||
let before = Self::stats();
|
||||
Self::collect();
|
||||
let after = Self::stats();
|
||||
|
||||
info!(
|
||||
"Mimalloc collected: {} MB -> {} MB (freed {} MB)",
|
||||
before.commit_mb(),
|
||||
after.commit_mb(),
|
||||
before.commit_mb().saturating_sub(after.commit_mb()),
|
||||
);
|
||||
|
||||
(before, after)
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory stats from mimalloc
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Stats {
|
||||
/// Resident set size (physical memory used)
|
||||
pub current_rss: usize,
|
||||
pub peak_rss: usize,
|
||||
/// Committed memory (virtual memory reserved)
|
||||
pub current_commit: usize,
|
||||
pub peak_commit: usize,
|
||||
}
|
||||
|
||||
impl Stats {
|
||||
/// Returns wasted memory in bytes (commit - rss).
|
||||
/// High values suggest fragmentation.
|
||||
#[inline]
|
||||
pub fn wasted(&self) -> usize {
|
||||
self.current_commit.saturating_sub(self.current_rss)
|
||||
}
|
||||
|
||||
/// Returns wasted memory in MB.
|
||||
#[inline]
|
||||
pub fn wasted_mb(&self) -> usize {
|
||||
self.wasted() / 1024 / 1024
|
||||
}
|
||||
|
||||
/// Returns current RSS in MB.
|
||||
#[inline]
|
||||
pub fn rss_mb(&self) -> usize {
|
||||
self.current_rss / 1024 / 1024
|
||||
}
|
||||
|
||||
/// Returns current commit in MB.
|
||||
#[inline]
|
||||
pub fn commit_mb(&self) -> usize {
|
||||
self.current_commit / 1024 / 1024
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Stats {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"rss: {} MB, commit: {} MB, wasted: {} MB",
|
||||
self.rss_mb(),
|
||||
self.commit_mb(),
|
||||
self.wasted_mb()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,10 +85,11 @@ fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) {
|
||||
.map(|arr| arr.iter().any(|v| v.as_str() == Some(prop_name)))
|
||||
.unwrap_or(false);
|
||||
let optional = if required { "" } else { "=" };
|
||||
let safe_name = to_camel_case(prop_name);
|
||||
writeln!(
|
||||
output,
|
||||
" * @property {{{}{}}} {}",
|
||||
prop_type, optional, prop_name
|
||||
prop_type, optional, safe_name
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -281,13 +282,17 @@ class MetricNode {{
|
||||
|
||||
/**
|
||||
* Fetch data points within a range.
|
||||
* @param {{string | number}} from
|
||||
* @param {{string | number}} to
|
||||
* @param {{string | number}} [from]
|
||||
* @param {{string | number}} [to]
|
||||
* @param {{(value: T[]) => void}} [onUpdate] - Called when data is available (may be called twice: cache then fresh)
|
||||
* @returns {{Promise<T[]>}}
|
||||
*/
|
||||
getRange(from, to, onUpdate) {{
|
||||
return this._client.get(`${{this._path}}?from=${{from}}&to=${{to}}`, onUpdate);
|
||||
const params = new URLSearchParams();
|
||||
if (from !== undefined) params.set('from', String(from));
|
||||
if (to !== undefined) params.set('to', String(to));
|
||||
const query = params.toString();
|
||||
return this._client.get(query ? `${{this._path}}?${{query}}` : this._path, onUpdate);
|
||||
}}
|
||||
}}
|
||||
|
||||
@@ -352,14 +357,25 @@ fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern]) {
|
||||
|
||||
writeln!(output, "// Index accessor factory functions\n").unwrap();
|
||||
|
||||
// Generate the ByIndexes type for each pattern
|
||||
for pattern in patterns {
|
||||
let by_type_name = format!("{}By", pattern.name);
|
||||
|
||||
// Inner 'by' object type
|
||||
writeln!(output, "/**").unwrap();
|
||||
writeln!(output, " * @template T").unwrap();
|
||||
writeln!(output, " * @typedef {{Object}} {}", by_type_name).unwrap();
|
||||
for index in &pattern.indexes {
|
||||
let index_name = index.serialize_long();
|
||||
writeln!(output, " * @property {{MetricNode<T>}} {}", index_name).unwrap();
|
||||
}
|
||||
writeln!(output, " */\n").unwrap();
|
||||
|
||||
// Outer type with 'by' property
|
||||
writeln!(output, "/**").unwrap();
|
||||
writeln!(output, " * @template T").unwrap();
|
||||
writeln!(output, " * @typedef {{Object}} {}", pattern.name).unwrap();
|
||||
for index in &pattern.indexes {
|
||||
let field_name = index_to_camel_case(index);
|
||||
writeln!(output, " * @property {{MetricNode<T>}} {}", field_name).unwrap();
|
||||
}
|
||||
writeln!(output, " * @property {{{}<T>}} by", by_type_name).unwrap();
|
||||
writeln!(output, " */\n").unwrap();
|
||||
|
||||
// Generate factory function
|
||||
@@ -377,10 +393,10 @@ fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern]) {
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(output, " return {{").unwrap();
|
||||
writeln!(output, " by: {{").unwrap();
|
||||
|
||||
for (i, index) in pattern.indexes.iter().enumerate() {
|
||||
let field_name = index_to_camel_case(index);
|
||||
let path_segment = index.serialize_long();
|
||||
let index_name = index.serialize_long();
|
||||
let comma = if i < pattern.indexes.len() - 1 {
|
||||
","
|
||||
} else {
|
||||
@@ -388,21 +404,18 @@ fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern]) {
|
||||
};
|
||||
writeln!(
|
||||
output,
|
||||
" {}: new MetricNode(client, `${{basePath}}/{}`){}",
|
||||
field_name, path_segment, comma
|
||||
" {}: new MetricNode(client, `${{basePath}}/{}`){}",
|
||||
index_name, index_name, comma
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
writeln!(output, " }}").unwrap();
|
||||
writeln!(output, " }};").unwrap();
|
||||
writeln!(output, "}}\n").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn index_to_camel_case(index: &Index) -> String {
|
||||
format!("by{}", to_pascal_case(index.serialize_long()))
|
||||
}
|
||||
|
||||
fn generate_structural_patterns(
|
||||
output: &mut String,
|
||||
patterns: &[StructuralPattern],
|
||||
|
||||
@@ -403,9 +403,15 @@ fn generate_metric_node(output: &mut String) {
|
||||
"""Fetch all data points for this metric."""
|
||||
return self._client.get(self._path)
|
||||
|
||||
def get_range(self, from_date: str, to_date: str) -> List[T]:
|
||||
"""Fetch data points within a date range."""
|
||||
return self._client.get(f"{{self._path}}?from={{from_date}}&to={{to_date}}")
|
||||
def get_range(self, from_val: Optional[str] = None, to_val: Optional[str] = None) -> List[T]:
|
||||
"""Fetch data points within a range."""
|
||||
params = []
|
||||
if from_val is not None:
|
||||
params.append(f"from={{from_val}}")
|
||||
if to_val is not None:
|
||||
params.append(f"to={{to_val}}")
|
||||
query = "&".join(params)
|
||||
return self._client.get(f"{{self._path}}?{{query}}" if query else self._path)
|
||||
|
||||
"#
|
||||
)
|
||||
|
||||
@@ -158,8 +158,15 @@ impl<T: DeserializeOwned> MetricNode<T> {{
|
||||
}}
|
||||
|
||||
/// Fetch data points within a range.
|
||||
pub fn get_range(&self, from: &str, to: &str) -> Result<Vec<T>> {{
|
||||
let path = format!("{{}}?from={{}}&to={{}}", self.path, from, to);
|
||||
pub fn get_range(&self, from: Option<&str>, to: Option<&str>) -> Result<Vec<T>> {{
|
||||
let mut params = Vec::new();
|
||||
if let Some(f) = from {{ params.push(format!("from={{}}", f)); }}
|
||||
if let Some(t) = to {{ params.push(format!("to={{}}", t)); }}
|
||||
let path = if params.is_empty() {{
|
||||
self.path.clone()
|
||||
}} else {{
|
||||
format!("{{}}?{{}}", self.path, params.join("&"))
|
||||
}};
|
||||
self.client.get(&path)
|
||||
}}
|
||||
}}
|
||||
|
||||
@@ -162,7 +162,7 @@ pub fn run() -> color_eyre::Result<()> {
|
||||
indexer.index(&blocks, &client, &exit)?
|
||||
};
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ fn run() -> Result<()> {
|
||||
let i = Instant::now();
|
||||
let starting_indexes = indexer.checked_index(&blocks, &client, &exit)?;
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
dbg!(i.elapsed());
|
||||
|
||||
@@ -62,7 +62,7 @@ fn run() -> Result<()> {
|
||||
let starting_indexes = indexer.index(&blocks, &client, &exit)?;
|
||||
info!("Done in {:?}", i.elapsed());
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
let i = Instant::now();
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
|
||||
@@ -83,7 +83,7 @@ fn run() -> Result<()> {
|
||||
let starting_indexes = indexer.index(&blocks, &client, &exit)?;
|
||||
info!("Done in {:?}", i.elapsed());
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
let i = Instant::now();
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
|
||||
69
crates/brk_computer/src/grouped/lazy_value2_from_height.rs
Normal file
69
crates/brk_computer/src/grouped/lazy_value2_from_height.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec};
|
||||
|
||||
use super::{ComputedValueVecsFromHeight, LazyVecsFrom2FromHeight};
|
||||
|
||||
/// Lazy value vecs computed from two `ComputedValueVecsFromHeight` sources via binary transforms.
|
||||
/// Used for computing coinbase = subsidy + fee.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyValueVecsFrom2FromHeight {
|
||||
pub sats: LazyVecsFrom2FromHeight<Sats, Sats, Sats>,
|
||||
pub bitcoin: LazyVecsFrom2FromHeight<Bitcoin, Sats, Sats>,
|
||||
pub dollars: Option<LazyVecsFrom2FromHeight<Dollars, Dollars, Dollars>>,
|
||||
}
|
||||
|
||||
impl LazyValueVecsFrom2FromHeight {
|
||||
pub fn from_computed<SatsF, BitcoinF, DollarsF>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
height_source1: IterableBoxedVec<Height, Sats>,
|
||||
height_source2: IterableBoxedVec<Height, Sats>,
|
||||
source1: &ComputedValueVecsFromHeight,
|
||||
source2: &ComputedValueVecsFromHeight,
|
||||
) -> Self
|
||||
where
|
||||
SatsF: BinaryTransform<Sats, Sats, Sats>,
|
||||
BitcoinF: BinaryTransform<Sats, Sats, Bitcoin>,
|
||||
DollarsF: BinaryTransform<Dollars, Dollars, Dollars>,
|
||||
{
|
||||
let sats = LazyVecsFrom2FromHeight::from_computed::<SatsF>(
|
||||
name,
|
||||
version,
|
||||
height_source1.boxed_clone(),
|
||||
height_source2.boxed_clone(),
|
||||
&source1.sats,
|
||||
&source2.sats,
|
||||
);
|
||||
|
||||
let bitcoin = LazyVecsFrom2FromHeight::from_computed::<BitcoinF>(
|
||||
&format!("{name}_btc"),
|
||||
version,
|
||||
height_source1,
|
||||
height_source2,
|
||||
&source1.sats,
|
||||
&source2.sats,
|
||||
);
|
||||
|
||||
let dollars = source1
|
||||
.dollars
|
||||
.as_ref()
|
||||
.zip(source2.dollars.as_ref())
|
||||
.map(|(d1, d2)| {
|
||||
LazyVecsFrom2FromHeight::from_computed::<DollarsF>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
d1.height.as_ref().unwrap().boxed_clone(),
|
||||
d2.height.as_ref().unwrap().boxed_clone(),
|
||||
d1,
|
||||
d2,
|
||||
)
|
||||
});
|
||||
|
||||
Self {
|
||||
sats,
|
||||
bitcoin,
|
||||
dollars,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ 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;
|
||||
@@ -40,6 +41,7 @@ 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::*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use brk_types::{Bitcoin, Close, Dollars, Sats, StoredF32, StoredF64, StoredU32};
|
||||
use brk_types::{Bitcoin, Close, Dollars, High, Sats, StoredF32, StoredF64, StoredU32};
|
||||
use vecdb::{BinaryTransform, UnaryTransform};
|
||||
|
||||
/// (Dollars, Dollars) -> Dollars addition
|
||||
@@ -23,6 +23,43 @@ impl BinaryTransform<Dollars, Dollars, Dollars> for DollarsMinus {
|
||||
}
|
||||
}
|
||||
|
||||
/// (Sats, Sats) -> Sats addition
|
||||
/// Used for computing coinbase = subsidy + fee
|
||||
pub struct SatsPlus;
|
||||
|
||||
impl BinaryTransform<Sats, Sats, Sats> for SatsPlus {
|
||||
#[inline(always)]
|
||||
fn apply(lhs: Sats, rhs: Sats) -> Sats {
|
||||
lhs + rhs
|
||||
}
|
||||
}
|
||||
|
||||
/// (Sats, Sats) -> Bitcoin addition with conversion
|
||||
/// Used for computing coinbase_btc = (subsidy + fee) / 1e8
|
||||
pub struct SatsPlusToBitcoin;
|
||||
|
||||
impl BinaryTransform<Sats, Sats, Bitcoin> for SatsPlusToBitcoin {
|
||||
#[inline(always)]
|
||||
fn apply(lhs: Sats, rhs: Sats) -> Bitcoin {
|
||||
Bitcoin::from(lhs + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/// (StoredU32, Sats) -> Sats mask
|
||||
/// Returns value if mask == 1, else 0. Used for pool fee/subsidy from chain data.
|
||||
pub struct MaskSats;
|
||||
|
||||
impl BinaryTransform<StoredU32, Sats, Sats> for MaskSats {
|
||||
#[inline(always)]
|
||||
fn apply(mask: StoredU32, value: Sats) -> Sats {
|
||||
if mask == StoredU32::ONE {
|
||||
value
|
||||
} else {
|
||||
Sats::ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF32 ratio
|
||||
/// Used for computing percentage ratios like profit/total, loss/total, etc.
|
||||
pub struct Ratio32;
|
||||
@@ -223,3 +260,78 @@ impl BinaryTransform<StoredU32, StoredU32, StoredF32> for PercentageU32F32 {
|
||||
StoredF32::from((*numerator as f64 / *denominator as f64) * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
// === Volatility Transforms (SD × sqrt(N)) ===
|
||||
|
||||
/// StoredF32 × sqrt(7) -> StoredF32 (1-week volatility from daily SD)
|
||||
pub struct StoredF32TimesSqrt7;
|
||||
|
||||
impl UnaryTransform<StoredF32, StoredF32> for StoredF32TimesSqrt7 {
|
||||
#[inline(always)]
|
||||
fn apply(v: StoredF32) -> StoredF32 {
|
||||
(*v * 7.0_f32.sqrt()).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// StoredF32 × sqrt(30) -> StoredF32 (1-month volatility from daily SD)
|
||||
pub struct StoredF32TimesSqrt30;
|
||||
|
||||
impl UnaryTransform<StoredF32, StoredF32> for StoredF32TimesSqrt30 {
|
||||
#[inline(always)]
|
||||
fn apply(v: StoredF32) -> StoredF32 {
|
||||
(*v * 30.0_f32.sqrt()).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// StoredF32 × sqrt(365) -> StoredF32 (1-year volatility from daily SD)
|
||||
pub struct StoredF32TimesSqrt365;
|
||||
|
||||
impl UnaryTransform<StoredF32, StoredF32> for StoredF32TimesSqrt365 {
|
||||
#[inline(always)]
|
||||
fn apply(v: StoredF32) -> StoredF32 {
|
||||
(*v * 365.0_f32.sqrt()).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// StoredU16 / 365.0 -> StoredF32 (days to years conversion)
|
||||
pub struct StoredU16ToYears;
|
||||
|
||||
impl UnaryTransform<StoredU16, StoredF32> for StoredU16ToYears {
|
||||
#[inline(always)]
|
||||
fn apply(v: StoredU16) -> StoredF32 {
|
||||
StoredF32::from(*v as f64 / 365.0)
|
||||
}
|
||||
}
|
||||
|
||||
// === Percentage Difference Transforms ===
|
||||
|
||||
/// (Close<Dollars>, Dollars) -> StoredF32 percentage difference ((a/b - 1) × 100)
|
||||
/// Used for DCA returns: (price / dca_avg_price - 1) × 100
|
||||
/// Also used for drawdown: (close / ath - 1) × 100 (note: drawdown is typically negative)
|
||||
pub struct PercentageDiffCloseDollars;
|
||||
|
||||
impl BinaryTransform<Close<Dollars>, Dollars, StoredF32> for PercentageDiffCloseDollars {
|
||||
#[inline(always)]
|
||||
fn apply(close: Close<Dollars>, base: Dollars) -> StoredF32 {
|
||||
if base == Dollars::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from((**close / *base - 1.0) * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// (High<Dollars>, Dollars) -> StoredF32 percentage difference ((a/b - 1) × 100)
|
||||
/// Used for drawdown calculation from high prices
|
||||
pub struct PercentageDiffHighDollars;
|
||||
|
||||
impl BinaryTransform<High<Dollars>, Dollars, StoredF32> for PercentageDiffHighDollars {
|
||||
#[inline(always)]
|
||||
fn apply(high: High<Dollars>, base: Dollars) -> StoredF32 {
|
||||
if base == Dollars::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from((**high / *base - 1.0) * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,19 +97,12 @@ impl Computer {
|
||||
|
||||
let i = Instant::now();
|
||||
let constants = constants::Vecs::new(VERSION, &indexes);
|
||||
let (price, market) = thread::scope(|s| -> Result<_> {
|
||||
let market_handle = big_thread().spawn_scoped(s, || {
|
||||
market::Vecs::forced_import(&computed_path, VERSION, &indexes)
|
||||
})?;
|
||||
|
||||
let price = fetched
|
||||
.is_some()
|
||||
.then(|| price::Vecs::forced_import(&computed_path, VERSION, &indexes).unwrap());
|
||||
|
||||
let market = market_handle.join().unwrap()?;
|
||||
|
||||
Ok((price, market))
|
||||
})?;
|
||||
// Price must be created before market since market's lazy vecs reference price
|
||||
let price = fetched
|
||||
.is_some()
|
||||
.then(|| price::Vecs::forced_import(&computed_path, VERSION, &indexes).unwrap());
|
||||
let market =
|
||||
market::Vecs::forced_import(&computed_path, VERSION, &indexes, price.as_ref())?;
|
||||
info!("Imported price/constants/market in {:?}", i.elapsed());
|
||||
|
||||
let i = Instant::now();
|
||||
@@ -130,8 +123,13 @@ impl Computer {
|
||||
let chain = chain_handle.join().unwrap()?;
|
||||
|
||||
// pools depends on chain for lazy dominance vecs
|
||||
let pools =
|
||||
pools::Vecs::forced_import(&computed_path, VERSION, &indexes, price.as_ref(), &chain)?;
|
||||
let pools = pools::Vecs::forced_import(
|
||||
&computed_path,
|
||||
VERSION,
|
||||
&indexes,
|
||||
price.as_ref(),
|
||||
&chain,
|
||||
)?;
|
||||
|
||||
Ok((chain, pools, cointime))
|
||||
})?;
|
||||
@@ -287,7 +285,6 @@ impl Computer {
|
||||
indexer,
|
||||
&self.indexes,
|
||||
&starting_indexes_clone,
|
||||
&self.chain,
|
||||
self.price.as_ref(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -53,17 +53,6 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_price_drawdown
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_drawdown(
|
||||
starting_indexes.dateindex,
|
||||
price.timeindexes_to_price_close.dateindex.u(),
|
||||
self.indexes_to_price_ath.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();
|
||||
@@ -117,84 +106,63 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_max_years_between_price_aths
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_max_days_between_price_aths.dateindex.u(),
|
||||
|(i, max, ..)| (i, StoredF32::from(*max as f64 / 365.0)),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
[
|
||||
(1, &mut self.price_1d_ago, &mut self._1d_price_returns, None),
|
||||
(7, &mut self.price_1w_ago, &mut self._1w_price_returns, None),
|
||||
(
|
||||
30,
|
||||
&mut self.price_1m_ago,
|
||||
&mut self._1m_price_returns,
|
||||
None,
|
||||
),
|
||||
(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,
|
||||
&mut self._3m_price_returns,
|
||||
&self._3m_price_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
6 * 30,
|
||||
&mut self.price_6m_ago,
|
||||
&mut self._6m_price_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
365,
|
||||
&mut self.price_1y_ago,
|
||||
&mut self._1y_price_returns,
|
||||
&self._6m_price_returns,
|
||||
None,
|
||||
),
|
||||
(365, &mut self.price_1y_ago, &self._1y_price_returns, None),
|
||||
(
|
||||
2 * 365,
|
||||
&mut self.price_2y_ago,
|
||||
&mut self._2y_price_returns,
|
||||
&self._2y_price_returns,
|
||||
Some(&mut self._2y_cagr),
|
||||
),
|
||||
(
|
||||
3 * 365,
|
||||
&mut self.price_3y_ago,
|
||||
&mut self._3y_price_returns,
|
||||
&self._3y_price_returns,
|
||||
Some(&mut self._3y_cagr),
|
||||
),
|
||||
(
|
||||
4 * 365,
|
||||
&mut self.price_4y_ago,
|
||||
&mut self._4y_price_returns,
|
||||
&self._4y_price_returns,
|
||||
Some(&mut self._4y_cagr),
|
||||
),
|
||||
(
|
||||
5 * 365,
|
||||
&mut self.price_5y_ago,
|
||||
&mut self._5y_price_returns,
|
||||
&self._5y_price_returns,
|
||||
Some(&mut self._5y_cagr),
|
||||
),
|
||||
(
|
||||
6 * 365,
|
||||
&mut self.price_6y_ago,
|
||||
&mut self._6y_price_returns,
|
||||
&self._6y_price_returns,
|
||||
Some(&mut self._6y_cagr),
|
||||
),
|
||||
(
|
||||
8 * 365,
|
||||
&mut self.price_8y_ago,
|
||||
&mut self._8y_price_returns,
|
||||
&self._8y_price_returns,
|
||||
Some(&mut self._8y_cagr),
|
||||
),
|
||||
(
|
||||
10 * 365,
|
||||
&mut self.price_10y_ago,
|
||||
&mut self._10y_price_returns,
|
||||
&self._10y_price_returns,
|
||||
Some(&mut self._10y_cagr),
|
||||
),
|
||||
]
|
||||
@@ -210,16 +178,6 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
returns.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_percentage_change(
|
||||
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(
|
||||
@@ -240,84 +198,84 @@ impl Vecs {
|
||||
7,
|
||||
&mut self._1w_dca_stack,
|
||||
&mut self._1w_dca_avg_price,
|
||||
&mut self._1w_dca_returns,
|
||||
&self._1w_dca_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
30,
|
||||
&mut self._1m_dca_stack,
|
||||
&mut self._1m_dca_avg_price,
|
||||
&mut self._1m_dca_returns,
|
||||
&self._1m_dca_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
3 * 30,
|
||||
&mut self._3m_dca_stack,
|
||||
&mut self._3m_dca_avg_price,
|
||||
&mut self._3m_dca_returns,
|
||||
&self._3m_dca_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
6 * 30,
|
||||
&mut self._6m_dca_stack,
|
||||
&mut self._6m_dca_avg_price,
|
||||
&mut self._6m_dca_returns,
|
||||
&self._6m_dca_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
365,
|
||||
&mut self._1y_dca_stack,
|
||||
&mut self._1y_dca_avg_price,
|
||||
&mut self._1y_dca_returns,
|
||||
&self._1y_dca_returns,
|
||||
None,
|
||||
),
|
||||
(
|
||||
2 * 365,
|
||||
&mut self._2y_dca_stack,
|
||||
&mut self._2y_dca_avg_price,
|
||||
&mut self._2y_dca_returns,
|
||||
&self._2y_dca_returns,
|
||||
Some(&mut self._2y_dca_cagr),
|
||||
),
|
||||
(
|
||||
3 * 365,
|
||||
&mut self._3y_dca_stack,
|
||||
&mut self._3y_dca_avg_price,
|
||||
&mut self._3y_dca_returns,
|
||||
&self._3y_dca_returns,
|
||||
Some(&mut self._3y_dca_cagr),
|
||||
),
|
||||
(
|
||||
4 * 365,
|
||||
&mut self._4y_dca_stack,
|
||||
&mut self._4y_dca_avg_price,
|
||||
&mut self._4y_dca_returns,
|
||||
&self._4y_dca_returns,
|
||||
Some(&mut self._4y_dca_cagr),
|
||||
),
|
||||
(
|
||||
5 * 365,
|
||||
&mut self._5y_dca_stack,
|
||||
&mut self._5y_dca_avg_price,
|
||||
&mut self._5y_dca_returns,
|
||||
&self._5y_dca_returns,
|
||||
Some(&mut self._5y_dca_cagr),
|
||||
),
|
||||
(
|
||||
6 * 365,
|
||||
&mut self._6y_dca_stack,
|
||||
&mut self._6y_dca_avg_price,
|
||||
&mut self._6y_dca_returns,
|
||||
&self._6y_dca_returns,
|
||||
Some(&mut self._6y_dca_cagr),
|
||||
),
|
||||
(
|
||||
8 * 365,
|
||||
&mut self._8y_dca_stack,
|
||||
&mut self._8y_dca_avg_price,
|
||||
&mut self._8y_dca_returns,
|
||||
&self._8y_dca_returns,
|
||||
Some(&mut self._8y_dca_cagr),
|
||||
),
|
||||
(
|
||||
10 * 365,
|
||||
&mut self._10y_dca_stack,
|
||||
&mut self._10y_dca_avg_price,
|
||||
&mut self._10y_dca_returns,
|
||||
&self._10y_dca_returns,
|
||||
Some(&mut self._10y_dca_cagr),
|
||||
),
|
||||
]
|
||||
@@ -344,16 +302,6 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
dca_returns.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_percentage_difference(
|
||||
starting_indexes.dateindex,
|
||||
price.timeindexes_to_price_close.dateindex.u(),
|
||||
dca_avg_price.dateindex.u(),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if let Some(dca_cagr) = dca_cagr {
|
||||
dca_cagr.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_cagr(
|
||||
@@ -374,72 +322,61 @@ impl Vecs {
|
||||
(
|
||||
2015,
|
||||
&mut self.dca_class_2015_avg_price,
|
||||
&mut self.dca_class_2015_returns,
|
||||
&mut self.dca_class_2015_stack,
|
||||
),
|
||||
(
|
||||
2016,
|
||||
&mut self.dca_class_2016_avg_price,
|
||||
&mut self.dca_class_2016_returns,
|
||||
&mut self.dca_class_2016_stack,
|
||||
),
|
||||
(
|
||||
2017,
|
||||
&mut self.dca_class_2017_avg_price,
|
||||
&mut self.dca_class_2017_returns,
|
||||
&mut self.dca_class_2017_stack,
|
||||
),
|
||||
(
|
||||
2018,
|
||||
&mut self.dca_class_2018_avg_price,
|
||||
&mut self.dca_class_2018_returns,
|
||||
&mut self.dca_class_2018_stack,
|
||||
),
|
||||
(
|
||||
2019,
|
||||
&mut self.dca_class_2019_avg_price,
|
||||
&mut self.dca_class_2019_returns,
|
||||
&mut self.dca_class_2019_stack,
|
||||
),
|
||||
(
|
||||
2020,
|
||||
&mut self.dca_class_2020_avg_price,
|
||||
&mut self.dca_class_2020_returns,
|
||||
&mut self.dca_class_2020_stack,
|
||||
),
|
||||
(
|
||||
2021,
|
||||
&mut self.dca_class_2021_avg_price,
|
||||
&mut self.dca_class_2021_returns,
|
||||
&mut self.dca_class_2021_stack,
|
||||
),
|
||||
(
|
||||
2022,
|
||||
&mut self.dca_class_2022_avg_price,
|
||||
&mut self.dca_class_2022_returns,
|
||||
&mut self.dca_class_2022_stack,
|
||||
),
|
||||
(
|
||||
2023,
|
||||
&mut self.dca_class_2023_avg_price,
|
||||
&mut self.dca_class_2023_returns,
|
||||
&mut self.dca_class_2023_stack,
|
||||
),
|
||||
(
|
||||
2024,
|
||||
&mut self.dca_class_2024_avg_price,
|
||||
&mut self.dca_class_2024_returns,
|
||||
&mut self.dca_class_2024_stack,
|
||||
),
|
||||
(
|
||||
2025,
|
||||
&mut self.dca_class_2025_avg_price,
|
||||
&mut self.dca_class_2025_returns,
|
||||
&mut self.dca_class_2025_stack,
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.try_for_each(|(year, avg_price, returns, stack)| -> Result<()> {
|
||||
.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| {
|
||||
@@ -462,16 +399,6 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
returns.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_percentage_difference(
|
||||
starting_indexes.dateindex,
|
||||
price.timeindexes_to_price_close.dateindex.u(),
|
||||
avg_price.dateindex.u(),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -591,49 +518,6 @@ impl Vecs {
|
||||
self._1d_price_returns.dateindex.u(),
|
||||
)?;
|
||||
|
||||
self.indexes_to_price_1w_volatility
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_1d_returns_1w_sd
|
||||
.sd
|
||||
.dateindex
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
|(i, v, ..)| (i, (*v * 7.0_f32.sqrt()).into()),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
self.indexes_to_price_1m_volatility
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_1d_returns_1m_sd
|
||||
.sd
|
||||
.dateindex
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
|(i, v, ..)| (i, (*v * 30.0_f32.sqrt()).into()),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
self.indexes_to_price_1y_volatility
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_1d_returns_1y_sd
|
||||
.sd
|
||||
.dateindex
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
|(i, v, ..)| (i, (*v * 365.0_f32.sqrt()).into()),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.dateindex_to_price_true_range.compute_transform3(
|
||||
starting_indexes.dateindex,
|
||||
price.timeindexes_to_price_open.dateindex.u(),
|
||||
|
||||
@@ -8,10 +8,12 @@ use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, PAGE_SIZE};
|
||||
use crate::{
|
||||
grouped::{
|
||||
ComputedRatioVecsFromDateIndex, ComputedStandardDeviationVecsFromDateIndex,
|
||||
ComputedVecsFromDateIndex, DollarsTimesTenths, LazyVecsFromDateIndex, Source,
|
||||
StandardDeviationVecsOptions, VecBuilderOptions,
|
||||
ComputedVecsFromDateIndex, DollarsTimesTenths, LazyVecsFrom2FromDateIndex,
|
||||
LazyVecsFromDateIndex, PercentageDiffCloseDollars, Source, StandardDeviationVecsOptions,
|
||||
StoredF32TimesSqrt30, StoredF32TimesSqrt365, StoredF32TimesSqrt7, StoredU16ToYears,
|
||||
VecBuilderOptions,
|
||||
},
|
||||
indexes,
|
||||
indexes, price,
|
||||
};
|
||||
|
||||
use super::Vecs;
|
||||
@@ -21,6 +23,7 @@ impl Vecs {
|
||||
parent_path: &Path,
|
||||
parent_version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
price: Option<&price::Vecs>,
|
||||
) -> Result<Self> {
|
||||
let db = Database::open(&parent_path.join(super::DB_NAME))?;
|
||||
db.set_min_len(PAGE_SIZE * 1_000_000)?;
|
||||
@@ -109,20 +112,199 @@ impl Vecs {
|
||||
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::<StoredF32TimesSqrt7>(
|
||||
"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::<StoredF32TimesSqrt30>(
|
||||
"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::<StoredF32TimesSqrt365>(
|
||||
"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::<StoredU16ToYears>(
|
||||
"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::<PercentageDiffCloseDollars>(
|
||||
"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::<PercentageDiffCloseDollars>(
|
||||
$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::<PercentageDiffCloseDollars>(
|
||||
$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 this = Self {
|
||||
height_to_price_ath: eager_h!("price_ath", v0),
|
||||
height_to_price_drawdown: eager_h!("price_drawdown", v0),
|
||||
indexes_to_price_ath: computed_di!("price_ath"),
|
||||
indexes_to_price_drawdown: computed_di!("price_drawdown"),
|
||||
indexes_to_1d_returns_1w_sd: sd_di!("1d_returns_1w_sd", 7, v1),
|
||||
indexes_to_1d_returns_1m_sd: sd_di!("1d_returns_1m_sd", 30, v1),
|
||||
indexes_to_1d_returns_1y_sd: sd_di!("1d_returns_1y_sd", 365, v1),
|
||||
indexes_to_price_1w_volatility: computed_di!("price_1w_volatility", v2),
|
||||
indexes_to_price_1m_volatility: computed_di!("price_1m_volatility", v2),
|
||||
indexes_to_price_1y_volatility: computed_di!("price_1y_volatility", v2),
|
||||
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: computed_di!("max_days_between_price_aths"),
|
||||
indexes_to_max_years_between_price_aths: computed_di!("max_years_between_price_aths"),
|
||||
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"),
|
||||
@@ -154,19 +336,19 @@ impl Vecs {
|
||||
indexes_to_price_200w_ema: ratio_di!("price_200w_ema"),
|
||||
indexes_to_price_4y_ema: ratio_di!("price_4y_ema"),
|
||||
|
||||
_1d_price_returns: computed_di!("1d_price_returns"),
|
||||
_1w_price_returns: computed_di!("1w_price_returns"),
|
||||
_1m_price_returns: computed_di!("1m_price_returns"),
|
||||
_3m_price_returns: computed_di!("3m_price_returns"),
|
||||
_6m_price_returns: computed_di!("6m_price_returns"),
|
||||
_1y_price_returns: computed_di!("1y_price_returns"),
|
||||
_2y_price_returns: computed_di!("2y_price_returns"),
|
||||
_3y_price_returns: computed_di!("3y_price_returns"),
|
||||
_4y_price_returns: computed_di!("4y_price_returns"),
|
||||
_5y_price_returns: computed_di!("5y_price_returns"),
|
||||
_6y_price_returns: computed_di!("6y_price_returns"),
|
||||
_8y_price_returns: computed_di!("8y_price_returns"),
|
||||
_10y_price_returns: computed_di!("10y_price_returns"),
|
||||
_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"),
|
||||
@@ -175,18 +357,18 @@ impl Vecs {
|
||||
_8y_cagr: computed_di!("8y_cagr"),
|
||||
_10y_cagr: computed_di!("10y_cagr"),
|
||||
|
||||
_1w_dca_returns: computed_di!("1w_dca_returns"),
|
||||
_1m_dca_returns: computed_di!("1m_dca_returns"),
|
||||
_3m_dca_returns: computed_di!("3m_dca_returns"),
|
||||
_6m_dca_returns: computed_di!("6m_dca_returns"),
|
||||
_1y_dca_returns: computed_di!("1y_dca_returns"),
|
||||
_2y_dca_returns: computed_di!("2y_dca_returns"),
|
||||
_3y_dca_returns: computed_di!("3y_dca_returns"),
|
||||
_4y_dca_returns: computed_di!("4y_dca_returns"),
|
||||
_5y_dca_returns: computed_di!("5y_dca_returns"),
|
||||
_6y_dca_returns: computed_di!("6y_dca_returns"),
|
||||
_8y_dca_returns: computed_di!("8y_dca_returns"),
|
||||
_10y_dca_returns: computed_di!("10y_dca_returns"),
|
||||
_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"),
|
||||
@@ -194,31 +376,31 @@ impl Vecs {
|
||||
_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: computed_di!("1w_dca_avg_price"),
|
||||
_1m_dca_avg_price: computed_di!("1m_dca_avg_price"),
|
||||
_3m_dca_avg_price: computed_di!("3m_dca_avg_price"),
|
||||
_6m_dca_avg_price: computed_di!("6m_dca_avg_price"),
|
||||
_1y_dca_avg_price: computed_di!("1y_dca_avg_price"),
|
||||
_2y_dca_avg_price: computed_di!("2y_dca_avg_price"),
|
||||
_3y_dca_avg_price: computed_di!("3y_dca_avg_price"),
|
||||
_4y_dca_avg_price: computed_di!("4y_dca_avg_price"),
|
||||
_5y_dca_avg_price: computed_di!("5y_dca_avg_price"),
|
||||
_6y_dca_avg_price: computed_di!("6y_dca_avg_price"),
|
||||
_8y_dca_avg_price: computed_di!("8y_dca_avg_price"),
|
||||
_10y_dca_avg_price: computed_di!("10y_dca_avg_price"),
|
||||
price_1d_ago: computed_di!("price_1d_ago"),
|
||||
price_1w_ago: computed_di!("price_1w_ago"),
|
||||
price_1m_ago: computed_di!("price_1m_ago"),
|
||||
price_3m_ago: computed_di!("price_3m_ago"),
|
||||
price_6m_ago: computed_di!("price_6m_ago"),
|
||||
price_1y_ago: computed_di!("price_1y_ago"),
|
||||
price_2y_ago: computed_di!("price_2y_ago"),
|
||||
price_3y_ago: computed_di!("price_3y_ago"),
|
||||
price_4y_ago: computed_di!("price_4y_ago"),
|
||||
price_5y_ago: computed_di!("price_5y_ago"),
|
||||
price_6y_ago: computed_di!("price_6y_ago"),
|
||||
price_8y_ago: computed_di!("price_8y_ago"),
|
||||
price_10y_ago: computed_di!("price_10y_ago"),
|
||||
_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"),
|
||||
@@ -244,29 +426,29 @@ impl Vecs {
|
||||
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: computed_di!("dca_class_2025_avg_price"),
|
||||
dca_class_2024_avg_price: computed_di!("dca_class_2024_avg_price"),
|
||||
dca_class_2023_avg_price: computed_di!("dca_class_2023_avg_price"),
|
||||
dca_class_2022_avg_price: computed_di!("dca_class_2022_avg_price"),
|
||||
dca_class_2021_avg_price: computed_di!("dca_class_2021_avg_price"),
|
||||
dca_class_2020_avg_price: computed_di!("dca_class_2020_avg_price"),
|
||||
dca_class_2019_avg_price: computed_di!("dca_class_2019_avg_price"),
|
||||
dca_class_2018_avg_price: computed_di!("dca_class_2018_avg_price"),
|
||||
dca_class_2017_avg_price: computed_di!("dca_class_2017_avg_price"),
|
||||
dca_class_2016_avg_price: computed_di!("dca_class_2016_avg_price"),
|
||||
dca_class_2015_avg_price: computed_di!("dca_class_2015_avg_price"),
|
||||
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: computed_di!("dca_class_2025_returns"),
|
||||
dca_class_2024_returns: computed_di!("dca_class_2024_returns"),
|
||||
dca_class_2023_returns: computed_di!("dca_class_2023_returns"),
|
||||
dca_class_2022_returns: computed_di!("dca_class_2022_returns"),
|
||||
dca_class_2021_returns: computed_di!("dca_class_2021_returns"),
|
||||
dca_class_2020_returns: computed_di!("dca_class_2020_returns"),
|
||||
dca_class_2019_returns: computed_di!("dca_class_2019_returns"),
|
||||
dca_class_2018_returns: computed_di!("dca_class_2018_returns"),
|
||||
dca_class_2017_returns: computed_di!("dca_class_2017_returns"),
|
||||
dca_class_2016_returns: computed_di!("dca_class_2016_returns"),
|
||||
dca_class_2015_returns: computed_di!("dca_class_2015_returns"),
|
||||
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,
|
||||
|
||||
@@ -2,12 +2,12 @@ mod compute;
|
||||
mod import;
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{DateIndex, Dollars, Height, Sats, StoredF32, StoredU16};
|
||||
use brk_types::{Close, DateIndex, Dollars, Height, Sats, StoredF32, StoredU16};
|
||||
use vecdb::{Database, EagerVec, PcoVec};
|
||||
|
||||
use crate::grouped::{
|
||||
ComputedRatioVecsFromDateIndex, ComputedStandardDeviationVecsFromDateIndex,
|
||||
ComputedVecsFromDateIndex, LazyVecsFromDateIndex,
|
||||
ComputedVecsFromDateIndex, LazyVecsFrom2FromDateIndex, LazyVecsFromDateIndex,
|
||||
};
|
||||
|
||||
pub const DB_NAME: &str = "market";
|
||||
@@ -19,17 +19,17 @@ pub struct Vecs {
|
||||
pub height_to_price_ath: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub height_to_price_drawdown: EagerVec<PcoVec<Height, StoredF32>>,
|
||||
pub indexes_to_price_ath: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_price_drawdown: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_price_drawdown: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub indexes_to_days_since_price_ath: ComputedVecsFromDateIndex<StoredU16>,
|
||||
pub indexes_to_max_days_between_price_aths: ComputedVecsFromDateIndex<StoredU16>,
|
||||
pub indexes_to_max_years_between_price_aths: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_max_years_between_price_aths: LazyVecsFromDateIndex<StoredF32, StoredU16>,
|
||||
|
||||
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: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_price_1m_volatility: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_price_1y_volatility: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_price_1w_volatility: LazyVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_price_1m_volatility: LazyVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_price_1y_volatility: LazyVecsFromDateIndex<StoredF32>,
|
||||
|
||||
pub indexes_to_price_1w_min: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_price_1w_max: ComputedVecsFromDateIndex<Dollars>,
|
||||
@@ -91,19 +91,19 @@ pub struct Vecs {
|
||||
pub price_8y_ago: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub price_10y_ago: ComputedVecsFromDateIndex<Dollars>,
|
||||
|
||||
pub _1d_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1w_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1m_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _3m_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _6m_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _2y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _3y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _4y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _5y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _6y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _8y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _10y_price_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1d_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _1w_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _1m_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _3m_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _6m_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _1y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _2y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _3y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _4y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _5y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _6y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _8y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _10y_price_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _2y_cagr: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _3y_cagr: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _4y_cagr: ComputedVecsFromDateIndex<StoredF32>,
|
||||
@@ -136,18 +136,18 @@ pub struct Vecs {
|
||||
pub _6y_dca_avg_price: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub _8y_dca_avg_price: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub _10y_dca_avg_price: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub _1w_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1m_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _3m_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _6m_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _2y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _3y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _4y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _5y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _6y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _8y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _10y_dca_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _1w_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _1m_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _3m_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _6m_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _1y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _2y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _3y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _4y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _5y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _6y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _8y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _10y_dca_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub _2y_dca_cagr: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _3y_dca_cagr: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub _4y_dca_cagr: ComputedVecsFromDateIndex<StoredF32>,
|
||||
@@ -180,15 +180,15 @@ pub struct Vecs {
|
||||
pub dca_class_2016_avg_price: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub dca_class_2015_avg_price: ComputedVecsFromDateIndex<Dollars>,
|
||||
|
||||
pub dca_class_2025_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2024_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2023_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2022_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2021_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2020_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2019_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2018_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2017_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2016_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2015_returns: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub dca_class_2025_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2024_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2023_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2022_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2021_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2020_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2019_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2018_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2017_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2016_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
pub dca_class_2015_returns: LazyVecsFrom2FromDateIndex<StoredF32, Close<Dollars>, Dollars>,
|
||||
}
|
||||
|
||||
@@ -79,11 +79,10 @@ impl Vecs {
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
chain: &chain::Vecs,
|
||||
price: Option<&price::Vecs>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_(indexer, indexes, starting_indexes, chain, price, exit)?;
|
||||
self.compute_(indexer, indexes, starting_indexes, price, exit)?;
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
Ok(())
|
||||
@@ -94,21 +93,13 @@ impl Vecs {
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
chain: &chain::Vecs,
|
||||
price: Option<&price::Vecs>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_height_to_pool(indexer, indexes, starting_indexes, exit)?;
|
||||
|
||||
self.vecs.par_iter_mut().try_for_each(|(_, vecs)| {
|
||||
vecs.compute(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_pool,
|
||||
chain,
|
||||
price,
|
||||
exit,
|
||||
)
|
||||
vecs.compute(indexes, starting_indexes, &self.height_to_pool, price, exit)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, PoolSlug, Sats, StoredF32, StoredU16, StoredU32};
|
||||
use vecdb::{Database, Exit, GenericStoredVec, IterableCloneableVec, IterableVec, VecIndex, Version};
|
||||
use vecdb::{
|
||||
Database, Exit, GenericStoredVec, IterableCloneableVec, IterableVec, LazyVecFrom2, VecIndex,
|
||||
Version,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
chain,
|
||||
grouped::{
|
||||
ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, ComputedVecsFromHeight,
|
||||
LazyVecsFrom2FromDateIndex, LazyVecsFrom2FromHeight, PercentageU32F32, Source,
|
||||
DollarsPlus, LazyValueVecsFrom2FromHeight, LazyVecsFrom2FromDateIndex,
|
||||
LazyVecsFrom2FromHeight, MaskSats, PercentageU32F32, SatsPlus, SatsPlusToBitcoin, Source,
|
||||
VecBuilderOptions,
|
||||
},
|
||||
indexes::{self, Indexes},
|
||||
price,
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
@@ -23,9 +26,11 @@ pub struct Vecs {
|
||||
pub indexes_to_1w_blocks_mined: ComputedVecsFromDateIndex<StoredU32>,
|
||||
pub indexes_to_1m_blocks_mined: ComputedVecsFromDateIndex<StoredU32>,
|
||||
pub indexes_to_1y_blocks_mined: ComputedVecsFromDateIndex<StoredU32>,
|
||||
pub height_to_subsidy: LazyVecFrom2<Height, Sats, Height, StoredU32, Height, Sats>,
|
||||
pub height_to_fee: LazyVecFrom2<Height, Sats, Height, StoredU32, Height, Sats>,
|
||||
pub indexes_to_subsidy: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_fee: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_coinbase: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_coinbase: LazyValueVecsFrom2FromHeight,
|
||||
pub indexes_to_dominance: LazyVecsFrom2FromHeight<StoredF32, StoredU32, StoredU32>,
|
||||
pub indexes_to_1d_dominance: LazyVecsFrom2FromHeight<StoredF32, StoredU32, StoredU32>,
|
||||
pub indexes_to_1w_dominance: LazyVecsFrom2FromDateIndex<StoredF32, StoredU32, StoredU32>,
|
||||
@@ -76,20 +81,86 @@ impl Vecs {
|
||||
let indexes_to_1m_blocks_mined = import_di!("1m_blocks_mined");
|
||||
let indexes_to_1y_blocks_mined = import_di!("1y_blocks_mined");
|
||||
|
||||
let height_to_subsidy = LazyVecFrom2::transformed::<MaskSats>(
|
||||
&suffix("subsidy"),
|
||||
version,
|
||||
indexes_to_blocks_mined
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
chain
|
||||
.indexes_to_subsidy
|
||||
.sats
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
);
|
||||
|
||||
let indexes_to_subsidy = ComputedValueVecsFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("subsidy"),
|
||||
Source::Vec(height_to_subsidy.boxed_clone()),
|
||||
version,
|
||||
sum_cum,
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
let height_to_fee = LazyVecFrom2::transformed::<MaskSats>(
|
||||
&suffix("fee"),
|
||||
version,
|
||||
indexes_to_blocks_mined
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
chain.indexes_to_fee.sats.height.unwrap_sum().boxed_clone(),
|
||||
);
|
||||
|
||||
let indexes_to_fee = ComputedValueVecsFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("fee"),
|
||||
Source::Vec(height_to_fee.boxed_clone()),
|
||||
version,
|
||||
sum_cum,
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
indexes_to_dominance: LazyVecsFrom2FromHeight::from_computed::<PercentageU32F32>(
|
||||
&suffix("dominance"),
|
||||
version,
|
||||
indexes_to_blocks_mined.height.as_ref().unwrap().boxed_clone(),
|
||||
chain.indexes_to_block_count.height.as_ref().unwrap().boxed_clone(),
|
||||
indexes_to_blocks_mined
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
chain
|
||||
.indexes_to_block_count
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
&indexes_to_blocks_mined,
|
||||
&chain.indexes_to_block_count,
|
||||
),
|
||||
indexes_to_1d_dominance: LazyVecsFrom2FromHeight::from_computed::<PercentageU32F32>(
|
||||
&suffix("1d_dominance"),
|
||||
version,
|
||||
indexes_to_blocks_mined.height.as_ref().unwrap().boxed_clone(),
|
||||
chain.indexes_to_block_count.height.as_ref().unwrap().boxed_clone(),
|
||||
indexes_to_blocks_mined
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
chain
|
||||
.indexes_to_block_count
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
&indexes_to_blocks_mined,
|
||||
&chain.indexes_to_block_count,
|
||||
),
|
||||
@@ -116,33 +187,22 @@ impl Vecs {
|
||||
indexes_to_1w_blocks_mined,
|
||||
indexes_to_1m_blocks_mined,
|
||||
indexes_to_1y_blocks_mined,
|
||||
indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("subsidy"),
|
||||
Source::Compute,
|
||||
version,
|
||||
sum_cum,
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_fee: ComputedValueVecsFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("fee"),
|
||||
Source::Compute,
|
||||
version,
|
||||
sum_cum,
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import(
|
||||
db,
|
||||
indexes_to_coinbase: LazyValueVecsFrom2FromHeight::from_computed::<
|
||||
SatsPlus,
|
||||
SatsPlusToBitcoin,
|
||||
DollarsPlus,
|
||||
>(
|
||||
&suffix("coinbase"),
|
||||
Source::Compute,
|
||||
version,
|
||||
sum_cum,
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
height_to_subsidy.boxed_clone(),
|
||||
height_to_fee.boxed_clone(),
|
||||
&indexes_to_subsidy,
|
||||
&indexes_to_fee,
|
||||
),
|
||||
height_to_subsidy,
|
||||
height_to_fee,
|
||||
indexes_to_subsidy,
|
||||
indexes_to_fee,
|
||||
indexes_to_days_since_block: import_di!("days_since_block"),
|
||||
})
|
||||
}
|
||||
@@ -153,7 +213,6 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
height_to_pool: &impl IterableVec<Height, PoolSlug>,
|
||||
chain: &chain::Vecs,
|
||||
price: Option<&price::Vecs>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
@@ -210,70 +269,21 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let height_to_blocks_mined = self.indexes_to_blocks_mined.height.u();
|
||||
self.indexes_to_subsidy.compute_rest(
|
||||
indexes,
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_subsidy),
|
||||
)?;
|
||||
|
||||
self.indexes_to_subsidy
|
||||
.compute_all(indexes, price, starting_indexes, exit, |vec| {
|
||||
vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
height_to_blocks_mined,
|
||||
chain.indexes_to_subsidy.sats.height.u(),
|
||||
|(h, mined, sats, ..)| {
|
||||
(
|
||||
h,
|
||||
if mined == StoredU32::ONE {
|
||||
sats
|
||||
} else {
|
||||
Sats::ZERO
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_fee
|
||||
.compute_all(indexes, price, starting_indexes, exit, |vec| {
|
||||
vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
height_to_blocks_mined,
|
||||
chain.indexes_to_fee.sats.height.unwrap_sum(),
|
||||
|(h, mined, sats, ..)| {
|
||||
(
|
||||
h,
|
||||
if mined == StoredU32::ONE {
|
||||
sats
|
||||
} else {
|
||||
Sats::ZERO
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_coinbase
|
||||
.compute_all(indexes, price, starting_indexes, exit, |vec| {
|
||||
vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
height_to_blocks_mined,
|
||||
chain.indexes_to_coinbase.sats.height.u(),
|
||||
|(h, mined, sats, ..)| {
|
||||
(
|
||||
h,
|
||||
if mined == StoredU32::ONE {
|
||||
sats
|
||||
} else {
|
||||
Sats::ZERO
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
self.indexes_to_fee.compute_rest(
|
||||
indexes,
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_fee),
|
||||
)?;
|
||||
|
||||
self.indexes_to_days_since_block
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
|
||||
@@ -49,7 +49,7 @@ fn main() -> color_eyre::Result<()> {
|
||||
indexer.checked_index(&blocks, &client, &exit)?;
|
||||
info!("Done in {:?}", i.elapsed());
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
sleep(Duration::from_secs(60));
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ fn main() -> Result<()> {
|
||||
|
||||
sleep(Duration::from_secs(10));
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
sleep(Duration::from_secs(10));
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ fn main() -> Result<()> {
|
||||
indexer.index(&blocks, &client, &exit)?;
|
||||
info!("Done in {:?}", i.elapsed());
|
||||
|
||||
Mimalloc::collect_if_wasted_above(500);
|
||||
Mimalloc::collect();
|
||||
|
||||
sleep(Duration::from_secs(60));
|
||||
}
|
||||
|
||||
@@ -1,132 +1,128 @@
|
||||
/**
|
||||
* @import { Signal, Signals } from "../brk-signals/index";
|
||||
* @import { BRK } from '../brk-client/index'
|
||||
* @import { Metric } from '../brk-client/metrics'
|
||||
* @import { IndexName } from '../brk-client/generated/metrics'
|
||||
* @import { MetricNode } from "../brk-client/index";
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} Resource
|
||||
* @property {Signal<T | null>} data
|
||||
* @property {Signal<boolean>} loading
|
||||
* @property {Signal<Error | null>} error
|
||||
* @property {(...args: any[]) => Promise<T | null>} fetch
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} RangeState
|
||||
* @property {Signal<T[] | null>} data
|
||||
* @property {Signal<boolean>} loading
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} MetricResource
|
||||
* @property {string} path
|
||||
* @property {(from?: number, to?: number) => RangeState<T>} range
|
||||
* @property {(from?: number, to?: number) => Promise<T[] | null>} fetch
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {ReturnType<typeof createResources>} Resources
|
||||
* @typedef {ReturnType<Resources["metrics"]["getOrCreate"]>} MetricResource
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {BRK} brk
|
||||
* @param {Signals} signals
|
||||
*/
|
||||
export function createResources(brk, signals) {
|
||||
export function createResources(signals) {
|
||||
const owner = signals.getOwner();
|
||||
|
||||
const defaultFrom = -10_000;
|
||||
const defaultTo = undefined;
|
||||
|
||||
/**
|
||||
* @param {Object} [args]
|
||||
* @param {number} [args.from]
|
||||
* @param {number} [args.to]
|
||||
*/
|
||||
function genKey(args) {
|
||||
return `${args?.from ?? defaultFrom}-${args?.to ?? ""}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a generic reactive resource wrapper for any async fetcher
|
||||
* @template T
|
||||
* @param {Metric} metric
|
||||
* @param {IndexName} index
|
||||
* @template {any[]} Args
|
||||
* @param {(...args: Args) => Promise<T>} fetcher
|
||||
* @returns {Resource<T>}
|
||||
*/
|
||||
function createMetricResource(metric, index) {
|
||||
if (!brk.hasMetric(metric)) {
|
||||
throw Error(`${metric} is invalid`);
|
||||
}
|
||||
|
||||
function createResource(fetcher) {
|
||||
return signals.runWithOwner(owner, () => {
|
||||
const fetchedRecord = signals.createSignal(
|
||||
/** @type {Map<string, {loading: boolean, at: Date | null, data: Signal<T[] | null>}>} */ (
|
||||
new Map()
|
||||
),
|
||||
);
|
||||
const data = signals.createSignal(/** @type {T | null} */ (null));
|
||||
const loading = signals.createSignal(false);
|
||||
const error = signals.createSignal(/** @type {Error | null} */ (null));
|
||||
|
||||
return {
|
||||
url: brk.genMetricURL(metric, index, defaultFrom),
|
||||
fetched: fetchedRecord,
|
||||
data,
|
||||
loading,
|
||||
error,
|
||||
/**
|
||||
* Defaults
|
||||
* - from: -10_000
|
||||
* - to: undefined
|
||||
*
|
||||
* @param {Object} [args]
|
||||
* @param {number} [args.from]
|
||||
* @param {number} [args.to]
|
||||
* @param {Args} args
|
||||
*/
|
||||
async fetch(args) {
|
||||
const from = args?.from ?? defaultFrom;
|
||||
const to = args?.to ?? defaultTo;
|
||||
const fetchedKey = genKey({ from, to });
|
||||
if (!fetchedRecord().has(fetchedKey)) {
|
||||
fetchedRecord.set((map) => {
|
||||
map.set(fetchedKey, {
|
||||
loading: false,
|
||||
at: null,
|
||||
data: signals.createSignal(/** @type {T[] | null} */ (null), {
|
||||
equals: false,
|
||||
}),
|
||||
});
|
||||
return map;
|
||||
});
|
||||
async fetch(...args) {
|
||||
loading.set(true);
|
||||
error.set(null);
|
||||
try {
|
||||
const result = await fetcher(...args);
|
||||
data.set(result);
|
||||
return result;
|
||||
} catch (e) {
|
||||
error.set(e instanceof Error ? e : new Error(String(e)));
|
||||
return null;
|
||||
} finally {
|
||||
loading.set(false);
|
||||
}
|
||||
const fetched = fetchedRecord().get(fetchedKey);
|
||||
if (!fetched) throw Error("Unreachable");
|
||||
if (fetched.loading) return fetched.data();
|
||||
if (fetched.at) {
|
||||
const diff = new Date().getTime() - fetched.at.getTime();
|
||||
const ONE_MINUTE_IN_MS = 60_000;
|
||||
if (diff < ONE_MINUTE_IN_MS) return fetched.data();
|
||||
}
|
||||
fetched.loading = true;
|
||||
const res = /** @type {T[] | null} */ (
|
||||
await brk.fetchMetric(
|
||||
(data) => {
|
||||
if (data.length || !fetched.data()) {
|
||||
fetched.data.set(data);
|
||||
}
|
||||
},
|
||||
index,
|
||||
metric,
|
||||
from,
|
||||
to,
|
||||
)
|
||||
);
|
||||
fetched.at = new Date();
|
||||
fetched.loading = false;
|
||||
return res;
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** @type {Map<string, NonNullable<ReturnType<typeof createMetricResource>>>} */
|
||||
const map = new Map();
|
||||
/**
|
||||
* Create a reactive resource wrapper for a MetricNode with multi-range support
|
||||
* @template T
|
||||
* @param {MetricNode<T>} node
|
||||
* @returns {MetricResource<T>}
|
||||
*/
|
||||
function useMetricNode(node) {
|
||||
return signals.runWithOwner(owner, () => {
|
||||
/** @type {Map<string, RangeState<T>>} */
|
||||
const ranges = new Map();
|
||||
|
||||
const metrics = {
|
||||
/**
|
||||
* @template T
|
||||
* @param {Metric} metric
|
||||
* @param {IndexName} index
|
||||
*/
|
||||
getOrCreate(metric, index) {
|
||||
const key = `${metric}/${index}`;
|
||||
const found = map.get(key);
|
||||
if (found) {
|
||||
return found;
|
||||
/**
|
||||
* Get or create range state
|
||||
* @param {number} [from=-10000]
|
||||
* @param {number} [to]
|
||||
*/
|
||||
function range(from = -10000, to) {
|
||||
const key = `${from}-${to ?? ""}`;
|
||||
if (!ranges.has(key)) {
|
||||
ranges.set(key, {
|
||||
data: signals.createSignal(/** @type {T[] | null} */ (null)),
|
||||
loading: signals.createSignal(false),
|
||||
});
|
||||
}
|
||||
return /** @type {RangeState<T>} */ (ranges.get(key));
|
||||
}
|
||||
|
||||
const resource = createMetricResource(metric, index);
|
||||
if (!resource) throw Error("metric is undefined");
|
||||
map.set(key, /** @type {any} */ (resource));
|
||||
return resource;
|
||||
},
|
||||
genKey,
|
||||
};
|
||||
return {
|
||||
path: node._path,
|
||||
range,
|
||||
/**
|
||||
* Fetch data for a range
|
||||
* @param {number} [from=-10000]
|
||||
* @param {number} [to]
|
||||
*/
|
||||
async fetch(from = -10000, to) {
|
||||
const r = range(from, to);
|
||||
r.loading.set(true);
|
||||
try {
|
||||
const result = await node.getRange(from, to, r.data.set);
|
||||
return result;
|
||||
} finally {
|
||||
r.loading.set(false);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return { metrics };
|
||||
return { createResource, useMetricNode };
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ Promise.all([
|
||||
]).then(([signals, { BrkClient, VERSION }, { createResources }, { initOptions }]) =>
|
||||
signals.createRoot(() => {
|
||||
const brk = new BrkClient("/");
|
||||
const resources = createResources(brk, signals);
|
||||
const resources = createResources(signals);
|
||||
const owner = signals.getOwner();
|
||||
|
||||
console.log(`VERSION = ${VERSION}`);
|
||||
|
||||
Reference in New Issue
Block a user