global: snapshot

This commit is contained in:
nym21
2026-03-04 10:25:41 +01:00
parent 269c1d5fdf
commit 0d63724903
91 changed files with 972 additions and 972 deletions
+7 -26
View File
@@ -165,33 +165,14 @@ where
if values.is_empty() {
// Handle edge case where all items were skipped
if let Some(ref mut max_vec) = max {
max_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut pct90_vec) = pct90 {
pct90_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut pct75_vec) = pct75 {
pct75_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut median_vec) = median {
median_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut pct25_vec) = pct25 {
pct25_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut pct10_vec) = pct10 {
pct10_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut min_vec) = min {
min_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut average_vec) = average {
average_vec.truncate_push_at(idx, T::from(0_usize))?;
}
if let Some(ref mut sum_vec) = sum {
sum_vec.truncate_push_at(idx, T::from(0_usize))?;
macro_rules! push_zero {
($($vec:ident),*) => {
$(if let Some(ref mut v) = $vec {
v.truncate_push_at(idx, T::from(0_usize))?;
})*
};
}
push_zero!(max, pct90, pct75, median, pct25, pct10, min, average, sum);
if let Some(ref mut cumulative_vec) = cumulative {
let t = cumulative_val.unwrap();
cumulative_vec.truncate_push_at(idx, t)?;
@@ -1,61 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, StoredF32, Version};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, UnaryTransform, VecValue};
use crate::indexes;
use super::{ComputedFromHeight, LazyFromHeight};
use crate::internal::NumericValue;
/// Basis-point storage with lazy ratio float view (÷10000).
///
/// Stores integer basis points on disk (Pco-compressed),
/// exposes a lazy StoredF32 ratio (e.g., 25000 bps → 2.5).
#[derive(Traversable)]
pub struct Float32FromHeight<B, M: StorageMode = Rw>
where
B: NumericValue + JsonSchema,
{
pub bps: ComputedFromHeight<B, M>,
pub float: LazyFromHeight<StoredF32, B>,
}
impl<B> Float32FromHeight<B>
where
B: NumericValue + JsonSchema,
{
pub(crate) fn forced_import<F: UnaryTransform<B, StoredF32>>(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let bps = ComputedFromHeight::forced_import(db, name, version, indexes)?;
let float = LazyFromHeight::from_computed::<F>(
&format!("{name}_float"),
version,
bps.height.read_only_boxed_clone(),
&bps,
);
Ok(Self { bps, float })
}
pub(crate) fn compute_binary<S1T, S2T, F>(
&mut self,
max_from: Height,
source1: &impl ReadableVec<Height, S1T>,
source2: &impl ReadableVec<Height, S2T>,
exit: &Exit,
) -> Result<()>
where
S1T: VecValue,
S2T: VecValue,
F: BinaryTransform<S1T, S2T, B>,
{
self.bps.compute_binary::<S1T, S2T, F>(max_from, source1, source2, exit)
}
}
@@ -6,10 +6,10 @@ mod cumulative;
mod cumulative_sum;
mod distribution;
mod fiat;
mod float32;
mod full;
mod lazy_base;
mod percent;
mod percent_distribution;
mod percentiles;
mod price;
mod ratio;
@@ -24,10 +24,10 @@ pub use cumulative::*;
pub use cumulative_sum::*;
pub use distribution::*;
pub use fiat::*;
pub use float32::*;
pub use full::*;
pub use lazy_base::*;
pub use percent::*;
pub use percent_distribution::*;
pub use percentiles::*;
pub use price::*;
pub use ratio::*;
@@ -1,12 +1,17 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, StoredF32, Version};
use brk_types::{
BasisPoints16, BasisPointsSigned16, BasisPointsSigned32, Height, StoredF32, Version,
};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, UnaryTransform, VecValue};
use crate::{
indexes,
internal::NumericValue,
internal::{
Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, Bps32ToFloat, Bps32ToPercent,
NumericValue,
},
traits::ComputeDrawdown,
};
@@ -44,7 +49,7 @@ where
RatioTransform: UnaryTransform<B, StoredF32>,
PercentTransform: UnaryTransform<B, StoredF32>,
{
let bps = ComputedFromHeight::forced_import(db, name, version, indexes)?;
let bps = ComputedFromHeight::forced_import(db, &format!("{name}_bps"), version, indexes)?;
let ratio = LazyFromHeight::from_computed::<RatioTransform>(
&format!("{name}_ratio"),
@@ -54,7 +59,7 @@ where
);
let percent = LazyFromHeight::from_computed::<PercentTransform>(
&format!("{name}_percent"),
name,
version,
bps.height.read_only_boxed_clone(),
&bps,
@@ -63,6 +68,45 @@ where
Ok(Self { bps, ratio, percent })
}
}
impl PercentFromHeight<BasisPoints16> {
pub(crate) fn forced_import_bp16(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
}
}
impl PercentFromHeight<BasisPointsSigned16> {
pub(crate) fn forced_import_bps16(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import::<Bps16ToFloat, Bps16ToPercent>(db, name, version, indexes)
}
}
impl PercentFromHeight<BasisPointsSigned32> {
pub(crate) fn forced_import_bps32(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import::<Bps32ToFloat, Bps32ToPercent>(db, name, version, indexes)
}
}
impl<B> PercentFromHeight<B>
where
B: NumericValue + JsonSchema,
{
pub(crate) fn compute_binary<S1T, S2T, F>(
&mut self,
max_from: Height,
@@ -0,0 +1,85 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Height, StoredF32, Version};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode, UnaryTransform};
use crate::{indexes, internal::{Bp16ToFloat, Bp16ToPercent, NumericValue, WindowStarts}};
use super::{ComputedFromHeightDistribution, LazyFromHeight};
/// Like PercentFromHeight but with rolling distribution stats on the bps data.
#[derive(Traversable)]
pub struct PercentFromHeightDistribution<B, M: StorageMode = Rw>
where
B: NumericValue + JsonSchema,
{
pub bps: ComputedFromHeightDistribution<B, M>,
pub ratio: LazyFromHeight<StoredF32, B>,
pub percent: LazyFromHeight<StoredF32, B>,
}
impl<B> PercentFromHeightDistribution<B>
where
B: NumericValue + JsonSchema,
{
pub(crate) fn forced_import<RatioTransform, PercentTransform>(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self>
where
RatioTransform: UnaryTransform<B, StoredF32>,
PercentTransform: UnaryTransform<B, StoredF32>,
{
let bps = ComputedFromHeightDistribution::forced_import(db, &format!("{name}_bps"), version, indexes)?;
let ratio = LazyFromHeight::from_height_source::<RatioTransform>(
&format!("{name}_ratio"),
version,
bps.height.read_only_boxed_clone(),
indexes,
);
let percent = LazyFromHeight::from_height_source::<PercentTransform>(
name,
version,
bps.height.read_only_boxed_clone(),
indexes,
);
Ok(Self { bps, ratio, percent })
}
}
impl PercentFromHeightDistribution<BasisPoints16> {
pub(crate) fn forced_import_bp16(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
}
}
impl<B> PercentFromHeightDistribution<B>
where
B: NumericValue + JsonSchema,
{
pub(crate) fn compute(
&mut self,
max_from: Height,
windows: &WindowStarts<'_>,
exit: &Exit,
compute_height: impl FnOnce(&mut EagerVec<PcoVec<Height, B>>) -> Result<()>,
) -> Result<()>
where
B: Copy + Ord + From<f64> + Default,
f64: From<B>,
{
self.bps.compute(max_from, windows, exit, compute_height)
}
}
@@ -1,6 +1,6 @@
use brk_error::Result;
use brk_traversable::{Traversable, TreeNode};
use brk_types::{Cents, Height, StoredF32, Version};
use brk_types::{BasisPoints16, Cents, Height, Version};
use vecdb::{AnyExportableVec, Database, ReadOnlyClone, Ro, Rw, StorageMode, WritableVec};
use crate::indexes;
@@ -16,9 +16,9 @@ pub const PERCENTILES_LEN: usize = PERCENTILES.len();
pub(crate) fn compute_spot_percentile_rank(
percentile_prices: &[Cents; PERCENTILES_LEN],
spot: Cents,
) -> StoredF32 {
) -> BasisPoints16 {
if spot == Cents::ZERO && percentile_prices[0] == Cents::ZERO {
return StoredF32::NAN;
return BasisPoints16::ZERO;
}
let spot_f64 = f64::from(spot);
@@ -27,10 +27,10 @@ pub(crate) fn compute_spot_percentile_rank(
let p5 = f64::from(percentile_prices[0]);
if spot_f64 <= p5 {
if p5 == 0.0 {
return StoredF32::from(0.0);
return BasisPoints16::ZERO;
}
// Linear extrapolation: rank = 5 * (spot / p5)
return StoredF32::from((5.0 * spot_f64 / p5).max(0.0));
// Linear extrapolation: rank = 5% * (spot / p5)
return BasisPoints16::from((0.05 * spot_f64 / p5).max(0.0));
}
// Above highest percentile (p95) - extrapolate towards 100
@@ -38,11 +38,11 @@ pub(crate) fn compute_spot_percentile_rank(
let p90 = f64::from(percentile_prices[PERCENTILES_LEN - 2]);
if spot_f64 >= p95 {
if p95 == p90 {
return StoredF32::from(100.0);
return BasisPoints16::ONE;
}
// Linear extrapolation using p90-p95 slope
let slope = 5.0 / (p95 - p90);
return StoredF32::from((95.0 + (spot_f64 - p95) * slope).min(100.0));
let slope = 0.05 / (p95 - p90);
return BasisPoints16::from((0.95 + (spot_f64 - p95) * slope).min(1.0));
}
// Find the band containing spot and interpolate
@@ -51,20 +51,20 @@ pub(crate) fn compute_spot_percentile_rank(
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]);
let lower_pct = f64::from(PERCENTILES[i]) / 100.0;
let upper_pct = f64::from(PERCENTILES[i + 1]) / 100.0;
if upper == lower {
return StoredF32::from(lower_pct);
return BasisPoints16::from(lower_pct);
}
// Linear interpolation
let ratio = (spot_f64 - lower) / (upper - lower);
return StoredF32::from(lower_pct + ratio * (upper_pct - lower_pct));
return BasisPoints16::from(lower_pct + ratio * (upper_pct - lower_pct));
}
}
StoredF32::NAN
BasisPoints16::ZERO
}
pub struct PercentilesVecs<M: StorageMode = Rw> {
@@ -1,6 +1,6 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Height, StoredF32, Version};
use brk_types::{BasisPoints32, Cents, Height, StoredF32, Version};
use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, WritableVec};
use crate::{
@@ -8,18 +8,18 @@ use crate::{
internal::{ComputedFromHeightStdDevExtended, Price, TDigest},
};
use super::super::ComputedFromHeight;
use super::{ComputedFromHeightRatio, super::ComputedFromHeight};
#[derive(Traversable)]
pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
pub ratio_sma_1w: ComputedFromHeight<StoredF32, M>,
pub ratio_sma_1m: ComputedFromHeight<StoredF32, M>,
pub ratio_pct99: ComputedFromHeight<StoredF32, M>,
pub ratio_pct98: ComputedFromHeight<StoredF32, M>,
pub ratio_pct95: ComputedFromHeight<StoredF32, M>,
pub ratio_pct5: ComputedFromHeight<StoredF32, M>,
pub ratio_pct2: ComputedFromHeight<StoredF32, M>,
pub ratio_pct1: ComputedFromHeight<StoredF32, M>,
pub ratio_sma_1w: ComputedFromHeightRatio<M>,
pub ratio_sma_1m: ComputedFromHeightRatio<M>,
pub ratio_pct99: ComputedFromHeightRatio<M>,
pub ratio_pct98: ComputedFromHeightRatio<M>,
pub ratio_pct95: ComputedFromHeightRatio<M>,
pub ratio_pct5: ComputedFromHeightRatio<M>,
pub ratio_pct2: ComputedFromHeightRatio<M>,
pub ratio_pct1: ComputedFromHeightRatio<M>,
pub ratio_pct99_price: Price<ComputedFromHeight<Cents, M>>,
pub ratio_pct98_price: Price<ComputedFromHeight<Cents, M>>,
pub ratio_pct95_price: Price<ComputedFromHeight<Cents, M>>,
@@ -47,9 +47,9 @@ impl ComputedFromHeightRatioExtension {
) -> Result<Self> {
let v = version + VERSION;
macro_rules! import {
macro_rules! import_ratio {
($suffix:expr) => {
ComputedFromHeight::forced_import(
ComputedFromHeightRatio::forced_import_raw(
db,
&format!("{name}_{}", $suffix),
v,
@@ -78,18 +78,18 @@ impl ComputedFromHeightRatioExtension {
}
Ok(Self {
ratio_sma_1w: import!("ratio_sma_1w"),
ratio_sma_1m: import!("ratio_sma_1m"),
ratio_sma_1w: import_ratio!("ratio_sma_1w"),
ratio_sma_1m: import_ratio!("ratio_sma_1m"),
ratio_sd: import_sd!("ratio", "", usize::MAX),
ratio_sd_1y: import_sd!("ratio", "1y", 365),
ratio_sd_2y: import_sd!("ratio", "2y", 2 * 365),
ratio_sd_4y: import_sd!("ratio", "4y", 4 * 365),
ratio_pct99: import!("ratio_pct99"),
ratio_pct98: import!("ratio_pct98"),
ratio_pct95: import!("ratio_pct95"),
ratio_pct5: import!("ratio_pct5"),
ratio_pct2: import!("ratio_pct2"),
ratio_pct1: import!("ratio_pct1"),
ratio_pct99: import_ratio!("ratio_pct99"),
ratio_pct98: import_ratio!("ratio_pct98"),
ratio_pct95: import_ratio!("ratio_pct95"),
ratio_pct5: import_ratio!("ratio_pct5"),
ratio_pct2: import_ratio!("ratio_pct2"),
ratio_pct1: import_ratio!("ratio_pct1"),
ratio_pct99_price: import_price!("ratio_pct99"),
ratio_pct98_price: import_price!("ratio_pct98"),
ratio_pct95_price: import_price!("ratio_pct95"),
@@ -109,14 +109,14 @@ impl ComputedFromHeightRatioExtension {
ratio_source: &impl ReadableVec<Height, StoredF32>,
) -> Result<()> {
// SMA using lookback vecs
self.ratio_sma_1w.height.compute_rolling_average(
self.ratio_sma_1w.bps.height.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1w_ago,
ratio_source,
exit,
)?;
self.ratio_sma_1m.height.compute_rolling_average(
self.ratio_sma_1m.bps.height.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1m_ago,
ratio_source,
@@ -124,14 +124,14 @@ impl ComputedFromHeightRatioExtension {
)?;
let ratio_version = ratio_source.version();
self.mut_ratio_vecs()
self.mut_pct_vecs()
.try_for_each(|v| -> Result<()> {
v.validate_computed_version_or_reset(ratio_version)?;
Ok(())
})?;
let starting_height = self
.mut_ratio_vecs()
.mut_pct_vecs()
.map(|v| Height::from(v.len()))
.min()
.unwrap()
@@ -154,13 +154,13 @@ impl ComputedFromHeightRatioExtension {
// Process new blocks [start, ratio_len)
let new_ratios = ratio_source.collect_range_at(start, ratio_len);
let mut pct_vecs: [&mut EagerVec<PcoVec<Height, StoredF32>>; 6] = [
&mut self.ratio_pct1.height,
&mut self.ratio_pct2.height,
&mut self.ratio_pct5.height,
&mut self.ratio_pct95.height,
&mut self.ratio_pct98.height,
&mut self.ratio_pct99.height,
let mut pct_vecs: [&mut EagerVec<PcoVec<Height, BasisPoints32>>; 6] = [
&mut self.ratio_pct1.bps.height,
&mut self.ratio_pct2.bps.height,
&mut self.ratio_pct5.bps.height,
&mut self.ratio_pct95.bps.height,
&mut self.ratio_pct98.bps.height,
&mut self.ratio_pct99.bps.height,
];
const PCTS: [f64; 6] = [0.01, 0.02, 0.05, 0.95, 0.98, 0.99];
let mut out = [0.0f64; 6];
@@ -170,14 +170,14 @@ impl ComputedFromHeightRatioExtension {
self.tdigest.quantiles(&PCTS, &mut out);
let idx = start + offset;
for (vec, &val) in pct_vecs.iter_mut().zip(out.iter()) {
vec.truncate_push_at(idx, StoredF32::from(val as f32))?;
vec.truncate_push_at(idx, BasisPoints32::from(val))?;
}
}
}
{
let _lock = exit.lock();
self.mut_ratio_vecs()
self.mut_pct_vecs()
.try_for_each(|v| v.flush())?;
}
@@ -201,13 +201,13 @@ impl ComputedFromHeightRatioExtension {
metric_price: &impl ReadableVec<Height, Cents>,
exit: &Exit,
) -> Result<()> {
use crate::internal::PriceTimesRatioCents;
use crate::internal::PriceTimesRatioBp32Cents;
macro_rules! compute_band {
($usd_field:ident, $band_source:expr) => {
self.$usd_field
.cents
.compute_binary::<Cents, StoredF32, PriceTimesRatioCents>(
.compute_binary::<Cents, BasisPoints32, PriceTimesRatioBp32Cents>(
starting_indexes.height,
metric_price,
$band_source,
@@ -216,12 +216,12 @@ impl ComputedFromHeightRatioExtension {
};
}
compute_band!(ratio_pct99_price, &self.ratio_pct99.height);
compute_band!(ratio_pct98_price, &self.ratio_pct98.height);
compute_band!(ratio_pct95_price, &self.ratio_pct95.height);
compute_band!(ratio_pct5_price, &self.ratio_pct5.height);
compute_band!(ratio_pct2_price, &self.ratio_pct2.height);
compute_band!(ratio_pct1_price, &self.ratio_pct1.height);
compute_band!(ratio_pct99_price, &self.ratio_pct99.bps.height);
compute_band!(ratio_pct98_price, &self.ratio_pct98.bps.height);
compute_band!(ratio_pct95_price, &self.ratio_pct95.bps.height);
compute_band!(ratio_pct5_price, &self.ratio_pct5.bps.height);
compute_band!(ratio_pct2_price, &self.ratio_pct2.bps.height);
compute_band!(ratio_pct1_price, &self.ratio_pct1.bps.height);
// Stddev cents bands
self.ratio_sd
@@ -236,16 +236,16 @@ impl ComputedFromHeightRatioExtension {
Ok(())
}
fn mut_ratio_vecs(
fn mut_pct_vecs(
&mut self,
) -> impl Iterator<Item = &mut EagerVec<PcoVec<Height, StoredF32>>> {
) -> impl Iterator<Item = &mut EagerVec<PcoVec<Height, BasisPoints32>>> {
[
&mut self.ratio_pct1.height,
&mut self.ratio_pct2.height,
&mut self.ratio_pct5.height,
&mut self.ratio_pct95.height,
&mut self.ratio_pct98.height,
&mut self.ratio_pct99.height,
&mut self.ratio_pct1.bps.height,
&mut self.ratio_pct2.bps.height,
&mut self.ratio_pct5.bps.height,
&mut self.ratio_pct95.bps.height,
&mut self.ratio_pct98.bps.height,
&mut self.ratio_pct99.bps.height,
]
.into_iter()
}
@@ -8,16 +8,17 @@ pub use price_extended::*;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Height, StoredF32, Version};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use brk_types::{BasisPoints32, Cents, Height, StoredF32, Version};
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::{ComputeIndexes, indexes};
use crate::{ComputeIndexes, indexes, internal::Bp32ToFloat};
use super::ComputedFromHeight;
use super::{ComputedFromHeight, LazyFromHeight};
#[derive(Traversable)]
pub struct ComputedFromHeightRatio<M: StorageMode = Rw> {
pub ratio: ComputedFromHeight<StoredF32, M>,
pub bps: ComputedFromHeight<BasisPoints32, M>,
pub ratio: LazyFromHeight<StoredF32, BasisPoints32>,
}
const VERSION: Version = Version::TWO;
@@ -28,12 +29,28 @@ impl ComputedFromHeightRatio {
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import_raw(db, &format!("{name}_ratio"), version, indexes)
}
pub(crate) fn forced_import_raw(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
Ok(Self {
ratio: ComputedFromHeight::forced_import(db, &format!("{name}_ratio"), v, indexes)?,
})
let bps = ComputedFromHeight::forced_import(db, &format!("{name}_bps"), v, indexes)?;
let ratio = LazyFromHeight::from_computed::<Bp32ToFloat>(
name,
v,
bps.height.read_only_boxed_clone(),
&bps,
);
Ok(Self { bps, ratio })
}
/// Compute ratio = close_price / metric_price at height level (both in cents)
@@ -44,15 +61,15 @@ impl ComputedFromHeightRatio {
metric_price: &impl ReadableVec<Height, Cents>,
exit: &Exit,
) -> Result<()> {
self.ratio.height.compute_transform2(
self.bps.height.compute_transform2(
starting_indexes.height,
close_price,
metric_price,
|(i, close, price, ..)| {
if price == Cents::ZERO {
(i, StoredF32::from(1.0))
(i, BasisPoints32::from(1.0))
} else {
(i, StoredF32::from(f64::from(close) / f64::from(price)))
(i, BasisPoints32::from(f64::from(close) / f64::from(price)))
}
},
exit,
@@ -1,13 +1,13 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, StoredF32, Version};
use brk_types::{BasisPoints16, Height, StoredF32, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, UnaryTransform};
use crate::{
indexes,
internal::{Emas1w1m, NumericValue, PercentFromHeight},
internal::{Bp16ToFloat, Bp16ToPercent, Emas1w1m, NumericValue, PercentFromHeight},
};
const VERSION: Version = Version::ZERO;
@@ -45,6 +45,23 @@ where
})?))
}
}
impl PercentRollingEmas1w1m<BasisPoints16> {
pub(crate) fn forced_import_bp16(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
}
}
impl<B> PercentRollingEmas1w1m<B>
where
B: NumericValue + JsonSchema,
{
pub(crate) fn compute_from_24h(
&mut self,
max_from: Height,
@@ -1,13 +1,13 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{StoredF32, Version};
use brk_types::{BasisPoints16, StoredF32, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, Rw, StorageMode, UnaryTransform};
use crate::{
indexes,
internal::{NumericValue, PercentFromHeight, Windows},
internal::{Bp16ToFloat, Bp16ToPercent, NumericValue, PercentFromHeight, Windows},
};
const VERSION: Version = Version::ZERO;
@@ -45,3 +45,14 @@ where
})?))
}
}
impl PercentRollingWindows<BasisPoints16> {
pub(crate) fn forced_import_bp16(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPoints16, StoredF32};
use vecdb::UnaryTransform;
pub struct Bp16ToFloat;
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToFloat {
#[inline(always)]
fn apply(bp: BasisPoints16) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPoints16, StoredF32};
use vecdb::UnaryTransform;
pub struct Bp16ToPercent;
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToPercent {
#[inline(always)]
fn apply(bp: BasisPoints16) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPoints32, StoredF32};
use vecdb::UnaryTransform;
pub struct Bp32ToFloat;
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToFloat {
#[inline(always)]
fn apply(bp: BasisPoints32) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPoints32, StoredF32};
use vecdb::UnaryTransform;
pub struct Bp32ToPercent;
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToPercent {
#[inline(always)]
fn apply(bp: BasisPoints32) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPointsSigned16, StoredF32};
use vecdb::UnaryTransform;
pub struct Bps16ToFloat;
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToFloat {
#[inline(always)]
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPointsSigned16, StoredF32};
use vecdb::UnaryTransform;
pub struct Bps16ToPercent;
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToPercent {
#[inline(always)]
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPointsSigned32, StoredF32};
use vecdb::UnaryTransform;
pub struct Bps32ToFloat;
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToFloat {
#[inline(always)]
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
@@ -1,11 +0,0 @@
use brk_types::{BasisPointsSigned32, StoredF32};
use vecdb::UnaryTransform;
pub struct Bps32ToPercent;
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToPercent {
#[inline(always)]
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
@@ -0,0 +1,38 @@
use brk_types::{BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32};
use vecdb::UnaryTransform;
pub struct Bp16ToFloat;
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToFloat {
#[inline(always)]
fn apply(bp: BasisPoints16) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
pub struct Bp32ToFloat;
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToFloat {
#[inline(always)]
fn apply(bp: BasisPoints32) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
pub struct Bps16ToFloat;
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToFloat {
#[inline(always)]
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
pub struct Bps32ToFloat;
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToFloat {
#[inline(always)]
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
StoredF32::from(bp.to_f32())
}
}
@@ -0,0 +1,29 @@
use brk_types::{BasisPoints16, BasisPointsSigned16, BasisPointsSigned32, StoredF32};
use vecdb::UnaryTransform;
pub struct Bp16ToPercent;
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToPercent {
#[inline(always)]
fn apply(bp: BasisPoints16) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
pub struct Bps16ToPercent;
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToPercent {
#[inline(always)]
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
pub struct Bps32ToPercent;
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToPercent {
#[inline(always)]
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
StoredF32::from(bp.inner() as f32 / 100.0)
}
}
@@ -0,0 +1,48 @@
use brk_types::{Cents, CentsSigned, Dollars, Sats};
use vecdb::UnaryTransform;
/// CentsUnsigned -> Dollars (convert cents to dollars for display)
pub struct CentsUnsignedToDollars;
impl UnaryTransform<Cents, Dollars> for CentsUnsignedToDollars {
#[inline(always)]
fn apply(cents: Cents) -> Dollars {
cents.into()
}
}
/// Cents -> -Dollars (negate after converting to dollars)
/// Avoids lazy-from-lazy by combining both transforms.
pub struct NegCentsUnsignedToDollars;
impl UnaryTransform<Cents, Dollars> for NegCentsUnsignedToDollars {
#[inline(always)]
fn apply(cents: Cents) -> Dollars {
-Dollars::from(cents)
}
}
/// CentsSigned -> Dollars (convert signed cents to dollars for display)
pub struct CentsSignedToDollars;
impl UnaryTransform<CentsSigned, Dollars> for CentsSignedToDollars {
#[inline(always)]
fn apply(cents: CentsSigned) -> Dollars {
cents.into()
}
}
/// CentsUnsigned -> Sats (sats per dollar: 1 BTC / price)
pub struct CentsUnsignedToSats;
impl UnaryTransform<Cents, Sats> for CentsUnsignedToSats {
#[inline(always)]
fn apply(cents: Cents) -> Sats {
let dollars = Dollars::from(cents);
if dollars == Dollars::ZERO {
Sats::ZERO
} else {
Sats::ONE_BTC / dollars
}
}
}
@@ -1,12 +0,0 @@
use brk_types::Cents;
use vecdb::UnaryTransform;
/// Cents -> Cents/2 (for supply_halved_cents)
pub struct HalveCents;
impl UnaryTransform<Cents, Cents> for HalveCents {
#[inline(always)]
fn apply(cents: Cents) -> Cents {
cents / 2u64
}
}
@@ -1,12 +0,0 @@
use brk_types::{CentsSigned, Dollars};
use vecdb::UnaryTransform;
/// CentsSigned -> Dollars (convert signed cents to dollars for display)
pub struct CentsSignedToDollars;
impl UnaryTransform<CentsSigned, Dollars> for CentsSignedToDollars {
#[inline(always)]
fn apply(cents: CentsSigned) -> Dollars {
cents.into()
}
}
@@ -1,12 +0,0 @@
use brk_types::{Cents, Dollars};
use vecdb::UnaryTransform;
/// CentsUnsigned -> Dollars (convert cents to dollars for display)
pub struct CentsUnsignedToDollars;
impl UnaryTransform<Cents, Dollars> for CentsUnsignedToDollars {
#[inline(always)]
fn apply(cents: Cents) -> Dollars {
cents.into()
}
}
@@ -1,17 +0,0 @@
use brk_types::{Cents, Dollars, Sats};
use vecdb::UnaryTransform;
/// CentsUnsigned -> Sats (sats per dollar: 1 BTC / price)
pub struct CentsUnsignedToSats;
impl UnaryTransform<Cents, Sats> for CentsUnsignedToSats {
#[inline(always)]
fn apply(cents: Cents) -> Sats {
let dollars = Dollars::from(cents);
if dollars == Dollars::ZERO {
Sats::ZERO
} else {
Sats::ONE_BTC / dollars
}
}
}
@@ -1,12 +0,0 @@
use brk_types::Dollars;
use vecdb::UnaryTransform;
/// Dollars -> Dollars/2 (for supply_halved_usd)
pub struct HalveDollars;
impl UnaryTransform<Dollars, Dollars> for HalveDollars {
#[inline(always)]
fn apply(dollars: Dollars) -> Dollars {
dollars.halved()
}
}
@@ -0,0 +1,43 @@
use brk_types::{Bitcoin, Cents, Dollars, Sats};
use vecdb::UnaryTransform;
/// Sats -> Sats/2 (for supply_halved)
pub struct HalveSats;
impl UnaryTransform<Sats, Sats> for HalveSats {
#[inline(always)]
fn apply(sats: Sats) -> Sats {
sats / 2
}
}
/// Sats -> Bitcoin/2 (halve then convert to bitcoin)
/// Avoids lazy-from-lazy by combining both transforms
pub struct HalveSatsToBitcoin;
impl UnaryTransform<Sats, Bitcoin> for HalveSatsToBitcoin {
#[inline(always)]
fn apply(sats: Sats) -> Bitcoin {
Bitcoin::from(sats / 2)
}
}
/// Cents -> Cents/2 (for supply_halved_cents)
pub struct HalveCents;
impl UnaryTransform<Cents, Cents> for HalveCents {
#[inline(always)]
fn apply(cents: Cents) -> Cents {
cents / 2u64
}
}
/// Dollars -> Dollars/2 (for supply_halved_usd)
pub struct HalveDollars;
impl UnaryTransform<Dollars, Dollars> for HalveDollars {
#[inline(always)]
fn apply(dollars: Dollars) -> Dollars {
dollars.halved()
}
}
@@ -1,86 +1,43 @@
mod bp16_to_float;
mod bp16_to_percent;
mod bp32_to_float;
mod bp32_to_percent;
mod bps16_to_float;
mod bps16_to_percent;
mod bps32_to_float;
mod bps32_to_percent;
mod block_count_target;
mod cents_halve;
mod identity;
mod bps_to_float;
mod bps_to_percent;
mod cents_convert;
mod cents_plus;
mod cents_signed_to_dollars;
mod cents_subtract_to_cents_signed;
mod cents_times_tenths;
mod cents_to_dollars;
mod cents_to_sats;
mod dollar_halve;
mod days_to_years;
mod dollars_to_sats_fract;
mod neg_cents_to_dollars;
mod ohlc_cents_to_dollars;
mod ohlc_cents_to_sats;
mod percentage_diff_close_cents;
mod percentage_diff_close_dollars;
mod price_times_ratio_cents;
mod ratio32;
mod ratio_cents64;
mod halve;
mod identity;
mod ohlc;
mod per_sec;
mod ratio_bp16;
mod ratio_bps16;
mod ratio_bps32;
mod ratio_u64_f32;
mod return_f32_tenths;
mod return_i8;
mod return_u16;
mod sats_to_cents;
mod sat_halve;
mod sat_halve_to_bitcoin;
mod price_times_ratio_cents;
mod ratio;
mod ratio_cents64;
mod return_const;
mod sat_mask;
mod sat_to_bitcoin;
mod days_to_years;
mod sats_to_cents;
mod volatility;
pub use bp16_to_float::*;
pub use bp16_to_percent::*;
pub use bp32_to_float::*;
pub use bp32_to_percent::*;
pub use bps16_to_float::*;
pub use bps16_to_percent::*;
pub use bps32_to_float::*;
pub use bps32_to_percent::*;
pub use block_count_target::*;
pub use cents_halve::*;
pub use identity::*;
pub use bps_to_float::*;
pub use bps_to_percent::*;
pub use cents_convert::*;
pub use cents_plus::*;
pub use cents_signed_to_dollars::*;
pub use cents_subtract_to_cents_signed::*;
pub use cents_times_tenths::*;
pub use cents_to_dollars::*;
pub use cents_to_sats::*;
pub use neg_cents_to_dollars::*;
pub use ohlc_cents_to_dollars::*;
pub use ohlc_cents_to_sats::*;
pub use dollar_halve::*;
pub use days_to_years::*;
pub use dollars_to_sats_fract::*;
pub use percentage_diff_close_cents::*;
pub use percentage_diff_close_dollars::*;
pub use price_times_ratio_cents::*;
pub use ratio32::*;
pub use ratio_cents64::*;
pub use halve::*;
pub use identity::*;
pub use ohlc::*;
pub use per_sec::*;
pub use ratio_bp16::*;
pub use ratio_bps16::*;
pub use ratio_bps32::*;
pub use ratio_u64_f32::*;
pub use return_f32_tenths::*;
pub use return_i8::*;
pub use return_u16::*;
pub use sats_to_cents::*;
pub use sat_halve::*;
pub use sat_halve_to_bitcoin::*;
pub use price_times_ratio_cents::*;
pub use ratio::*;
pub use ratio_cents64::*;
pub use return_const::*;
pub use sat_mask::*;
pub use sat_to_bitcoin::*;
pub use days_to_years::*;
pub use sats_to_cents::*;
pub use volatility::*;
@@ -1,13 +0,0 @@
use brk_types::{Cents, Dollars};
use vecdb::UnaryTransform;
/// Cents -> -Dollars (negate after converting to dollars)
/// Avoids lazy-from-lazy by combining both transforms.
pub struct NegCentsUnsignedToDollars;
impl UnaryTransform<Cents, Dollars> for NegCentsUnsignedToDollars {
#[inline(always)]
fn apply(cents: Cents) -> Dollars {
-Dollars::from(cents)
}
}
@@ -1,8 +1,17 @@
use brk_types::{Close, High, Low, OHLCCents, OHLCSats, Open};
use brk_types::{Close, High, Low, OHLCCents, OHLCDollars, OHLCSats, Open};
use vecdb::UnaryTransform;
use super::CentsUnsignedToSats;
pub struct OhlcCentsToDollars;
impl UnaryTransform<OHLCCents, OHLCDollars> for OhlcCentsToDollars {
#[inline(always)]
fn apply(cents: OHLCCents) -> OHLCDollars {
OHLCDollars::from(cents)
}
}
/// OHLCCents -> OHLCSats with high/low swapped (inverse price relationship).
pub struct OhlcCentsToSats;
@@ -1,11 +0,0 @@
use brk_types::{OHLCCents, OHLCDollars};
use vecdb::UnaryTransform;
pub struct OhlcCentsToDollars;
impl UnaryTransform<OHLCCents, OHLCDollars> for OhlcCentsToDollars {
#[inline(always)]
fn apply(cents: OHLCCents) -> OHLCDollars {
OHLCDollars::from(cents)
}
}
@@ -1,17 +0,0 @@
use brk_types::{Cents, StoredF32};
use vecdb::BinaryTransform;
/// (Cents, Cents) -> StoredF32 percentage difference ((a/b - 1) * 100)
pub struct PercentageDiffCents;
impl BinaryTransform<Cents, Cents, StoredF32> for PercentageDiffCents {
#[inline(always)]
fn apply(close: Cents, base: Cents) -> StoredF32 {
let base_f64 = f64::from(base);
if base_f64 == 0.0 {
StoredF32::default()
} else {
StoredF32::from((f64::from(close) / base_f64 - 1.0) * 100.0)
}
}
}
@@ -1,16 +0,0 @@
use brk_types::{Dollars, StoredF32};
use vecdb::BinaryTransform;
/// (Dollars, Dollars) -> StoredF32 percentage difference ((a/b - 1) × 100)
pub struct PercentageDiffDollars;
impl BinaryTransform<Dollars, Dollars, StoredF32> for PercentageDiffDollars {
#[inline(always)]
fn apply(close: Dollars, base: Dollars) -> StoredF32 {
if base == Dollars::ZERO {
StoredF32::default()
} else {
StoredF32::from((*close / *base - 1.0) * 100.0)
}
}
}
@@ -1,4 +1,4 @@
use brk_types::{Cents, StoredF32};
use brk_types::{BasisPoints32, Cents, StoredF32};
use vecdb::BinaryTransform;
pub struct PriceTimesRatioCents;
@@ -9,3 +9,12 @@ impl BinaryTransform<Cents, StoredF32, Cents> for PriceTimesRatioCents {
Cents::from(f64::from(price) * f64::from(ratio))
}
}
pub struct PriceTimesRatioBp32Cents;
impl BinaryTransform<Cents, BasisPoints32, Cents> for PriceTimesRatioBp32Cents {
#[inline(always)]
fn apply(price: Cents, ratio: BasisPoints32) -> Cents {
Cents::from(f64::from(price) * f64::from(ratio))
}
}
@@ -0,0 +1,197 @@
use brk_types::{
BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, Cents, CentsSigned,
Dollars, Sats, StoredF32, StoredU32, StoredU64,
};
use vecdb::BinaryTransform;
// === BasisPoints16 (unsigned) ratios ===
/// (StoredU64, StoredU64) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioU64Bp16;
impl BinaryTransform<StoredU64, StoredU64, BasisPoints16> for RatioU64Bp16 {
#[inline(always)]
fn apply(numerator: StoredU64, denominator: StoredU64) -> BasisPoints16 {
if *denominator > 0 {
BasisPoints16::from(*numerator as f64 / *denominator as f64)
} else {
BasisPoints16::ZERO
}
}
}
/// (Sats, Sats) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioSatsBp16;
impl BinaryTransform<Sats, Sats, BasisPoints16> for RatioSatsBp16 {
#[inline(always)]
fn apply(numerator: Sats, denominator: Sats) -> BasisPoints16 {
if *denominator > 0 {
BasisPoints16::from(*numerator as f64 / *denominator as f64)
} else {
BasisPoints16::ZERO
}
}
}
/// (Cents, Cents) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioCentsBp16;
impl BinaryTransform<Cents, Cents, BasisPoints16> for RatioCentsBp16 {
#[inline(always)]
fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 {
if denominator == Cents::ZERO {
BasisPoints16::ZERO
} else {
BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64)
}
}
}
/// (StoredU32, StoredU32) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioU32Bp16;
impl BinaryTransform<StoredU32, StoredU32, BasisPoints16> for RatioU32Bp16 {
#[inline(always)]
fn apply(numerator: StoredU32, denominator: StoredU32) -> BasisPoints16 {
if *denominator > 0 {
BasisPoints16::from(*numerator as f64 / *denominator as f64)
} else {
BasisPoints16::ZERO
}
}
}
/// (Dollars, Dollars) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioDollarsBp16;
impl BinaryTransform<Dollars, Dollars, BasisPoints16> for RatioDollarsBp16 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints16 {
let ratio = *(numerator / denominator);
if ratio.is_finite() {
BasisPoints16::from(ratio)
} else {
BasisPoints16::ZERO
}
}
}
// === BasisPointsSigned16 (signed) ratios ===
/// (Dollars, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000)
pub struct RatioDollarsBps16;
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned16> for RatioDollarsBps16 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 {
let ratio = *(numerator / denominator);
if ratio.is_finite() {
BasisPointsSigned16::from(ratio)
} else {
BasisPointsSigned16::ZERO
}
}
}
/// (Dollars, Dollars) -> BasisPointsSigned16 negated ratio (-(a/b) × 10000)
pub struct NegRatioDollarsBps16;
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned16> for NegRatioDollarsBps16 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 {
let ratio = *(numerator / denominator);
if ratio.is_finite() {
BasisPointsSigned16::from(-ratio)
} else {
BasisPointsSigned16::ZERO
}
}
}
/// (CentsSigned, Cents) -> BasisPointsSigned16 ratio (a/b × 10000)
pub struct RatioCentsSignedCentsBps16;
impl BinaryTransform<CentsSigned, Cents, BasisPointsSigned16> for RatioCentsSignedCentsBps16 {
#[inline(always)]
fn apply(numerator: CentsSigned, denominator: Cents) -> BasisPointsSigned16 {
if denominator == Cents::ZERO {
BasisPointsSigned16::ZERO
} else {
BasisPointsSigned16::from(numerator.inner() as f64 / denominator.inner() as f64)
}
}
}
/// (CentsSigned, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000)
pub struct RatioCentsSignedDollarsBps16;
impl BinaryTransform<CentsSigned, Dollars, BasisPointsSigned16> for RatioCentsSignedDollarsBps16 {
#[inline(always)]
fn apply(numerator: CentsSigned, denominator: Dollars) -> BasisPointsSigned16 {
let d: f64 = denominator.into();
if d > 0.0 {
BasisPointsSigned16::from(numerator.inner() as f64 / 100.0 / d)
} else {
BasisPointsSigned16::ZERO
}
}
}
// === BasisPoints32 (unsigned) ratios ===
/// (Dollars, Dollars) -> BasisPoints32 ratio (a / b × 10000)
pub struct RatioDollarsBp32;
impl BinaryTransform<Dollars, Dollars, BasisPoints32> for RatioDollarsBp32 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints32 {
BasisPoints32::from(f64::from(numerator) / f64::from(denominator))
}
}
// === BasisPointsSigned32 (signed) ratio diffs ===
/// (StoredF32, StoredF32) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000)
pub struct RatioDiffF32Bps32;
impl BinaryTransform<StoredF32, StoredF32, BasisPointsSigned32> for RatioDiffF32Bps32 {
#[inline(always)]
fn apply(value: StoredF32, base: StoredF32) -> BasisPointsSigned32 {
if base.is_nan() || *base == 0.0 {
BasisPointsSigned32::ZERO
} else {
BasisPointsSigned32::from((*value / *base - 1.0) as f64)
}
}
}
/// (Dollars, Dollars) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000)
pub struct RatioDiffDollarsBps32;
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned32> for RatioDiffDollarsBps32 {
#[inline(always)]
fn apply(close: Dollars, base: Dollars) -> BasisPointsSigned32 {
let base_f64: f64 = base.into();
if base_f64 == 0.0 {
BasisPointsSigned32::ZERO
} else {
BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0)
}
}
}
/// (Cents, Cents) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000)
pub struct RatioDiffCentsBps32;
impl BinaryTransform<Cents, Cents, BasisPointsSigned32> for RatioDiffCentsBps32 {
#[inline(always)]
fn apply(close: Cents, base: Cents) -> BasisPointsSigned32 {
let base_f64 = f64::from(base);
if base_f64 == 0.0 {
BasisPointsSigned32::ZERO
} else {
BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0)
}
}
}
@@ -1,13 +0,0 @@
use brk_types::{Dollars, StoredF32};
use vecdb::BinaryTransform;
/// (Dollars, Dollars) -> StoredF32 ratio
/// Used for computing percentage ratios like profit/total, loss/total, etc.
pub struct Ratio32;
impl BinaryTransform<Dollars, Dollars, StoredF32> for Ratio32 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 {
StoredF32::from(numerator / denominator)
}
}
@@ -1,73 +0,0 @@
use brk_types::{BasisPoints16, Cents, Dollars, Sats, StoredU32, StoredU64};
use vecdb::BinaryTransform;
/// (StoredU64, StoredU64) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioU64Bp16;
impl BinaryTransform<StoredU64, StoredU64, BasisPoints16> for RatioU64Bp16 {
#[inline(always)]
fn apply(numerator: StoredU64, denominator: StoredU64) -> BasisPoints16 {
if *denominator > 0 {
BasisPoints16::from(*numerator as f64 / *denominator as f64)
} else {
BasisPoints16::ZERO
}
}
}
/// (Sats, Sats) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioSatsBp16;
impl BinaryTransform<Sats, Sats, BasisPoints16> for RatioSatsBp16 {
#[inline(always)]
fn apply(numerator: Sats, denominator: Sats) -> BasisPoints16 {
if *denominator > 0 {
BasisPoints16::from(*numerator as f64 / *denominator as f64)
} else {
BasisPoints16::ZERO
}
}
}
/// (Cents, Cents) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioCentsBp16;
impl BinaryTransform<Cents, Cents, BasisPoints16> for RatioCentsBp16 {
#[inline(always)]
fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 {
if denominator == Cents::ZERO {
BasisPoints16::ZERO
} else {
BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64)
}
}
}
/// (StoredU32, StoredU32) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioU32Bp16;
impl BinaryTransform<StoredU32, StoredU32, BasisPoints16> for RatioU32Bp16 {
#[inline(always)]
fn apply(numerator: StoredU32, denominator: StoredU32) -> BasisPoints16 {
if *denominator > 0 {
BasisPoints16::from(*numerator as f64 / *denominator as f64)
} else {
BasisPoints16::ZERO
}
}
}
/// (Dollars, Dollars) -> BasisPoints16 ratio (a/b × 10000)
pub struct RatioDollarsBp16;
impl BinaryTransform<Dollars, Dollars, BasisPoints16> for RatioDollarsBp16 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints16 {
let ratio = *(numerator / denominator);
if ratio.is_finite() {
BasisPoints16::from(ratio)
} else {
BasisPoints16::ZERO
}
}
}
@@ -1,62 +0,0 @@
use brk_types::{BasisPointsSigned16, Cents, CentsSigned, Dollars};
use vecdb::BinaryTransform;
/// (Dollars, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000)
pub struct RatioDollarsBps16;
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned16> for RatioDollarsBps16 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 {
let ratio = *(numerator / denominator);
if ratio.is_finite() {
BasisPointsSigned16::from(ratio)
} else {
BasisPointsSigned16::ZERO
}
}
}
/// (Dollars, Dollars) -> BasisPointsSigned16 negated ratio (-(a/b) × 10000)
pub struct NegRatioDollarsBps16;
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned16> for NegRatioDollarsBps16 {
#[inline(always)]
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 {
let ratio = *(numerator / denominator);
if ratio.is_finite() {
BasisPointsSigned16::from(-ratio)
} else {
BasisPointsSigned16::ZERO
}
}
}
/// (CentsSigned, Cents) -> BasisPointsSigned16 ratio (a/b × 10000)
pub struct RatioCentsSignedCentsBps16;
impl BinaryTransform<CentsSigned, Cents, BasisPointsSigned16> for RatioCentsSignedCentsBps16 {
#[inline(always)]
fn apply(numerator: CentsSigned, denominator: Cents) -> BasisPointsSigned16 {
if denominator == Cents::ZERO {
BasisPointsSigned16::ZERO
} else {
BasisPointsSigned16::from(numerator.inner() as f64 / denominator.inner() as f64)
}
}
}
/// (CentsSigned, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000)
pub struct RatioCentsSignedDollarsBps16;
impl BinaryTransform<CentsSigned, Dollars, BasisPointsSigned16> for RatioCentsSignedDollarsBps16 {
#[inline(always)]
fn apply(numerator: CentsSigned, denominator: Dollars) -> BasisPointsSigned16 {
let d: f64 = denominator.into();
if d > 0.0 {
// Convert cents to dollars first, then compute ratio
BasisPointsSigned16::from(numerator.inner() as f64 / 100.0 / d)
} else {
BasisPointsSigned16::ZERO
}
}
}
@@ -1,32 +0,0 @@
use brk_types::{BasisPointsSigned32, Cents, Dollars};
use vecdb::BinaryTransform;
/// (Dollars, Dollars) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000)
pub struct RatioDiffDollarsBps32;
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned32> for RatioDiffDollarsBps32 {
#[inline(always)]
fn apply(close: Dollars, base: Dollars) -> BasisPointsSigned32 {
let base_f64: f64 = base.into();
if base_f64 == 0.0 {
BasisPointsSigned32::ZERO
} else {
BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0)
}
}
}
/// (Cents, Cents) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000)
pub struct RatioDiffCentsBps32;
impl BinaryTransform<Cents, Cents, BasisPointsSigned32> for RatioDiffCentsBps32 {
#[inline(always)]
fn apply(close: Cents, base: Cents) -> BasisPointsSigned32 {
let base_f64 = f64::from(base);
if base_f64 == 0.0 {
BasisPointsSigned32::ZERO
} else {
BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0)
}
}
}
@@ -1,17 +0,0 @@
use brk_types::{StoredF32, StoredU64};
use vecdb::BinaryTransform;
/// (StoredU64, StoredU64) -> StoredF32 ratio (a/b)
/// Used for adoption ratio calculations (script_count / total_outputs)
pub struct RatioU64F32;
impl BinaryTransform<StoredU64, StoredU64, StoredF32> for RatioU64F32 {
#[inline(always)]
fn apply(numerator: StoredU64, denominator: StoredU64) -> StoredF32 {
if *denominator > 0 {
StoredF32::from(*numerator as f64 / *denominator as f64)
} else {
StoredF32::from(0.0)
}
}
}
@@ -0,0 +1,32 @@
use brk_types::{StoredF32, StoredI8, StoredU16};
use vecdb::UnaryTransform;
/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input.
pub struct ReturnF32Tenths<const V: u16>;
impl<S, const V: u16> UnaryTransform<S, StoredF32> for ReturnF32Tenths<V> {
#[inline(always)]
fn apply(_: S) -> StoredF32 {
StoredF32::from(V as f32 / 10.0)
}
}
/// Returns a constant u16 value, ignoring the input.
pub struct ReturnU16<const V: u16>;
impl<S, const V: u16> UnaryTransform<S, StoredU16> for ReturnU16<V> {
#[inline(always)]
fn apply(_: S) -> StoredU16 {
StoredU16::new(V)
}
}
/// Returns a constant i8 value, ignoring the input.
pub struct ReturnI8<const V: i8>;
impl<S, const V: i8> UnaryTransform<S, StoredI8> for ReturnI8<V> {
#[inline(always)]
fn apply(_: S) -> StoredI8 {
StoredI8::new(V)
}
}
@@ -1,12 +0,0 @@
use brk_types::StoredF32;
use vecdb::UnaryTransform;
/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input.
pub struct ReturnF32Tenths<const V: u16>;
impl<S, const V: u16> UnaryTransform<S, StoredF32> for ReturnF32Tenths<V> {
#[inline(always)]
fn apply(_: S) -> StoredF32 {
StoredF32::from(V as f32 / 10.0)
}
}
@@ -1,12 +0,0 @@
use brk_types::StoredI8;
use vecdb::UnaryTransform;
/// Returns a constant i8 value, ignoring the input.
pub struct ReturnI8<const V: i8>;
impl<S, const V: i8> UnaryTransform<S, StoredI8> for ReturnI8<V> {
#[inline(always)]
fn apply(_: S) -> StoredI8 {
StoredI8::new(V)
}
}
@@ -1,12 +0,0 @@
use brk_types::StoredU16;
use vecdb::UnaryTransform;
/// Returns a constant u16 value, ignoring the input.
pub struct ReturnU16<const V: u16>;
impl<S, const V: u16> UnaryTransform<S, StoredU16> for ReturnU16<V> {
#[inline(always)]
fn apply(_: S) -> StoredU16 {
StoredU16::new(V)
}
}
@@ -1,12 +0,0 @@
use brk_types::Sats;
use vecdb::UnaryTransform;
/// Sats -> Sats/2 (for supply_halved)
pub struct HalveSats;
impl UnaryTransform<Sats, Sats> for HalveSats {
#[inline(always)]
fn apply(sats: Sats) -> Sats {
sats / 2
}
}
@@ -1,13 +0,0 @@
use brk_types::{Bitcoin, Sats};
use vecdb::UnaryTransform;
/// Sats -> Bitcoin/2 (halve then convert to bitcoin)
/// Avoids lazy-from-lazy by combining both transforms
pub struct HalveSatsToBitcoin;
impl UnaryTransform<Sats, Bitcoin> for HalveSatsToBitcoin {
#[inline(always)]
fn apply(sats: Sats) -> Bitcoin {
Bitcoin::from(sats / 2)
}
}