global: snapshot

This commit is contained in:
nym21
2026-01-31 17:39:48 +01:00
parent 8dd350264a
commit ff5bb770d7
116 changed files with 13312 additions and 9530 deletions

View File

@@ -10,7 +10,7 @@ use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom
use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightSum, ComputedFromDateLast, ComputedVecValue,
LazyBinaryComputedFromHeightLast, LazyBinaryComputedFromHeightSum, LazyBinaryTransformLast,
LazyDateDerivedLast, LazyDateDerivedSumCum, NumericValue,
LazyDateDerivedLast, LazyDateDerivedSumCum, LazyFromDateLast, LazyFromHeightLast, NumericValue,
};
const VERSION: Version = Version::ZERO;
@@ -223,6 +223,45 @@ where
}
}
pub fn from_lazy_height_and_dateindex_last<F, S1SourceT>(
name: &str,
version: Version,
source1: &LazyFromHeightLast<S1T, S1SourceT>,
source2: &ComputedFromDateLast<S2T>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_vecs::<F>(
name,
v,
source1.$p.boxed_clone(),
source2.$p.boxed_clone(),
)
};
}
Self {
dateindex: LazyVecFrom2::transformed::<F>(
name,
v,
source1.dateindex.boxed_clone(),
source2.dateindex.boxed_clone(),
),
weekindex: period!(weekindex),
monthindex: period!(monthindex),
quarterindex: period!(quarterindex),
semesterindex: period!(semesterindex),
yearindex: period!(yearindex),
decadeindex: period!(decadeindex),
}
}
pub fn from_dateindex_and_height_last<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
@@ -753,4 +792,44 @@ where
decadeindex: period!(decadeindex),
}
}
/// Create from a ComputedFromDateLast and a LazyFromDateLast.
pub fn from_computed_and_lazy_last<F, S2SourceT>(
name: &str,
version: Version,
source1: &ComputedFromDateLast<S1T>,
source2: &LazyFromDateLast<S2T, S2SourceT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S2SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_vecs::<F>(
name,
v,
source1.rest.$p.boxed_clone(),
source2.$p.boxed_clone(),
)
};
}
Self {
dateindex: LazyVecFrom2::transformed::<F>(
name,
v,
source1.dateindex.boxed_clone(),
source2.dateindex.boxed_clone(),
),
weekindex: period!(weekindex),
monthindex: period!(monthindex),
quarterindex: period!(quarterindex),
semesterindex: period!(semesterindex),
yearindex: period!(yearindex),
decadeindex: period!(decadeindex),
}
}
}

View File

@@ -58,4 +58,37 @@ where
decadeindex: period!(decadeindex),
}
}
/// Create from two LazyBinaryFromDateSum sources.
pub fn from_binary<F, S1aT, S1bT, S2aT, S2bT>(
name: &str,
version: Version,
source1: &LazyBinaryFromDateSum<S1T, S1aT, S1bT>,
source2: &LazyBinaryFromDateSum<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformSum::from_boxed::<F>(name, v, source1.$p.boxed_clone(), source2.$p.boxed_clone())
};
}
Self {
dateindex: period!(dateindex),
weekindex: period!(weekindex),
monthindex: period!(monthindex),
quarterindex: period!(quarterindex),
semesterindex: period!(semesterindex),
yearindex: period!(yearindex),
decadeindex: period!(decadeindex),
}
}
}

View File

@@ -10,7 +10,7 @@ use vecdb::{BinaryTransform, IterableCloneableVec};
use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedHeightDerivedLast,
ComputedHeightDerivedSumCum, ComputedVecValue, LazyBinaryTransformSumCum, LazyDateDerivedFull,
LazyDateDerivedSumCum, NumericValue, SumCum,
LazyDateDerivedSumCum, LazyFromHeightLast, NumericValue, SumCum,
};
const VERSION: Version = Version::ZERO;
@@ -278,4 +278,47 @@ where
decadeindex: period!(decadeindex),
}
}
// --- Methods accepting SumCum + LazyLast sources ---
pub fn from_computed_lazy_last<F, S2ST>(
name: &str,
version: Version,
source1: &ComputedFromHeightSumCum<S1T>,
source2: &LazyFromHeightLast<S2T, S2ST>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: PartialOrd,
S2T: NumericValue,
S2ST: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformSumCum::from_sources_last_sum_raw::<F>(
name, v,
source1.rest.$p.sum.boxed_clone(),
source1.rest.$p.cumulative.boxed_clone(),
source2.rest.dates.$p.boxed_clone(),
)
};
}
Self {
dateindex: LazyBinaryTransformSumCum::from_sources_last_sum_raw::<F>(
name, v,
source1.dateindex.boxed_sum(),
source1.dateindex.boxed_cumulative(),
source2.rest.dates.dateindex.boxed_clone(),
),
weekindex: period!(weekindex),
monthindex: period!(monthindex),
quarterindex: period!(quarterindex),
semesterindex: period!(semesterindex),
yearindex: period!(yearindex),
decadeindex: period!(decadeindex),
}
}
}

