mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-01 01:50:00 -07:00
global: snapshot
This commit is contained in:
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user