use core::error; use std::{ cmp::Ordering, f32, fmt::Debug, ops::{Add, Div, Mul}, path::{Path, PathBuf}, time::Duration, }; use arc_swap::ArcSwap; use brk_core::{ Bitcoin, CheckedSub, Close, Date, DateIndex, Dollars, Error, Result, Sats, StoredF32, StoredUsize, Value, Version, }; use brk_exit::Exit; use log::info; use memmap2::Mmap; use crate::{ AnyCollectableVec, AnyIterableVec, AnyVec, BoxedVecIterator, CollectableVec, Format, GenericStoredVec, StoredIndex, StoredType, StoredVec, StoredVecIterator, VecIterator, }; const ONE_KIB: usize = 1024; const ONE_MIB: usize = ONE_KIB * ONE_KIB; const MAX_CACHE_SIZE: usize = 210 * ONE_MIB; const DCA_AMOUNT: Dollars = Dollars::mint(100.0); #[derive(Debug, Clone)] pub struct EagerVec(StoredVec); // computed_version: Arc>>, impl EagerVec where I: StoredIndex, T: StoredType, { const SIZE_OF: usize = size_of::(); pub fn forced_import( path: &Path, value_name: &str, version: Version, format: Format, ) -> Result { Ok(Self(StoredVec::forced_import( path, value_name, version, format, )?)) } fn safe_truncate_if_needed(&mut self, index: I, exit: &Exit) -> Result<()> { if exit.triggered() { return Ok(()); } let blocked = exit.blocked(); if !blocked { exit.block(); } self.0.truncate_if_needed(index)?; if !blocked { exit.release(); } Ok(()) } #[inline] pub fn forced_push_at(&mut self, index: I, value: T, exit: &Exit) -> Result<()> { match self.len().cmp(&index.to_usize()?) { Ordering::Less => { return Err(Error::IndexTooHigh); } ord => { if ord == Ordering::Greater { self.safe_truncate_if_needed(index, exit)?; } self.0.push(value); } } if self.0.pushed_len() * Self::SIZE_OF >= MAX_CACHE_SIZE { self.safe_flush(exit) } else { Ok(()) } } pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> { if exit.triggered() { return Ok(()); } let blocked = exit.blocked(); if !blocked { exit.block(); } self.0.flush()?; if !blocked { exit.release(); } Ok(()) } pub fn path(&self) -> PathBuf { self.0.path() } pub fn get_or_read(&self, index: I, mmap: &Mmap) -> Result>> { self.0.get_or_read(index, mmap) } pub fn mmap(&self) -> &ArcSwap { self.0.mmap() } pub fn inner_version(&self) -> Version { self.0.version() } fn update_computed_version(&mut self, computed_version: Version) { self.0 .mut_header() .update_computed_version(computed_version); } pub fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> { if version != self.0.header().computed_version() { self.update_computed_version(version); if !self.is_empty() { self.0.reset()?; } } if self.is_empty() { info!( "Computing {}_to_{}...", self.index_type_to_string(), self.name() ) } Ok(()) } pub fn compute_to( &mut self, max_from: I, to: usize, version: Version, mut t: F, exit: &Exit, ) -> Result<()> where F: FnMut(I) -> (I, T), { self.validate_computed_version_or_reset_file(Version::ZERO + self.0.version() + version)?; let index = max_from.min(I::from(self.len())); (index.to_usize()?..to).try_for_each(|i| { let (i, v) = t(I::from(i)); self.forced_push_at(i, v, exit) })?; self.safe_flush(exit) } pub fn compute_range( &mut self, max_from: I, other: &impl AnyIterableVec, t: F, exit: &Exit, ) -> Result<()> where A: StoredType, F: FnMut(I) -> (I, T), { self.compute_to(max_from, other.len(), other.version(), t, exit) } pub fn compute_from_index( &mut self, max_from: I, other: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: From, T2: StoredType, { self.compute_to( max_from, other.len(), other.version(), |i| (i, T::from(i)), exit, ) } pub fn compute_transform( &mut self, max_from: A, other: &impl AnyIterableVec, mut t: F, exit: &Exit, ) -> Result<()> where A: StoredIndex, B: StoredType, F: FnMut((A, B, &Self)) -> (I, T), { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + other.version(), )?; let index = max_from.min(A::from(self.len())); other.iter_at(index).try_for_each(|(a, b)| { let (i, v) = t((a, b.into_inner(), self)); self.forced_push_at(i, v, exit) })?; self.safe_flush(exit) } pub fn compute_add( &mut self, max_from: I, added: &impl AnyIterableVec, adder: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: Add, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + added.version() + adder.version(), )?; let index = max_from.min(I::from(self.len())); let mut adder_iter = adder.iter(); added.iter_at(index).try_for_each(|(i, v)| { let v = v.into_inner() + adder_iter.unwrap_get_inner(i); self.forced_push_at(i, v, exit) })?; self.safe_flush(exit) } pub fn compute_subtract( &mut self, max_from: I, subtracted: &impl AnyIterableVec, subtracter: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: CheckedSub, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + subtracted.version() + subtracter.version(), )?; let index = max_from.min(I::from(self.len())); let mut subtracter_iter = subtracter.iter(); subtracted.iter_at(index).try_for_each(|(i, v)| { let v = v .into_inner() .checked_sub(subtracter_iter.unwrap_get_inner(i)) .unwrap(); self.forced_push_at(i, v, exit) })?; self.safe_flush(exit) } pub fn compute_max( &mut self, max_from: I, source: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: From + Ord, T2: StoredType, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + source.version(), )?; let index = max_from.min(I::from(self.len())); let mut prev = None; source.iter_at(index).try_for_each(|(i, v)| { 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(source.iter().unwrap_get_inner_(0)) }); } let max = prev.clone().unwrap().max(T::from(v.into_inner())); prev.replace(max.clone()); self.forced_push_at(i, max, exit) })?; self.safe_flush(exit) } pub fn compute_multiply( &mut self, max_from: I, multiplied: &impl AnyIterableVec, multiplier: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T2: StoredType + Mul, T3: StoredType, T4: StoredType, T: From, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + multiplied.version() + multiplier.version(), )?; let index = max_from.min(I::from(self.len())); let mut multiplier_iter = multiplier.iter(); multiplied.iter_at(index).try_for_each(|(i, v)| { let v = v.into_inner() * multiplier_iter.unwrap_get_inner(i); self.forced_push_at(i, v.into(), exit) })?; self.safe_flush(exit) } pub fn compute_divide( &mut self, max_from: I, divided: &impl AnyIterableVec, divider: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T2: StoredType + Mul, T3: StoredType, T4: Div + From, T5: CheckedSub, T: From, { self.compute_divide_(max_from, divided, divider, exit, false, false) } pub fn compute_percentage( &mut self, max_from: I, divided: &impl AnyIterableVec, divider: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T2: StoredType + Mul, T3: StoredType, T4: Div + From, T5: CheckedSub, T: From, { self.compute_divide_(max_from, divided, divider, exit, true, false) } pub fn compute_percentage_difference( &mut self, max_from: I, divided: &impl AnyIterableVec, divider: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T2: StoredType + Mul, T3: StoredType, T4: Div + From, T5: CheckedSub, T: From, { self.compute_divide_(max_from, divided, divider, exit, true, true) } pub fn compute_divide_( &mut self, max_from: I, divided: &impl AnyIterableVec, divider: &impl AnyIterableVec, exit: &Exit, as_percentage: bool, as_difference: bool, ) -> Result<()> where T2: StoredType + Mul, T3: StoredType, T4: Div + From, T5: CheckedSub, T: From, { self.validate_computed_version_or_reset_file( Version::ONE + self.0.version() + divided.version() + divider.version(), )?; let index = max_from.min(I::from(self.len())); let multiplier = if as_percentage { 100 } else { 1 }; let mut divider_iter = divider.iter(); divided.iter_at(index).try_for_each(|(i, divided)| { let divided = divided.into_inner(); let divider = divider_iter.unwrap_get_inner(i); let v = if as_percentage { divided * multiplier } else { T4::from(divided) }; let mut v = v / divider; if as_difference { v = v.checked_sub(multiplier).unwrap(); } self.forced_push_at(i, T::from(v), exit) })?; self.safe_flush(exit) } pub fn compute_drawdown( &mut self, max_from: I, close: &impl AnyIterableVec>, ath: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: From, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + ath.version() + close.version(), )?; let index = max_from.min(I::from(self.len())); let mut close_iter = close.iter(); ath.iter_at(index).try_for_each(|(i, ath)| { let ath = ath.into_inner(); if ath == Dollars::ZERO { self.forced_push_at(i, T::from(StoredF32::default()), exit) } else { let close = *close_iter.unwrap_get_inner(i); let drawdown = StoredF32::from((*ath - *close) / *ath * -100.0); self.forced_push_at(i, T::from(drawdown), exit) } })?; self.safe_flush(exit) } pub fn compute_inverse_more_to_less( &mut self, max_from: T, other: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where I: StoredType + StoredIndex, T: StoredIndex, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + other.version(), )?; let index = max_from.min( VecIterator::last(self.0.into_iter()).map_or_else(T::default, |(_, v)| v.into_inner()), ); let mut prev_i = None; other.iter_at(index).try_for_each(|(v, i)| -> Result<()> { let i = i.into_inner(); if prev_i.is_some_and(|prev_i| prev_i == i) { return Ok(()); } if self.iter().get_inner(i).is_none_or(|old_v| old_v > v) { self.forced_push_at(i, v, exit)?; } prev_i.replace(i); Ok(()) })?; self.safe_flush(exit) } pub fn compute_inverse_less_to_more( &mut self, max_from: T, first_indexes: &impl AnyIterableVec, indexes_count: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where I: StoredType, T: StoredIndex, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + first_indexes.version() + indexes_count.version(), )?; let mut indexes_count_iter = indexes_count.iter(); let index = max_from.min(T::from(self.len())); first_indexes .iter_at(index) .try_for_each(|(value, first_index)| { let first_index = (first_index).to_usize()?; let count = *indexes_count_iter.unwrap_get_inner(value); (first_index..first_index + count) .try_for_each(|index| self.forced_push_at(I::from(index), value, exit)) })?; self.safe_flush(exit) } pub fn compute_count_from_indexes( &mut self, max_from: I, first_indexes: &impl AnyIterableVec, other_to_else: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: From, T2: StoredType + StoredIndex + Copy + Add + CheckedSub + TryInto + Default, >::Error: error::Error + 'static, T3: StoredType, { let opt: Option bool>> = None; self.compute_filtered_count_from_indexes_(max_from, first_indexes, other_to_else, opt, exit) } pub fn compute_filtered_count_from_indexes( &mut self, max_from: I, first_indexes: &impl AnyIterableVec, other_to_else: &impl AnyIterableVec, filter: F, exit: &Exit, ) -> Result<()> where T: From, T2: StoredType + StoredIndex + Copy + Add + CheckedSub + TryInto + Default, >::Error: error::Error + 'static, T3: StoredType, F: FnMut(T2) -> bool, { self.compute_filtered_count_from_indexes_( max_from, first_indexes, other_to_else, Some(Box::new(filter)), exit, ) } fn compute_filtered_count_from_indexes_( &mut self, max_from: I, first_indexes: &impl AnyIterableVec, other_to_else: &impl AnyIterableVec, mut filter: Option bool + '_>>, exit: &Exit, ) -> Result<()> where T: From, T2: StoredType + StoredIndex + Copy + Add + CheckedSub + TryInto + Default, T3: StoredType, >::Error: error::Error + 'static, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + first_indexes.version() + other_to_else.version(), )?; let mut other_iter = first_indexes.iter(); let index = max_from.min(I::from(self.len())); first_indexes .iter_at(index) .try_for_each(|(i, first_index)| { let end = other_iter .get_inner(i + 1) .map(|v| v.unwrap_to_usize()) .unwrap_or_else(|| other_to_else.len()); let range = first_index.unwrap_to_usize()..end; let count = if let Some(filter) = filter.as_mut() { range.into_iter().filter(|i| filter(T2::from(*i))).count() } else { range.count() }; self.forced_push_at(i, T::from(T2::from(count)), exit) })?; self.safe_flush(exit) } pub fn compute_is_first_ordered( &mut self, max_from: I, self_to_other: &impl AnyIterableVec, other_to_self: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where I: StoredType, T: From, A: StoredIndex + StoredType, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + self_to_other.version() + other_to_self.version(), )?; let mut other_to_self_iter = other_to_self.iter(); let index = max_from.min(I::from(self.len())); self_to_other.iter_at(index).try_for_each(|(i, other)| { self.forced_push_at( i, T::from(other_to_self_iter.unwrap_get_inner(other.into_inner()) == i), exit, ) })?; self.safe_flush(exit) } pub fn compute_sum_from_indexes( &mut self, max_from: I, first_indexes: &impl AnyIterableVec, indexes_count: &impl AnyIterableVec, source: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: From + Add, T2: StoredIndex + StoredType, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + first_indexes.version() + indexes_count.version(), )?; let mut indexes_count_iter = indexes_count.iter(); let mut source_iter = source.iter(); let index = max_from.min(I::from(self.len())); first_indexes .iter_at(index) .try_for_each(|(i, first_index)| { let count = *indexes_count_iter.unwrap_get_inner(i); let first_index = first_index.unwrap_to_usize(); let range = first_index..first_index + count; let mut sum = T::from(0_usize); range.into_iter().for_each(|i| { sum = sum.clone() + source_iter.unwrap_get_inner(T2::from(i)); }); self.forced_push_at(i, sum, exit) })?; self.safe_flush(exit) } pub fn compute_sum_of_others( &mut self, max_from: I, others: &[&impl AnyIterableVec], exit: &Exit, ) -> Result<()> where T: From + Add, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + others.iter().map(|v| v.version()).sum(), )?; if others.is_empty() { unreachable!("others should've length of 1 at least"); } let mut others_iter = others[1..].iter().map(|v| v.iter()).collect::>(); let index = max_from.min(I::from(self.len())); others .first() .unwrap() .iter_at(index) .try_for_each(|(i, v)| { let mut sum = v.into_inner(); others_iter.iter_mut().for_each(|iter| { sum = sum.clone() + iter.unwrap_get_inner(i); }); self.forced_push_at(i, sum, exit) })?; self.safe_flush(exit) } pub fn compute_min_of_others( &mut self, max_from: I, others: &[&impl AnyIterableVec], exit: &Exit, ) -> Result<()> where T: From + Add + Ord, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + others.iter().map(|v| v.version()).sum(), )?; if others.is_empty() { unreachable!("others should've length of 1 at least"); } let mut others_iter = others[1..].iter().map(|v| v.iter()).collect::>(); let index = max_from.min(I::from(self.len())); others .first() .unwrap() .iter_at(index) .try_for_each(|(i, v)| { let min = v.into_inner(); let min = others_iter .iter_mut() .map(|iter| iter.unwrap_get_inner(i)) .min() .map_or(min.clone(), |min2| min.min(min2)); self.forced_push_at(i, min, exit) })?; self.safe_flush(exit) } pub fn compute_max_of_others( &mut self, max_from: I, others: &[&impl AnyIterableVec], exit: &Exit, ) -> Result<()> where T: From + Add + Ord, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + others.iter().map(|v| v.version()).sum(), )?; if others.is_empty() { unreachable!("others should've length of 1 at least"); } let mut others_iter = others[1..].iter().map(|v| v.iter()).collect::>(); let index = max_from.min(I::from(self.len())); others .first() .unwrap() .iter_at(index) .try_for_each(|(i, v)| { let max = v.into_inner(); let max = others_iter .iter_mut() .map(|iter| iter.unwrap_get_inner(i)) .max() .map_or(max.clone(), |max2| max.max(max2)); self.forced_push_at(i, max, exit) })?; self.safe_flush(exit) } pub fn compute_sma( &mut self, max_from: I, source: &impl AnyIterableVec, sma: usize, exit: &Exit, ) -> Result<()> where T: Add + From + Div + From, T2: StoredType, f32: From + From, { self.compute_sma_(max_from, source, sma, exit, None) } pub fn compute_sma_( &mut self, max_from: I, source: &impl AnyIterableVec, sma: usize, exit: &Exit, min_i: Option, ) -> Result<()> where T: Add + From + Div + From, T2: StoredType, f32: From + From, { self.validate_computed_version_or_reset_file( Version::ONE + self.0.version() + source.version(), )?; let index = max_from.min(I::from(self.len())); let mut prev = None; let min_prev_i = min_i.unwrap_or_default().unwrap_to_usize(); let mut other_iter = source.iter(); source.iter_at(index).try_for_each(|(i, value)| { let value = value.into_inner(); if min_i.is_none() || min_i.is_some_and(|min_i| min_i <= i) { if prev.is_none() { let i = i.unwrap_to_usize(); prev.replace(if i > min_prev_i { self.into_iter().unwrap_get_inner_(i - 1) } else { T::from(0.0) }); } let processed_values_count = i.unwrap_to_usize() - min_prev_i + 1; let len = (processed_values_count).min(sma); let value = f32::from(value); let sma = T::from(if processed_values_count > sma { let prev_sum = f32::from(prev.clone().unwrap()) * len as f32; let value_to_subtract = f32::from( other_iter.unwrap_get_inner_(i.unwrap_to_usize().checked_sub(sma).unwrap()), ); (prev_sum - value_to_subtract + value) / len as f32 } else { (f32::from(prev.clone().unwrap()) * (len - 1) as f32 + value) / len as f32 }); prev.replace(sma.clone()); self.forced_push_at(i, sma, exit) } else { self.forced_push_at(i, T::from(f32::NAN), exit) } })?; self.safe_flush(exit) } pub fn compute_previous_value( &mut self, max_from: I, source: &impl AnyIterableVec, len: usize, exit: &Exit, ) -> Result<()> where I: CheckedSub, T2: StoredType + Default, f32: From, T: From, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + source.version(), )?; let index = max_from.min(I::from(self.len())); let mut source_iter = source.iter(); (index.to_usize()?..source.len()).try_for_each(|i| { let i = I::from(i); let previous_value = i .checked_sub(I::from(len)) .map(|prev_i| f32::from(source_iter.unwrap_get_inner(prev_i))) .unwrap_or(f32::NAN); self.forced_push_at(i, T::from(previous_value), exit) })?; self.safe_flush(exit) } pub fn compute_change( &mut self, max_from: I, source: &impl AnyIterableVec, len: usize, exit: &Exit, ) -> Result<()> where I: CheckedSub, T: CheckedSub + Default, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + source.version(), )?; let index = max_from.min(I::from(self.len())); let mut source_iter = source.iter(); source.iter_at(index).try_for_each(|(i, current)| { let current = current.into_inner(); let prev = i .checked_sub(I::from(len)) .map(|prev_i| source_iter.unwrap_get_inner(prev_i)) .unwrap_or_default(); self.forced_push_at(i, current.checked_sub(prev).unwrap(), exit) })?; self.safe_flush(exit) } pub fn compute_percentage_change( &mut self, max_from: I, source: &impl AnyIterableVec, len: usize, exit: &Exit, ) -> Result<()> where I: CheckedSub, T2: StoredType + Default, f32: From, T: From, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + source.version(), )?; let index = max_from.min(I::from(self.len())); let mut source_iter = source.iter(); source.iter_at(index).try_for_each(|(i, b)| { let previous_value = f32::from( i.checked_sub(I::from(len)) .map(|prev_i| source_iter.unwrap_get_inner(prev_i)) .unwrap_or_default(), ); let last_value = f32::from(b.into_inner()); let percentage_change = ((last_value / previous_value) - 1.0) * 100.0; self.forced_push_at(i, T::from(percentage_change), exit) })?; self.safe_flush(exit) } pub fn compute_cagr( &mut self, max_from: I, percentage_returns: &impl AnyIterableVec, days: usize, exit: &Exit, ) -> Result<()> where I: CheckedSub, T2: StoredType + Default, f32: From, T: From, { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + percentage_returns.version(), )?; if days % 365 != 0 { panic!("bad days"); } let years = days / 365; let index = max_from.min(I::from(self.len())); percentage_returns .iter_at(index) .try_for_each(|(i, percentage)| { let percentage = percentage.into_inner(); let cagr = (((f32::from(percentage) / 100.0 + 1.0).powf(1.0 / years as f32)) - 1.0) * 100.0; self.forced_push_at(i, T::from(cagr), exit) })?; self.safe_flush(exit) } pub fn compute_zscore( &mut self, max_from: I, ratio: &impl AnyIterableVec, sma: &impl AnyIterableVec, sd: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> where T: From, { let mut sma_iter = sma.iter(); let mut sd_iter = sd.iter(); self.compute_transform( max_from, ratio, |(i, ratio, ..)| { let sma = sma_iter.unwrap_get_inner(i); let sd = sd_iter.unwrap_get_inner(i); (i, T::from((ratio - sma) / sd)) }, exit, ) } } impl EagerVec { pub fn compute_dca_stack_via_len( &mut self, max_from: DateIndex, closes: &impl AnyIterableVec>, len: usize, exit: &Exit, ) -> Result<()> { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + closes.version(), )?; let mut other_iter = closes.iter(); let mut prev = None; let index = max_from.min(DateIndex::from(self.len())); closes.iter_at(index).try_for_each(|(i, closes)| { let price = *closes.into_inner(); let i_usize = i.unwrap_to_usize(); if prev.is_none() { if i_usize == 0 { prev.replace(Sats::ZERO); } else { prev.replace(self.into_iter().unwrap_get_inner_(i_usize - 1)); } } let mut stack = Sats::ZERO; if price != Dollars::ZERO { stack = prev.unwrap() + Sats::from(Bitcoin::from(DCA_AMOUNT / price)); if i_usize >= len { let prev_price = *other_iter.unwrap_get_inner_(i_usize - len); if prev_price != Dollars::ZERO { stack = stack .checked_sub(Sats::from(Bitcoin::from(DCA_AMOUNT / prev_price))) .unwrap(); } } } prev.replace(stack); self.forced_push_at(i, stack, exit) })?; self.safe_flush(exit) } pub fn compute_dca_stack_via_from( &mut self, max_from: DateIndex, closes: &impl AnyIterableVec>, from: DateIndex, exit: &Exit, ) -> Result<()> { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + closes.version(), )?; let mut prev = None; let index = max_from.min(DateIndex::from(self.len())); closes.iter_at(index).try_for_each(|(i, closes)| { let price = *closes.into_inner(); let i_usize = i.unwrap_to_usize(); if prev.is_none() { if i_usize == 0 { prev.replace(Sats::ZERO); } else { prev.replace(self.into_iter().unwrap_get_inner_(i_usize - 1)); } } let mut stack = Sats::ZERO; if price != Dollars::ZERO && i >= from { stack = prev.unwrap() + Sats::from(Bitcoin::from(DCA_AMOUNT / price)); } prev.replace(stack); self.forced_push_at(i, stack, exit) })?; self.safe_flush(exit) } } impl EagerVec { pub fn compute_dca_avg_price_via_len( &mut self, max_from: DateIndex, stacks: &impl AnyIterableVec, len: usize, exit: &Exit, ) -> Result<()> { self.validate_computed_version_or_reset_file( Version::ONE + self.0.version() + stacks.version(), )?; let index = max_from.min(DateIndex::from(self.len())); let first_price_date = DateIndex::try_from(Date::new(2010, 7, 12)).unwrap(); stacks.iter_at(index).try_for_each(|(i, stack)| { let stack = stack.into_inner(); let mut avg_price = Dollars::from(f64::NAN); if i > first_price_date { avg_price = DCA_AMOUNT * len .min(i.unwrap_to_usize() + 1) .min(i.checked_sub(first_price_date).unwrap().unwrap_to_usize() + 1) / Bitcoin::from(stack); } self.forced_push_at(i, avg_price, exit) })?; self.safe_flush(exit) } pub fn compute_dca_avg_price_via_from( &mut self, max_from: DateIndex, stacks: &impl AnyIterableVec, from: DateIndex, exit: &Exit, ) -> Result<()> { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + stacks.version(), )?; let index = max_from.min(DateIndex::from(self.len())); let from_usize = from.unwrap_to_usize(); stacks.iter_at(index).try_for_each(|(i, stack)| { let stack = stack.into_inner(); let mut avg_price = Dollars::from(f64::NAN); if i >= from { avg_price = DCA_AMOUNT * (i.unwrap_to_usize() + 1 - from_usize) / Bitcoin::from(stack); } self.forced_push_at(i, avg_price, exit) })?; self.safe_flush(exit) } } impl EagerVec where I: StoredIndex, { pub fn compute_from_sats( &mut self, max_from: I, sats: &impl AnyIterableVec, exit: &Exit, ) -> Result<()> { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + sats.version(), )?; let index = max_from.min(I::from(self.len())); sats.iter_at(index).try_for_each(|(i, sats)| { let (i, v) = (i, Bitcoin::from(sats.into_inner())); self.forced_push_at(i, v, exit) })?; self.safe_flush(exit) } } impl EagerVec where I: StoredIndex, { pub fn compute_from_bitcoin( &mut self, max_from: I, bitcoin: &impl AnyIterableVec, price: &impl AnyIterableVec>, exit: &Exit, ) -> Result<()> { self.validate_computed_version_or_reset_file( Version::ZERO + self.0.version() + bitcoin.version(), )?; let mut price_iter = price.iter(); let index = max_from.min(I::from(self.len())); bitcoin.iter_at(index).try_for_each(|(i, bitcoin)| { let dollars = price_iter.unwrap_get_inner(i); let (i, v) = (i, *dollars * bitcoin.into_inner()); self.forced_push_at(i, v, exit) })?; self.safe_flush(exit) } } // impl EagerVec { // pub fn compute_txindex_from_bitcoin( // &mut self, // max_from: TxIndex, // bitcoin: &impl AnyIterableVec, // i_to_height: &impl AnyIterableVec, // price: &impl AnyIterableVec>, // exit: &Exit, // ) -> Result<()> { // self.validate_computed_version_or_reset_file( // Version::ZERO // + self.0.version() // + bitcoin.version() // + i_to_height.version() // + price.version(), // )?; // let mut i_to_height_iter = i_to_height.iter(); // let mut price_iter = price.iter(); // let index = max_from.min(TxIndex::from(self.len())); // bitcoin.iter_at(index).try_for_each(|(i, bitcoin, ..)| { // let height = i_to_height_iter.unwrap_get_inner(i); // let dollars = price_iter.unwrap_get_inner(height); // let (i, v) = (i, *dollars * bitcoin.into_inner()); // self.forced_push_at(i, v, exit) // })?; // self.safe_flush(exit) // } // } impl<'a, I, T> IntoIterator for &'a EagerVec where I: StoredIndex, T: StoredType, { type Item = (I, Value<'a, T>); type IntoIter = StoredVecIterator<'a, I, T>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl AnyVec for EagerVec where I: StoredIndex, T: StoredType, { #[inline] fn version(&self) -> Version { self.0.header().computed_version() } #[inline] fn name(&self) -> &str { self.0.name() } #[inline] fn len(&self) -> usize { self.0.len() } #[inline] fn modified_time(&self) -> Result { self.0.modified_time() } #[inline] fn index_type_to_string(&self) -> &'static str { I::to_string() } #[inline] fn value_type_to_size_of(&self) -> usize { size_of::() } } impl AnyIterableVec for EagerVec where I: StoredIndex, T: StoredType, { fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> where I: StoredIndex, T: StoredType + 'a, { Box::new(self.0.into_iter()) } } impl AnyCollectableVec for EagerVec where I: StoredIndex, T: StoredType, { fn collect_range_serde_json( &self, from: Option, to: Option, ) -> Result> { CollectableVec::collect_range_serde_json(self, from, to) } }