View File

@@ -10,7 +10,7 @@ use schemars::JsonSchema;
use vecdb::{BinaryTransform, IterableCloneableVec, LazyVecFrom1};
use super::{ComputedFromDateLast, LazyBinaryFromDateLast};
use crate::internal::{ComputedFromHeightLast, ComputedVecValue, DollarsToSatsFract, LazyTransformLast, NumericValue};
use crate::internal::{ComputedFromHeightLast, ComputedVecValue, DollarsToSatsFract, LazyFromHeightLast, LazyTransformLast, NumericValue};
/// Lazy binary price with both USD and sats representations.
///
@@ -71,6 +71,23 @@ where
Self::from_dollars(name, version, dollars)
}
/// Create from lazy height-based price and dateindex-based ratio sources.
pub fn from_lazy_height_and_dateindex_last<F, S1SourceT>(
name: &str,
version: Version,
source1: &LazyFromHeightLast<S1T, S1SourceT>,
source2: &ComputedFromDateLast<S2T>,
) -> Self
where
F: BinaryTransform<S1T, S2T, Dollars>,
S1SourceT: ComputedVecValue + JsonSchema,
{
let dollars = LazyBinaryFromDateLast::from_lazy_height_and_dateindex_last::<F, S1SourceT>(
name, version, source1, source2,
);
Self::from_dollars(name, version, dollars)
}
/// Create from two computed dateindex sources.
pub fn from_computed_both_last<F: BinaryTransform<S1T, S2T, Dollars>>(
name: &str,

View File

@@ -1,6 +1,6 @@
use brk_error::Result;
use brk_traversable::{Traversable, TreeNode};
use brk_types::{DateIndex, Dollars, Version};
use brk_types::{DateIndex, Dollars, StoredF32, Version};
use rayon::prelude::*;
use vecdb::{
AnyExportableVec, AnyStoredVec, AnyVec, Database, EagerVec, Exit, GenericStoredVec, PcoVec,
@@ -15,28 +15,77 @@ pub const PERCENTILES: [u8; 19] = [
];
pub const PERCENTILES_LEN: usize = PERCENTILES.len();
/// Compute spot percentile rank by interpolating within percentile bands.
/// Returns a value between 0 and 100 indicating where spot sits in the distribution.
pub fn compute_spot_percentile_rank(percentile_prices: &[Dollars; PERCENTILES_LEN], spot: Dollars) -> StoredF32 {
if spot.is_nan() || percentile_prices[0].is_nan() {
return StoredF32::NAN;
}
let spot_f64 = f64::from(spot);
// Below lowest percentile (p5) - extrapolate towards 0
let p5 = f64::from(percentile_prices[0]);
if spot_f64 <= p5 {
if p5 == 0.0 {
return StoredF32::from(0.0);
}
// Linear extrapolation: rank = 5 * (spot / p5)
return StoredF32::from((5.0 * spot_f64 / p5).max(0.0));
}
// Above highest percentile (p95) - extrapolate towards 100
let p95 = f64::from(percentile_prices[PERCENTILES_LEN - 1]);
let p90 = f64::from(percentile_prices[PERCENTILES_LEN - 2]);
if spot_f64 >= p95 {
if p95 == p90 {
return StoredF32::from(100.0);
}
// Linear extrapolation using p90-p95 slope
let slope = 5.0 / (p95 - p90);
return StoredF32::from((95.0 + (spot_f64 - p95) * slope).min(100.0));
}
// Find the band containing spot and interpolate
for i in 0..PERCENTILES_LEN - 1 {
let lower = f64::from(percentile_prices[i]);
let upper = f64::from(percentile_prices[i + 1]);
if spot_f64 >= lower && spot_f64 <= upper {
let lower_pct = f64::from(PERCENTILES[i]);
let upper_pct = f64::from(PERCENTILES[i + 1]);
if upper == lower {
return StoredF32::from(lower_pct);
}
// Linear interpolation
let ratio = (spot_f64 - lower) / (upper - lower);
return StoredF32::from(lower_pct + ratio * (upper_pct - lower_pct));
}
}
StoredF32::NAN
}
#[derive(Clone)]
pub struct CostBasisPercentiles {
pub struct PercentilesVecs {
pub vecs: [Option<Price>; PERCENTILES_LEN],
}
const VERSION: Version = Version::ZERO;
impl CostBasisPercentiles {
impl PercentilesVecs {
pub fn forced_import(
db: &Database,
name: &str,
prefix: &str,
version: Version,
indexes: &indexes::Vecs,
compute: bool,
) -> Result<Self> {
let vecs = PERCENTILES.map(|p| {
compute.then(|| {
let metric_name = if name.is_empty() {
format!("cost_basis_pct{p:02}")
} else {
format!("{name}_cost_basis_pct{p:02}")
};
let metric_name = format!("{prefix}_pct{p:02}");
Price::forced_import(db, &metric_name, version + VERSION, indexes).unwrap()
})
});
@@ -88,7 +137,7 @@ impl CostBasisPercentiles {
}
}
impl CostBasisPercentiles {
impl PercentilesVecs {
pub fn write(&mut self) -> Result<()> {
for vec in self.vecs.iter_mut().flatten() {
vec.dateindex.write()?;
@@ -115,7 +164,7 @@ impl CostBasisPercentiles {
}
}
impl Traversable for CostBasisPercentiles {
impl Traversable for PercentilesVecs {
fn to_tree_node(&self) -> TreeNode {
TreeNode::Branch(
PERCENTILES

View File

@@ -17,7 +17,8 @@ use crate::{
};
use super::{ComputedFromDateLast, Price};
use crate::internal::ComputedFromHeightLast;
use crate::internal::{ComputedFromHeightLast, ComputedVecValue, LazyFromHeightLast};
use schemars::JsonSchema;
#[derive(Clone, Traversable)]
pub struct ComputedFromDateRatio {
@@ -56,7 +57,6 @@ impl ComputedFromDateRatio {
version: Version,
indexes: &indexes::Vecs,
extended: bool,
price_vecs: Option<&price::Vecs>,
) -> Result<Self> {
let v = version + VERSION;
@@ -81,7 +81,8 @@ impl ComputedFromDateRatio {
v,
indexes,
StandardDeviationVecsOptions::default().add_all(),
price_vecs,
metric_price,
price.as_ref().map(|p| &p.dollars),
)
.unwrap()
};
@@ -142,6 +143,82 @@ impl ComputedFromDateRatio {
})
}
pub fn forced_import_from_lazy<S1T: ComputedVecValue + JsonSchema>(
db: &Database,
name: &str,
metric_price: &LazyFromHeightLast<Dollars, S1T>,
version: Version,
indexes: &indexes::Vecs,
extended: bool,
) -> Result<Self> {
let v = version + VERSION;
macro_rules! import {
($suffix:expr) => {
ComputedFromDateLast::forced_import(db, &format!("{name}_{}", $suffix), v, indexes)
.unwrap()
};
}
macro_rules! import_sd {
($suffix:expr, $days:expr) => {
ComputedFromDateStdDev::forced_import_from_lazy(
db,
&format!("{name}_{}", $suffix),
$days,
v,
indexes,
StandardDeviationVecsOptions::default().add_all(),
Some(metric_price),
)
.unwrap()
};
}
let ratio_pct99 = extended.then(|| import!("ratio_pct99"));
let ratio_pct98 = extended.then(|| import!("ratio_pct98"));
let ratio_pct95 = extended.then(|| import!("ratio_pct95"));
let ratio_pct5 = extended.then(|| import!("ratio_pct5"));
let ratio_pct2 = extended.then(|| import!("ratio_pct2"));
let ratio_pct1 = extended.then(|| import!("ratio_pct1"));
macro_rules! lazy_usd {
($ratio:expr, $suffix:expr) => {
$ratio.as_ref().map(|r| {
LazyBinaryPrice::from_lazy_height_and_dateindex_last::<PriceTimesRatio, S1T>(
&format!("{name}_{}", $suffix),
v,
metric_price,
r,
)
})
};
}
Ok(Self {
ratio: import!("ratio"),
ratio_1w_sma: extended.then(|| import!("ratio_1w_sma")),
ratio_1m_sma: extended.then(|| import!("ratio_1m_sma")),
ratio_sd: extended.then(|| import_sd!("ratio", usize::MAX)),
ratio_1y_sd: extended.then(|| import_sd!("ratio_1y", 365)),
ratio_2y_sd: extended.then(|| import_sd!("ratio_2y", 2 * 365)),
ratio_4y_sd: extended.then(|| import_sd!("ratio_4y", 4 * 365)),
ratio_pct99_usd: lazy_usd!(&ratio_pct99, "ratio_pct99_usd"),
ratio_pct98_usd: lazy_usd!(&ratio_pct98, "ratio_pct98_usd"),
ratio_pct95_usd: lazy_usd!(&ratio_pct95, "ratio_pct95_usd"),
ratio_pct5_usd: lazy_usd!(&ratio_pct5, "ratio_pct5_usd"),
ratio_pct2_usd: lazy_usd!(&ratio_pct2, "ratio_pct2_usd"),
ratio_pct1_usd: lazy_usd!(&ratio_pct1, "ratio_pct1_usd"),
price: None,
ratio_pct99,
ratio_pct98,
ratio_pct95,
ratio_pct5,
ratio_pct2,
ratio_pct1,
})
}
pub fn compute_all<F>(
&mut self,
price: &price::Vecs,

View File

@@ -2,15 +2,19 @@ use std::mem;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Close, Date, DateIndex, Dollars, StoredF32, Version};
use brk_types::{Date, DateIndex, Dollars, StoredF32, Version};
use schemars::JsonSchema;
use vecdb::{
AnyStoredVec, AnyVec, CollectableVec, Database, EagerVec, Exit, GenericStoredVec, IterableVec,
PcoVec, VecIndex,
};
use crate::{ComputeIndexes, indexes, price};
use crate::{ComputeIndexes, indexes};
use crate::internal::{ClosePriceTimesRatio, ComputedFromDateLast, LazyBinaryPrice};
use crate::internal::{
ComputedFromDateLast, ComputedFromHeightLast, ComputedVecValue, LazyBinaryPrice,
LazyFromHeightLast, PriceTimesRatio,
};
#[derive(Clone, Traversable)]
pub struct ComputedFromDateStdDev {
@@ -35,19 +39,19 @@ pub struct ComputedFromDateStdDev {
pub m2_5sd: Option<ComputedFromDateLast<StoredF32>>,
pub m3sd: Option<ComputedFromDateLast<StoredF32>>,
pub _0sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub p0_5sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub p1sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub p1_5sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub p2sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub p2_5sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub p3sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub m0_5sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub m1sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub m1_5sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub m2sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub m2_5sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub m3sd_usd: Option<LazyBinaryPrice<Close<Dollars>, StoredF32>>,
pub _0sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub p0_5sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub p1sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub p1_5sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub p2sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub p2_5sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub p3sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub m0_5sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub m1sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub m1_5sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub m2sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub m2_5sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
pub m3sd_usd: Option<LazyBinaryPrice<Dollars, StoredF32>>,
}
#[derive(Debug, Default)]
@@ -103,9 +107,10 @@ impl ComputedFromDateStdDev {
parent_version: Version,
indexes: &indexes::Vecs,
options: StandardDeviationVecsOptions,
price_vecs: Option<&price::Vecs>,
metric_price: Option<&ComputedFromHeightLast<Dollars>>,
date_price: Option<&ComputedFromDateLast<Dollars>>,
) -> Result<Self> {
let version = parent_version + Version::ONE;
let version = parent_version + Version::TWO;
macro_rules! import {
($suffix:expr) => {
@@ -133,20 +138,33 @@ impl ComputedFromDateStdDev {
let m2_5sd = options.bands().then(|| import!("m2_5sd"));
let m3sd = options.bands().then(|| import!("m3sd"));
// Create USD bands using the metric price (the denominator of the ratio).
// This converts ratio bands back to USD: usd_band = metric_price * ratio_band
macro_rules! lazy_usd {
($band:expr, $suffix:expr) => {
price_vecs
.map(|p| &p.usd.split.close)
.zip($band.as_ref())
.filter(|_| options.price_bands())
.map(|(p, b)| {
LazyBinaryPrice::from_computed_both_last::<ClosePriceTimesRatio>(
if !options.price_bands() {
None
} else if let Some(mp) = metric_price {
$band.as_ref().map(|b| {
LazyBinaryPrice::from_height_and_dateindex_last::<PriceTimesRatio>(
&format!("{name}_{}", $suffix),
version,
p,
mp,
b,
)
})
} else if let Some(dp) = date_price {
$band.as_ref().map(|b| {
LazyBinaryPrice::from_computed_both_last::<PriceTimesRatio>(
&format!("{name}_{}", $suffix),
version,
dp,
b,
)
})
} else {
None
}
};
}
@@ -395,4 +413,91 @@ impl ComputedFromDateStdDev {
) -> impl Iterator<Item = &mut EagerVec<PcoVec<DateIndex, StoredF32>>> {
self.mut_stateful_computed().map(|c| &mut c.dateindex)
}
#[allow(clippy::too_many_arguments)]
pub fn forced_import_from_lazy<S1T: ComputedVecValue + JsonSchema>(
db: &Database,
name: &str,
days: usize,
parent_version: Version,
indexes: &indexes::Vecs,
options: StandardDeviationVecsOptions,
metric_price: Option<&LazyFromHeightLast<Dollars, S1T>>,
) -> Result<Self> {
let version = parent_version + Version::TWO;
macro_rules! import {
($suffix:expr) => {
ComputedFromDateLast::forced_import(
db,
&format!("{name}_{}", $suffix),
version,
indexes,
)
.unwrap()
};
}
let sma_vec = Some(import!("sma"));
let p0_5sd = options.bands().then(|| import!("p0_5sd"));
let p1sd = options.bands().then(|| import!("p1sd"));
let p1_5sd = options.bands().then(|| import!("p1_5sd"));
let p2sd = options.bands().then(|| import!("p2sd"));
let p2_5sd = options.bands().then(|| import!("p2_5sd"));
let p3sd = options.bands().then(|| import!("p3sd"));
let m0_5sd = options.bands().then(|| import!("m0_5sd"));
let m1sd = options.bands().then(|| import!("m1sd"));
let m1_5sd = options.bands().then(|| import!("m1_5sd"));
let m2sd = options.bands().then(|| import!("m2sd"));
let m2_5sd = options.bands().then(|| import!("m2_5sd"));
let m3sd = options.bands().then(|| import!("m3sd"));
macro_rules! lazy_usd {
($band:expr, $suffix:expr) => {
metric_price
.zip($band.as_ref())
.filter(|_| options.price_bands())
.map(|(mp, b)| {
LazyBinaryPrice::from_lazy_height_and_dateindex_last::<PriceTimesRatio, S1T>(
&format!("{name}_{}", $suffix),
version,
mp,
b,
)
})
};
}
Ok(Self {
days,
sd: import!("sd"),
zscore: options.zscore().then(|| import!("zscore")),
_0sd_usd: lazy_usd!(&sma_vec, "0sd_usd"),
p0_5sd_usd: lazy_usd!(&p0_5sd, "p0_5sd_usd"),
p1sd_usd: lazy_usd!(&p1sd, "p1sd_usd"),
p1_5sd_usd: lazy_usd!(&p1_5sd, "p1_5sd_usd"),
p2sd_usd: lazy_usd!(&p2sd, "p2sd_usd"),
p2_5sd_usd: lazy_usd!(&p2_5sd, "p2_5sd_usd"),
p3sd_usd: lazy_usd!(&p3sd, "p3sd_usd"),
m0_5sd_usd: lazy_usd!(&m0_5sd, "m0_5sd_usd"),
m1sd_usd: lazy_usd!(&m1sd, "m1sd_usd"),
m1_5sd_usd: lazy_usd!(&m1_5sd, "m1_5sd_usd"),
m2sd_usd: lazy_usd!(&m2sd, "m2sd_usd"),
m2_5sd_usd: lazy_usd!(&m2_5sd, "m2_5sd_usd"),
m3sd_usd: lazy_usd!(&m3sd, "m3sd_usd"),
sma: sma_vec,
p0_5sd,
p1sd,
p1_5sd,
p2sd,
p2_5sd,
p3sd,
m0_5sd,
m1sd,
m1_5sd,
m2sd,
m2_5sd,
m3sd,
})
}
}

View File

@@ -9,7 +9,7 @@ use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom
use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedFromHeightAndDateLast, ComputedVecValue,
LazyBinaryComputedFromHeightLast, LazyBinaryFromDateLast, LazyBinaryHeightDerivedLast,
LazyBinaryTransformLast, LazyDateDerivedLast, NumericValue,
LazyBinaryTransformLast, LazyDateDerivedLast, LazyFromHeightLast, NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
@@ -369,4 +369,31 @@ where
},
}
}
/// Create from a ComputedFromHeightAndDateLast and a LazyFromHeightLast.
pub fn from_computed_height_date_and_lazy_block_last<F, S2SourceT>(
name: &str,
version: Version,
source1: &ComputedFromHeightAndDateLast<S1T>,
source2: &LazyFromHeightLast<S2T, S2SourceT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: PartialOrd,
S2SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.boxed_clone(),
source2.height.boxed_clone(),
),
rest: LazyBinaryHeightDerivedLast::from_computed_height_date_and_lazy_block_last::<F, _>(
name, v, source1, source2,
),
}
}
}

View File

@@ -68,4 +68,36 @@ where
rest: LazyBinaryHeightDerivedSum::from_derived::<F>(name, v, &source1.rest, &source2.rest),
}
}
/// Create from two LazyBinaryFromHeightSum sources.
pub fn from_binary<F, S1aT, S1bT, S2aT, S2bT>(
name: &str,
version: Version,
source1: &LazyBinaryFromHeightSum<S1T, S1aT, S1bT>,
source2: &LazyBinaryFromHeightSum<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.boxed_clone(),
source2.height.boxed_clone(),
),
rest: LazyBinaryHeightDerivedSum::from_binary::<F, _, _, _, _>(
name,
v,
&source1.rest,
&source2.rest,
),
}
}
}

View File

@@ -8,7 +8,7 @@ use vecdb::{BinaryTransform, IterableBoxedVec, IterableCloneableVec, LazyVecFrom
use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedHeightDerivedLast, ComputedHeightDerivedSumCum,
ComputedVecValue, LazyBinaryHeightDerivedSumCum, NumericValue,
ComputedVecValue, LazyBinaryHeightDerivedSumCum, LazyFromHeightLast, NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
@@ -207,4 +207,33 @@ where
rest: LazyBinaryHeightDerivedSumCum::from_computed_derived_last::<F>(name, v, source1, source2),
}
}
// --- Methods accepting SumCum + LazyLast sources ---
pub fn from_computed_lazy_last<F, S2ST>(
name: &str,
version: Version,
height_source1: IterableBoxedVec<Height, S1T>,
height_source2: IterableBoxedVec<Height, S2T>,
source1: &ComputedFromHeightSumCum<S1T>,
source2: &LazyFromHeightLast<S2T, S2ST>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: PartialOrd,
S2T: NumericValue,
S2ST: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(name, v, height_source1, height_source2),
height_cumulative: LazyVecFrom2::transformed::<F>(
&format!("{name}_cumulative"),
v,
source1.height_cumulative.boxed_clone(),
source2.height.boxed_clone(),
),
rest: LazyBinaryHeightDerivedSumCum::from_computed_lazy_last::<F, S2ST>(name, v, source1, source2),
}
}
}

View File

@@ -0,0 +1,47 @@
//! Lazy price wrapper for height-based metrics with both USD and sats representations.
//! Derives both from a cents base metric.
use brk_traversable::Traversable;
use brk_types::{CentsUnsigned, Dollars, SatsFract, Version};
use derive_more::{Deref, DerefMut};
use vecdb::IterableCloneableVec;
use super::{ComputedFromHeightLast, LazyFromHeightLast};
use crate::internal::{CentsUnsignedToDollars, CentsUnsignedToSatsFract};
/// Lazy price metric (height-based) with both USD and sats representations.
/// Both are lazily derived from a cents base metric.
///
/// Derefs to the dollars metric, so existing code works unchanged.
/// Access `.sats` for the sats exchange rate version.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyPriceFromCents {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub dollars: LazyFromHeightLast<Dollars, CentsUnsigned>,
pub sats: LazyFromHeightLast<SatsFract, CentsUnsigned>,
}
impl LazyPriceFromCents {
pub fn from_computed(
name: &str,
version: Version,
cents: &ComputedFromHeightLast<CentsUnsigned>,
) -> Self {
let dollars = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
name,
version,
cents.height.boxed_clone(),
cents,
);
let sats = LazyFromHeightLast::from_computed::<CentsUnsignedToSatsFract>(
&format!("{name}_sats"),
version,
cents.height.boxed_clone(),
cents,
);
Self { dollars, sats }
}
}

View File

@@ -16,6 +16,7 @@ mod lazy_binary_computed_sum_cum;
mod lazy_computed_full;
mod lazy_computed_sum_cum;
mod lazy_last;
mod lazy_price_from_cents;
mod lazy_sum;
mod price;
mod unary_last;
@@ -51,6 +52,7 @@ pub use lazy_binary_computed_sum_cum::*;
pub use lazy_computed_full::*;
pub use lazy_computed_sum_cum::*;
pub use lazy_last::*;
pub use lazy_price_from_cents::*;
pub use lazy_sum::*;
pub use price::*;
pub use unary_last::*;

View File

@@ -8,7 +8,7 @@ use vecdb::{BinaryTransform, IterableCloneableVec};
use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedFromHeightAndDateLast, ComputedVecValue,
LazyBinaryFromDateLast, LazyBinaryTransformLast, NumericValue,
LazyBinaryFromDateLast, LazyBinaryTransformLast, LazyFromHeightLast, NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
@@ -141,4 +141,34 @@ where
),
}
}
/// Create from a ComputedFromHeightAndDateLast and a LazyFromHeightLast.
pub fn from_computed_height_date_and_lazy_block_last<F, S2SourceT>(
name: &str,
version: Version,
source1: &ComputedFromHeightAndDateLast<S1T>,
source2: &LazyFromHeightLast<S2T, S2SourceT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: PartialOrd,
S2SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
dates: LazyBinaryFromDateLast::from_computed_and_lazy_last::<F, _>(
name,
v,
&source1.rest,
&source2.rest.dates,
),
difficultyepoch: LazyBinaryTransformLast::from_vecs::<F>(
name,
v,
source1.difficultyepoch.boxed_clone(),
source2.rest.difficultyepoch.boxed_clone(),
),
}
}
}

