global: MASSIVE snapshot

This commit is contained in:
nym21
2026-01-07 01:16:37 +01:00
parent e832ffbe23
commit cb0abc324e
487 changed files with 21155 additions and 13627 deletions
+334
View File
@@ -0,0 +1,334 @@
use brk_error::Result;
use brk_types::{Bitcoin, CheckedSub, Close, Date, DateIndex, Dollars, Sats, StoredF32};
use vecdb::{
AnyStoredVec, AnyVec, EagerVec, Exit, GenericStoredVec, IterableVec, PcoVec, VecIndex, Version,
};
mod pricing;
// TODO: Re-export when Phase 3 (Pricing migration) is complete
// pub use pricing::{Priced, Pricing, Unpriced};
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
pub trait ComputeDCAStackViaLen {
fn compute_dca_stack_via_len(
&mut self,
max_from: DateIndex,
closes: &impl IterableVec<DateIndex, Close<Dollars>>,
len: usize,
exit: &Exit,
) -> Result<()>;
fn compute_dca_stack_via_from(
&mut self,
max_from: DateIndex,
closes: &impl IterableVec<DateIndex, Close<Dollars>>,
from: DateIndex,
exit: &Exit,
) -> Result<()>;
}
impl ComputeDCAStackViaLen for EagerVec<PcoVec<DateIndex, Sats>> {
fn compute_dca_stack_via_len(
&mut self,
max_from: DateIndex,
closes: &impl IterableVec<DateIndex, Close<Dollars>>,
len: usize,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset(closes.version())?;
let index = max_from.to_usize().min(self.len());
// Initialize prev before the loop to avoid checking on every iteration
let mut prev = if index == 0 {
Sats::ZERO
} else {
self.read_at_unwrap_once(index - 1)
};
let mut lookback = closes.create_lookback(index, len, 0);
closes
.iter()
.enumerate()
.skip(index)
.try_for_each(|(i, closes)| {
let price = *closes;
let i_usize = i.to_usize();
let mut stack = Sats::ZERO;
if price != Dollars::ZERO {
stack = prev + Sats::from(Bitcoin::from(DCA_AMOUNT / price));
let prev_price =
*lookback.get_and_push(i_usize, Close::new(price), Close::default());
if prev_price != Dollars::ZERO {
stack = stack
.checked_sub(Sats::from(Bitcoin::from(DCA_AMOUNT / prev_price)))
.unwrap();
}
}
prev = stack;
self.truncate_push_at(i, stack)
})?;
let _lock = exit.lock();
self.write()?;
Ok(())
}
fn compute_dca_stack_via_from(
&mut self,
max_from: DateIndex,
closes: &impl IterableVec<DateIndex, Close<Dollars>>,
from: DateIndex,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset(closes.version())?;
let from = from.to_usize();
let index = max_from.min(DateIndex::from(self.len()));
// Initialize prev before the loop to avoid checking on every iteration
let mut prev = if index.to_usize() == 0 {
Sats::ZERO
} else {
self.read_at_unwrap_once(index.to_usize() - 1)
};
closes
.iter()
.enumerate()
.skip(index.to_usize())
.try_for_each(|(i, closes)| {
let price = *closes;
let mut stack = Sats::ZERO;
if price != Dollars::ZERO && i >= from {
stack = prev + Sats::from(Bitcoin::from(DCA_AMOUNT / price));
}
prev = stack;
self.truncate_push_at(i, stack)
})?;
let _lock = exit.lock();
self.write()?;
Ok(())
}
}
pub trait ComputeDCAAveragePriceViaLen {
fn compute_dca_average_price_via_len(
&mut self,
max_from: DateIndex,
stacks: &impl IterableVec<DateIndex, Sats>,
len: usize,
exit: &Exit,
) -> Result<()>;
fn compute_dca_average_price_via_from(
&mut self,
max_from: DateIndex,
stacks: &impl IterableVec<DateIndex, Sats>,
from: DateIndex,
exit: &Exit,
) -> Result<()>;
}
impl ComputeDCAAveragePriceViaLen for EagerVec<PcoVec<DateIndex, Dollars>> {
fn compute_dca_average_price_via_len(
&mut self,
max_from: DateIndex,
stacks: &impl IterableVec<DateIndex, Sats>,
len: usize,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset(Version::ONE + stacks.version())?;
let index = max_from.min(DateIndex::from(self.len()));
let first_price_date = DateIndex::try_from(Date::new(2010, 7, 12))
.unwrap()
.to_usize();
stacks
.iter()
.enumerate()
.skip(index.to_usize())
.try_for_each(|(i, stack)| {
let mut average_price = Dollars::from(f64::NAN);
if i > first_price_date {
average_price = DCA_AMOUNT
* len
.min(i.to_usize() + 1)
.min(i.checked_sub(first_price_date).unwrap().to_usize() + 1)
/ Bitcoin::from(stack);
}
self.truncate_push_at(i, average_price)
})?;
let _lock = exit.lock();
self.write()?;
Ok(())
}
fn compute_dca_average_price_via_from(
&mut self,
max_from: DateIndex,
stacks: &impl IterableVec<DateIndex, Sats>,
from: DateIndex,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset(stacks.version())?;
let index = max_from.min(DateIndex::from(self.len()));
let from = from.to_usize();
stacks
.iter()
.enumerate()
.skip(index.to_usize())
.try_for_each(|(i, stack)| {
let mut average_price = Dollars::from(f64::NAN);
if i >= from {
average_price = DCA_AMOUNT * (i.to_usize() + 1 - from) / Bitcoin::from(stack);
}
self.truncate_push_at(i, average_price)
})?;
let _lock = exit.lock();
self.write()?;
Ok(())
}
}
pub trait ComputeLumpSumStackViaLen {
fn compute_lump_sum_stack_via_len(
&mut self,
max_from: DateIndex,
closes: &impl IterableVec<DateIndex, Close<Dollars>>,
lookback_prices: &impl IterableVec<DateIndex, Dollars>,
len: usize,
exit: &Exit,
) -> Result<()>;
}
impl ComputeLumpSumStackViaLen for EagerVec<PcoVec<DateIndex, Sats>> {
/// Compute lump sum stack: sats you would have if you invested (len * DCA_AMOUNT) at the lookback price
fn compute_lump_sum_stack_via_len(
&mut self,
max_from: DateIndex,
closes: &impl IterableVec<DateIndex, Close<Dollars>>,
lookback_prices: &impl IterableVec<DateIndex, Dollars>,
len: usize,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset(closes.version())?;
let index = max_from.to_usize().min(self.len());
let total_invested = DCA_AMOUNT * len;
lookback_prices
.iter()
.enumerate()
.skip(index)
.try_for_each(|(i, lookback_price)| {
let stack = if lookback_price == Dollars::ZERO {
Sats::ZERO
} else {
Sats::from(Bitcoin::from(total_invested / lookback_price))
};
self.truncate_push_at(i, stack)
})?;
let _lock = exit.lock();
self.write()?;
Ok(())
}
}
pub trait ComputeFromBitcoin<I> {
fn compute_from_bitcoin(
&mut self,
max_from: I,
bitcoin: &impl IterableVec<I, Bitcoin>,
price: &impl IterableVec<I, Close<Dollars>>,
exit: &Exit,
) -> Result<()>;
}
impl<I> ComputeFromBitcoin<I> for EagerVec<PcoVec<I, Dollars>>
where
I: VecIndex,
{
fn compute_from_bitcoin(
&mut self,
max_from: I,
bitcoin: &impl IterableVec<I, Bitcoin>,
price: &impl IterableVec<I, Close<Dollars>>,
exit: &Exit,
) -> Result<()> {
self.compute_transform2(
max_from,
bitcoin,
price,
|(i, bitcoin, price, _)| (i, *price * bitcoin),
exit,
)?;
Ok(())
}
}
pub trait ComputeDrawdown<I> {
fn compute_drawdown(
&mut self,
max_from: I,
close: &impl IterableVec<I, Close<Dollars>>,
ath: &impl IterableVec<I, Dollars>,
exit: &Exit,
) -> Result<()>;
}
impl<I> ComputeDrawdown<I> for EagerVec<PcoVec<I, StoredF32>>
where
I: VecIndex,
{
fn compute_drawdown(
&mut self,
max_from: I,
close: &impl IterableVec<I, Close<Dollars>>,
ath: &impl IterableVec<I, Dollars>,
exit: &Exit,
) -> Result<()> {
self.compute_transform2(
max_from,
ath,
close,
|(i, ath, close, _)| {
if ath == Dollars::ZERO {
(i, StoredF32::default())
} else {
let drawdown = StoredF32::from((*ath - **close) / *ath * -100.0);
(i, drawdown)
}
},
exit,
)?;
Ok(())
}
}
+123
View File
@@ -0,0 +1,123 @@
//! Compile-time type-state for price-dependent data.
//!
// TODO: Remove this once Phase 3 (Pricing migration) is complete
#![allow(dead_code)]
//!
//! This module provides the `Pricing` trait which enables compile-time
//! differentiation between priced and unpriced data variants. Instead of
//! using `Option<T>` for price-dependent fields, structs use `P: Pricing`
//! with associated types that are either concrete types (for `Priced`) or
//! `()` (for `Unpriced`).
//!
//! Benefits:
//! - LSP/autocomplete visibility: no Options cluttering suggestions
//! - Compile-time guarantees: cannot access price data on `Unpriced` variants
//! - Zero runtime overhead: `()` is a ZST (zero-sized type)
use brk_traversable::Traversable;
/// Type-state trait for price-dependent data.
///
/// Implements the type-state pattern using associated types:
/// - `Priced`: associated types resolve to concrete data types
/// - `Unpriced`: associated types resolve to `()`
///
/// # Associated Types
///
/// | Type | Usage | Priced | Unpriced |
/// |------|-------|--------|----------|
/// | `Data` | Computer top-level | `PricingData` | `()` |
/// | `PriceRef<'a>` | Function params | `&price::Vecs` | `()` |
/// | `ComputedDollarsHeight` | Value wrappers (Height) | `ComputedBlock<Dollars>` | `()` |
/// | `ComputedDollarsDateIndex` | Value wrappers (DateIndex) | `ComputedVecsDate<Dollars>` | `()` |
/// | `StdDevBandsUsd` | StdDev USD bands | `StdDevBandsUsdData` | `()` |
/// | `RatioUsd` | Ratio USD variants | `RatioUsdData` | `()` |
/// | `BasePriced` | Base metrics | `BasePricedData` | `()` |
/// | `ExtendedPriced` | Extended metrics | `ExtendedPricedData` | `()` |
/// | `AdjustedPriced` | Adjusted metrics | `AdjustedPricedData` | `()` |
/// | `RelToAllPriced` | Rel-to-all metrics | `RelToAllPricedData` | `()` |
pub trait Pricing: 'static + Clone + Send + Sync {
// === Top-level ===
/// Top-level pricing data - PricingData for Priced, () for Unpriced
type Data: Clone + Send + Sync + Traversable;
/// Reference to price vecs for import functions
type PriceRef<'a>: Copy;
// === Value wrappers (used in 20+ places) ===
/// Computed dollars with Height index
type ComputedDollarsHeight: Clone + Send + Sync + Traversable;
/// Computed dollars with DateIndex index
type ComputedDollarsDateIndex: Clone + Send + Sync + Traversable;
// === Specialized structs ===
/// StdDev USD bands (13 fields grouped)
type StdDevBandsUsd: Clone + Send + Sync + Traversable;
/// Ratio USD data
type RatioUsd: Clone + Send + Sync + Traversable;
// === Distribution metrics ===
/// Base-level priced metrics (realized + unrealized)
type BasePriced: Clone + Send + Sync + Traversable;
/// Extended-level priced metrics
type ExtendedPriced: Clone + Send + Sync + Traversable;
/// Adjusted metrics
type AdjustedPriced: Clone + Send + Sync + Traversable;
/// Dollar-based relative-to-all metrics
type RelToAllPriced: Clone + Send + Sync + Traversable;
}
/// Marker type for priced data.
///
/// When `P = Priced`, all associated types resolve to their concrete
/// data types containing price-denominated values.
#[derive(Clone, Copy, Default, Debug)]
pub struct Priced;
/// Marker type for unpriced data.
///
/// When `P = Unpriced`, all associated types resolve to `()`,
/// effectively removing those fields at compile time with zero overhead.
#[derive(Clone, Copy, Default, Debug)]
pub struct Unpriced;
// Note: The actual type implementations for `Priced` and `Unpriced`
// will be added in Phase 3 when we migrate the concrete data types.
// For now, we provide placeholder implementations using () for all types
// to allow incremental migration.
impl Pricing for Priced {
// Placeholder implementations - will be replaced with concrete types in Phase 3
type Data = ();
type PriceRef<'a> = ();
type ComputedDollarsHeight = ();
type ComputedDollarsDateIndex = ();
type StdDevBandsUsd = ();
type RatioUsd = ();
type BasePriced = ();
type ExtendedPriced = ();
type AdjustedPriced = ();
type RelToAllPriced = ();
}
impl Pricing for Unpriced {
type Data = ();
type PriceRef<'a> = ();
type ComputedDollarsHeight = ();
type ComputedDollarsDateIndex = ();
type StdDevBandsUsd = ();
type RatioUsd = ();
type BasePriced = ();
type ExtendedPriced = ();
type AdjustedPriced = ();
type RelToAllPriced = ();
}