View File

@@ -48,4 +48,36 @@ where
),
}
}
/// Create from two LazyBinaryHeightDerivedSum sources.
pub fn from_binary<F, S1aT, S1bT, S2aT, S2bT>(
name: &str,
version: Version,
source1: &LazyBinaryHeightDerivedSum<S1T, S1aT, S1bT>,
source2: &LazyBinaryHeightDerivedSum<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
dates: LazyBinaryFromDateSum::from_binary::<F, _, _, _, _>(
name,
v,
&source1.dates,
&source2.dates,
),
difficultyepoch: LazyBinaryTransformSum::from_boxed::<F>(
name,
v,
source1.difficultyepoch.boxed_clone(),
source2.difficultyepoch.boxed_clone(),
),
}
}
}

View File

@@ -9,7 +9,7 @@ use vecdb::{BinaryTransform, IterableCloneableVec};
use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedHeightDerivedLast, ComputedHeightDerivedSumCum,
ComputedVecValue, LazyBinaryFromDateSumCum, LazyBinaryTransformSumCum, LazyFull, LazyDateDerivedFull,
LazyDateDerivedSumCum, LazySumCum, NumericValue, SumCum,
LazyDateDerivedSumCum, LazyFromHeightLast, LazySumCum, NumericValue, SumCum,
};
const VERSION: Version = Version::ZERO;
@@ -221,4 +221,32 @@ where
),
}
}
// --- Methods accepting SumCum + LazyLast sources ---
pub fn from_computed_lazy_last<F, S2ST>(
name: &str,
version: Version,
source1: &ComputedFromHeightSumCum<S1T>,
source2: &LazyFromHeightLast<S2T, S2ST>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: PartialOrd,
S2T: NumericValue,
S2ST: ComputedVecValue + schemars::JsonSchema,
{
let v = version + VERSION;
Self {
dates: LazyBinaryFromDateSumCum::from_computed_lazy_last::<F, S2ST>(name, v, source1, source2),
difficultyepoch: LazyBinaryTransformSumCum::from_sources_last_sum_raw::<F>(
name,
v,
source1.difficultyepoch.sum.boxed_clone(),
source1.difficultyepoch.cumulative.boxed_clone(),
source2.rest.difficultyepoch.boxed_clone(),
),
}
}
}