mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-03 03:33:38 -07:00
global: snapshot
This commit is contained in:
@@ -4,12 +4,14 @@ mod windows;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Sats, Version};
|
||||
use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
|
||||
internal::{
|
||||
CentsUnsignedToDollars, ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin,
|
||||
},
|
||||
};
|
||||
|
||||
pub use rolling_full::*;
|
||||
@@ -19,7 +21,8 @@ pub use rolling_sum::*;
|
||||
pub struct ByUnit<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
pub cents: ComputedFromHeightLast<Cents, M>,
|
||||
pub usd: LazyFromHeightLast<Dollars, Cents>,
|
||||
}
|
||||
|
||||
impl ByUnit {
|
||||
@@ -38,9 +41,25 @@ impl ByUnit {
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd =
|
||||
ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), version, indexes)?;
|
||||
let cents = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_cents"),
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
sats,
|
||||
btc,
|
||||
cents,
|
||||
usd,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -47,11 +47,11 @@ impl RollingFullSlot {
|
||||
max_from: Height,
|
||||
starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sum.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?;
|
||||
self.sum.usd.height.compute_rolling_sum(max_from, starts, usd_source, exit)?;
|
||||
self.sum.cents.height.compute_rolling_sum(max_from, starts, cents_source, exit)?;
|
||||
|
||||
let d = &mut self.distribution;
|
||||
|
||||
@@ -64,11 +64,11 @@ impl RollingFullSlot {
|
||||
)?;
|
||||
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, starts, usd_source,
|
||||
&mut d.average.usd.height, &mut d.min.usd.height,
|
||||
&mut d.max.usd.height, &mut d.pct10.usd.height,
|
||||
&mut d.pct25.usd.height, &mut d.median.usd.height,
|
||||
&mut d.pct75.usd.height, &mut d.pct90.usd.height, exit,
|
||||
max_from, starts, cents_source,
|
||||
&mut d.average.cents.height, &mut d.min.cents.height,
|
||||
&mut d.max.cents.height, &mut d.pct10.cents.height,
|
||||
&mut d.pct25.cents.height, &mut d.median.cents.height,
|
||||
&mut d.pct75.cents.height, &mut d.pct90.cents.height, exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@@ -105,11 +105,11 @@ impl RollingFullByUnit {
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (slot, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
slot.compute(max_from, starts, sats_source, usd_source, exit)?;
|
||||
slot.compute(max_from, starts, sats_source, cents_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -34,12 +34,12 @@ impl RollingSumByUnit {
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?;
|
||||
w.usd.height.compute_rolling_sum(max_from, starts, usd_source, exit)?;
|
||||
w.cents.height.compute_rolling_sum(max_from, starts, cents_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::{Traversable, TreeNode};
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{AnyExportableVec, Database, ReadOnlyClone, Ro, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::indexes;
|
||||
@@ -14,10 +14,10 @@ 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(crate) fn compute_spot_percentile_rank(
|
||||
percentile_prices: &[Dollars; PERCENTILES_LEN],
|
||||
spot: Dollars,
|
||||
percentile_prices: &[Cents; PERCENTILES_LEN],
|
||||
spot: Cents,
|
||||
) -> StoredF32 {
|
||||
if spot.is_nan() || percentile_prices[0].is_nan() {
|
||||
if spot == Cents::ZERO && percentile_prices[0] == Cents::ZERO {
|
||||
return StoredF32::NAN;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ pub(crate) fn compute_spot_percentile_rank(
|
||||
}
|
||||
|
||||
pub struct PercentilesVecs<M: StorageMode = Rw> {
|
||||
pub vecs: [Price<ComputedFromHeightLast<Dollars, M>>; PERCENTILES_LEN],
|
||||
pub vecs: [Price<ComputedFromHeightLast<Cents, M>>; PERCENTILES_LEN],
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
@@ -94,14 +94,14 @@ impl PercentilesVecs {
|
||||
Ok(Self { vecs })
|
||||
}
|
||||
|
||||
/// Push percentile prices at this height.
|
||||
/// Push percentile prices at this height (in cents).
|
||||
pub(crate) fn truncate_push(
|
||||
&mut self,
|
||||
height: Height,
|
||||
percentile_prices: &[Dollars; PERCENTILES_LEN],
|
||||
percentile_prices: &[Cents; PERCENTILES_LEN],
|
||||
) -> Result<()> {
|
||||
for (i, v) in self.vecs.iter_mut().enumerate() {
|
||||
v.usd.height.truncate_push(height, percentile_prices[i])?;
|
||||
v.cents.height.truncate_push(height, percentile_prices[i])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -109,7 +109,7 @@ impl PercentilesVecs {
|
||||
/// Validate computed versions or reset if mismatched.
|
||||
pub(crate) fn validate_computed_version_or_reset(&mut self, version: Version) -> Result<()> {
|
||||
for vec in self.vecs.iter_mut() {
|
||||
vec.usd.height.validate_computed_version_or_reset(version)?;
|
||||
vec.cents.height.validate_computed_version_or_reset(version)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -130,7 +130,7 @@ impl ReadOnlyClone for PercentilesVecs {
|
||||
|
||||
impl<M: StorageMode> Traversable for PercentilesVecs<M>
|
||||
where
|
||||
Price<ComputedFromHeightLast<Dollars, M>>: Traversable,
|
||||
Price<ComputedFromHeightLast<Cents, M>>: Traversable,
|
||||
{
|
||||
fn to_tree_node(&self) -> TreeNode {
|
||||
TreeNode::Branch(
|
||||
|
||||
@@ -1,65 +1,104 @@
|
||||
//! Generic price wrapper with both USD and sats representations.
|
||||
//! Generic price wrapper with cents, USD, and sats representations.
|
||||
//!
|
||||
//! All prices use this single struct with different USD types.
|
||||
//! All prices use this single struct with different cents types.
|
||||
//! USD is always lazily derived from cents via CentsUnsignedToDollars.
|
||||
//! Sats is always lazily derived from USD via DollarsToSatsFract.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, SatsFract, Version};
|
||||
use brk_types::{Cents, Dollars, SatsFract, Version};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{Database, ReadableCloneableVec, UnaryTransform};
|
||||
|
||||
use super::{ComputedFromHeightLast, LazyFromHeightLast};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedVecValue, DollarsToSatsFract, NumericValue},
|
||||
internal::{CentsUnsignedToDollars, ComputedVecValue, DollarsToSatsFract, NumericValue},
|
||||
};
|
||||
|
||||
/// Generic price metric with both USD and sats representations.
|
||||
/// Generic price metric with cents, USD, and sats representations.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Price<U> {
|
||||
pub usd: U,
|
||||
pub struct Price<C> {
|
||||
pub cents: C,
|
||||
pub usd: LazyFromHeightLast<Dollars, Cents>,
|
||||
pub sats: LazyFromHeightLast<SatsFract, Dollars>,
|
||||
}
|
||||
|
||||
impl Price<ComputedFromHeightLast<Dollars>> {
|
||||
impl Price<ComputedFromHeightLast<Cents>> {
|
||||
/// Import from database: stored cents, lazy USD + sats.
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let usd = ComputedFromHeightLast::forced_import(db, name, version, indexes)?;
|
||||
let sats = LazyFromHeightLast::from_computed::<DollarsToSatsFract>(
|
||||
let cents = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_cents"),
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
|
||||
&format!("{name}_sats"),
|
||||
version,
|
||||
usd.height.read_only_boxed_clone(),
|
||||
&usd,
|
||||
);
|
||||
Ok(Self { usd, sats })
|
||||
Ok(Self { cents, usd, sats })
|
||||
}
|
||||
|
||||
/// Wrap an already-imported ComputedFromHeightLast<Cents> with lazy USD + sats.
|
||||
pub(crate) fn from_cents(
|
||||
name: &str,
|
||||
version: Version,
|
||||
cents: ComputedFromHeightLast<Cents>,
|
||||
) -> Self {
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
|
||||
&format!("{name}_sats"),
|
||||
version,
|
||||
&usd,
|
||||
);
|
||||
Self { cents, usd, sats }
|
||||
}
|
||||
}
|
||||
|
||||
impl<ST> Price<LazyFromHeightLast<Dollars, ST>>
|
||||
impl<ST> Price<LazyFromHeightLast<Cents, ST>>
|
||||
where
|
||||
ST: ComputedVecValue + NumericValue + JsonSchema + 'static,
|
||||
{
|
||||
pub(crate) fn from_computed<F: UnaryTransform<ST, Dollars>>(
|
||||
/// Create from a computed source, applying a transform to produce Cents.
|
||||
pub(crate) fn from_cents_source<F: UnaryTransform<ST, Cents>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
source: &ComputedFromHeightLast<ST>,
|
||||
) -> Self {
|
||||
let usd = LazyFromHeightLast::from_computed::<F>(
|
||||
name,
|
||||
let cents = LazyFromHeightLast::from_computed::<F>(
|
||||
&format!("{name}_cents"),
|
||||
version,
|
||||
source.height.read_only_boxed_clone(),
|
||||
source,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, ST>(
|
||||
let usd = LazyFromHeightLast::from_lazy::<CentsUnsignedToDollars, ST>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
¢s,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
|
||||
&format!("{name}_sats"),
|
||||
version,
|
||||
&usd,
|
||||
);
|
||||
Self { usd, sats }
|
||||
Self { cents, usd, sats }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Version};
|
||||
use brk_types::{Cents, Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -31,22 +31,22 @@ impl ComputedFromHeightRatioExtended {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute ratio and all extended metrics from an externally-provided metric price.
|
||||
/// Compute ratio and all extended metrics from an externally-provided metric price (in cents).
|
||||
pub(crate) fn compute_rest(
|
||||
&mut self,
|
||||
blocks: &blocks::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
) -> Result<()> {
|
||||
let close_price = &prices.price.usd.height;
|
||||
let close_price = &prices.price.cents.height;
|
||||
self.base
|
||||
.compute_ratio(starting_indexes, close_price, metric_price, exit)?;
|
||||
self.extended
|
||||
.compute_rest(blocks, starting_indexes, exit, &self.base.ratio.height)?;
|
||||
self.extended
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -21,12 +21,12 @@ pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
|
||||
pub ratio_pct5: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub ratio_pct2: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub ratio_pct1: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub ratio_pct99_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct98_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct95_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct5_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct2_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct1_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct99_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct98_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct95_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct5_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct2_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct1_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
|
||||
pub ratio_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_4y_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
@@ -68,7 +68,7 @@ impl ComputedFromHeightRatioExtension {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! import_usd {
|
||||
macro_rules! import_price {
|
||||
($suffix:expr) => {
|
||||
Price::forced_import(db, &format!("{name}_{}", $suffix), v, indexes)?
|
||||
};
|
||||
@@ -87,12 +87,12 @@ impl ComputedFromHeightRatioExtension {
|
||||
ratio_pct5: import!("ratio_pct5"),
|
||||
ratio_pct2: import!("ratio_pct2"),
|
||||
ratio_pct1: import!("ratio_pct1"),
|
||||
ratio_pct99_usd: import_usd!("ratio_pct99_usd"),
|
||||
ratio_pct98_usd: import_usd!("ratio_pct98_usd"),
|
||||
ratio_pct95_usd: import_usd!("ratio_pct95_usd"),
|
||||
ratio_pct5_usd: import_usd!("ratio_pct5_usd"),
|
||||
ratio_pct2_usd: import_usd!("ratio_pct2_usd"),
|
||||
ratio_pct1_usd: import_usd!("ratio_pct1_usd"),
|
||||
ratio_pct99_price: import_price!("ratio_pct99"),
|
||||
ratio_pct98_price: import_price!("ratio_pct98"),
|
||||
ratio_pct95_price: import_price!("ratio_pct95"),
|
||||
ratio_pct5_price: import_price!("ratio_pct5"),
|
||||
ratio_pct2_price: import_price!("ratio_pct2"),
|
||||
ratio_pct1_price: import_price!("ratio_pct1"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -219,20 +219,20 @@ impl ComputedFromHeightRatioExtension {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute USD ratio bands: usd_band = metric_price * ratio_percentile
|
||||
pub(crate) fn compute_usd_bands(
|
||||
/// Compute cents ratio bands: cents_band = metric_price_cents * ratio_percentile
|
||||
pub(crate) fn compute_cents_bands(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
use crate::internal::PriceTimesRatio;
|
||||
use crate::internal::PriceTimesRatioCents;
|
||||
|
||||
macro_rules! compute_band {
|
||||
($usd_field:ident, $band_source:expr) => {
|
||||
self.$usd_field
|
||||
.usd
|
||||
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
|
||||
.cents
|
||||
.compute_binary::<Cents, StoredF32, PriceTimesRatioCents>(
|
||||
starting_indexes.height,
|
||||
metric_price,
|
||||
$band_source,
|
||||
@@ -241,22 +241,22 @@ impl ComputedFromHeightRatioExtension {
|
||||
};
|
||||
}
|
||||
|
||||
compute_band!(ratio_pct99_usd, &self.ratio_pct99.height);
|
||||
compute_band!(ratio_pct98_usd, &self.ratio_pct98.height);
|
||||
compute_band!(ratio_pct95_usd, &self.ratio_pct95.height);
|
||||
compute_band!(ratio_pct5_usd, &self.ratio_pct5.height);
|
||||
compute_band!(ratio_pct2_usd, &self.ratio_pct2.height);
|
||||
compute_band!(ratio_pct1_usd, &self.ratio_pct1.height);
|
||||
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);
|
||||
|
||||
// Stddev USD bands
|
||||
// Stddev cents bands
|
||||
self.ratio_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_4y_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_2y_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_1y_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pub use price_extended::*;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{ComputeIndexes, indexes};
|
||||
@@ -36,12 +36,12 @@ impl ComputedFromHeightRatio {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute ratio = close_price / metric_price at height level
|
||||
/// Compute ratio = close_price / metric_price at height level (both in cents)
|
||||
pub(crate) fn compute_ratio(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
close_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
close_price: &impl ReadableVec<Height, Cents>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.ratio.height.compute_transform2(
|
||||
@@ -49,10 +49,10 @@ impl ComputedFromHeightRatio {
|
||||
close_price,
|
||||
metric_price,
|
||||
|(i, close, price, ..)| {
|
||||
if price == Dollars::ZERO {
|
||||
if price == Cents::ZERO {
|
||||
(i, StoredF32::from(1.0))
|
||||
} else {
|
||||
(i, StoredF32::from(close / price))
|
||||
(i, StoredF32::from(f64::from(close) / f64::from(price)))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Version};
|
||||
use brk_types::{Cents, Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct ComputedFromHeightPriceWithRatioExtended<M: StorageMode = Rw> {
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub inner: ComputedFromHeightRatioExtended<M>,
|
||||
pub price: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
}
|
||||
|
||||
impl ComputedFromHeightPriceWithRatioExtended {
|
||||
@@ -32,7 +32,7 @@ impl ComputedFromHeightPriceWithRatioExtended {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute price via closure, then compute ratio + extended metrics.
|
||||
/// Compute price via closure (in cents), then compute ratio + extended metrics.
|
||||
pub(crate) fn compute_all<F>(
|
||||
&mut self,
|
||||
blocks: &blocks::Vecs,
|
||||
@@ -42,15 +42,15 @@ impl ComputedFromHeightPriceWithRatioExtended {
|
||||
mut compute_price: F,
|
||||
) -> Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<PcoVec<Height, Dollars>>) -> Result<()>,
|
||||
F: FnMut(&mut EagerVec<PcoVec<Height, Cents>>) -> Result<()>,
|
||||
{
|
||||
compute_price(&mut self.price.usd.height)?;
|
||||
compute_price(&mut self.price.cents.height)?;
|
||||
self.inner.compute_rest(
|
||||
blocks,
|
||||
prices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.price.usd.height,
|
||||
&self.price.cents.height,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex,
|
||||
WritableVec,
|
||||
@@ -32,19 +32,19 @@ pub struct ComputedFromHeightStdDevExtended<M: StorageMode = Rw> {
|
||||
pub m2_5sd: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub m3sd: ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
pub _0sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p0_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p1sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p1_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p2sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p2_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p3sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m0_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m1sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m1_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m2sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m2_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m3sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub _0sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p0_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p1sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p1_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p2sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p2_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p3sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m0_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m1sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m1_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m2sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m2_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m3sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
}
|
||||
|
||||
impl ComputedFromHeightStdDevExtended {
|
||||
@@ -68,7 +68,7 @@ impl ComputedFromHeightStdDevExtended {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! import_usd {
|
||||
macro_rules! import_price {
|
||||
($suffix:expr) => {
|
||||
Price::forced_import(db, &format!("{name}_{}", $suffix), version, indexes)?
|
||||
};
|
||||
@@ -89,19 +89,19 @@ impl ComputedFromHeightStdDevExtended {
|
||||
m2sd: import!("m2sd"),
|
||||
m2_5sd: import!("m2_5sd"),
|
||||
m3sd: import!("m3sd"),
|
||||
_0sd_usd: import_usd!("0sd_usd"),
|
||||
p0_5sd_usd: import_usd!("p0_5sd_usd"),
|
||||
p1sd_usd: import_usd!("p1sd_usd"),
|
||||
p1_5sd_usd: import_usd!("p1_5sd_usd"),
|
||||
p2sd_usd: import_usd!("p2sd_usd"),
|
||||
p2_5sd_usd: import_usd!("p2_5sd_usd"),
|
||||
p3sd_usd: import_usd!("p3sd_usd"),
|
||||
m0_5sd_usd: import_usd!("m0_5sd_usd"),
|
||||
m1sd_usd: import_usd!("m1sd_usd"),
|
||||
m1_5sd_usd: import_usd!("m1_5sd_usd"),
|
||||
m2sd_usd: import_usd!("m2sd_usd"),
|
||||
m2_5sd_usd: import_usd!("m2_5sd_usd"),
|
||||
m3sd_usd: import_usd!("m3sd_usd"),
|
||||
_0sd_price: import_price!("0sd"),
|
||||
p0_5sd_price: import_price!("p0_5sd"),
|
||||
p1sd_price: import_price!("p1sd"),
|
||||
p1_5sd_price: import_price!("p1_5sd"),
|
||||
p2sd_price: import_price!("p2sd"),
|
||||
p2_5sd_price: import_price!("p2_5sd"),
|
||||
p3sd_price: import_price!("p3sd"),
|
||||
m0_5sd_price: import_price!("m0_5sd"),
|
||||
m1sd_price: import_price!("m1sd"),
|
||||
m1_5sd_price: import_price!("m1_5sd"),
|
||||
m2sd_price: import_price!("m2sd"),
|
||||
m2_5sd_price: import_price!("m2_5sd"),
|
||||
m3sd_price: import_price!("m3sd"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -217,20 +217,20 @@ impl ComputedFromHeightStdDevExtended {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute USD price bands: usd_band = metric_price * band_ratio
|
||||
pub(crate) fn compute_usd_bands(
|
||||
/// Compute cents price bands: cents_band = metric_price_cents * band_ratio
|
||||
pub(crate) fn compute_cents_bands(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
use crate::internal::PriceTimesRatio;
|
||||
use crate::internal::PriceTimesRatioCents;
|
||||
|
||||
macro_rules! compute_band {
|
||||
($usd_field:ident, $band_source:expr) => {
|
||||
self.$usd_field
|
||||
.usd
|
||||
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
|
||||
.cents
|
||||
.compute_binary::<Cents, StoredF32, PriceTimesRatioCents>(
|
||||
starting_indexes.height,
|
||||
metric_price,
|
||||
$band_source,
|
||||
@@ -239,19 +239,19 @@ impl ComputedFromHeightStdDevExtended {
|
||||
};
|
||||
}
|
||||
|
||||
compute_band!(_0sd_usd, &self.base.sma.height);
|
||||
compute_band!(p0_5sd_usd, &self.p0_5sd.height);
|
||||
compute_band!(p1sd_usd, &self.p1sd.height);
|
||||
compute_band!(p1_5sd_usd, &self.p1_5sd.height);
|
||||
compute_band!(p2sd_usd, &self.p2sd.height);
|
||||
compute_band!(p2_5sd_usd, &self.p2_5sd.height);
|
||||
compute_band!(p3sd_usd, &self.p3sd.height);
|
||||
compute_band!(m0_5sd_usd, &self.m0_5sd.height);
|
||||
compute_band!(m1sd_usd, &self.m1sd.height);
|
||||
compute_band!(m1_5sd_usd, &self.m1_5sd.height);
|
||||
compute_band!(m2sd_usd, &self.m2sd.height);
|
||||
compute_band!(m2_5sd_usd, &self.m2_5sd.height);
|
||||
compute_band!(m3sd_usd, &self.m3sd.height);
|
||||
compute_band!(_0sd_price, &self.base.sma.height);
|
||||
compute_band!(p0_5sd_price, &self.p0_5sd.height);
|
||||
compute_band!(p1sd_price, &self.p1sd.height);
|
||||
compute_band!(p1_5sd_price, &self.p1_5sd.height);
|
||||
compute_band!(p2sd_price, &self.p2sd.height);
|
||||
compute_band!(p2_5sd_price, &self.p2_5sd.height);
|
||||
compute_band!(p3sd_price, &self.p3sd.height);
|
||||
compute_band!(m0_5sd_price, &self.m0_5sd.height);
|
||||
compute_band!(m1sd_price, &self.m1sd.height);
|
||||
compute_band!(m1_5sd_price, &self.m1_5sd.height);
|
||||
compute_band!(m2sd_price, &self.m2sd.height);
|
||||
compute_band!(m2_5sd_price, &self.m2_5sd.height);
|
||||
compute_band!(m3sd_price, &self.m3sd.height);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,22 +2,25 @@
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, SatsSigned, Version};
|
||||
use brk_types::{Bitcoin, Cents, CentsSigned, Dollars, Height, Sats, SatsSigned, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsSignedToBitcoin},
|
||||
internal::{
|
||||
CentsSignedToDollars, ComputedFromHeightLast, LazyFromHeightLast, SatsSignedToBitcoin,
|
||||
},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
/// Change values indexed by height - sats (stored), btc (lazy), usd (stored).
|
||||
/// Change values indexed by height - sats (stored), btc (lazy), cents (stored), usd (lazy).
|
||||
#[derive(Traversable)]
|
||||
pub struct ValueFromHeightChange<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<SatsSigned, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, SatsSigned>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
pub cents: ComputedFromHeightLast<CentsSigned, M>,
|
||||
pub usd: LazyFromHeightLast<Dollars, CentsSigned>,
|
||||
}
|
||||
|
||||
impl ValueFromHeightChange {
|
||||
@@ -38,31 +41,38 @@ impl ValueFromHeightChange {
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd = ComputedFromHeightLast::forced_import(
|
||||
let cents = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_usd"),
|
||||
&format!("{name}_cents"),
|
||||
v,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsSignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
|
||||
Ok(Self { sats, btc, cents, usd })
|
||||
}
|
||||
|
||||
/// Compute rolling change for both sats and dollars in one call.
|
||||
/// Compute rolling change for both sats and cents in one call.
|
||||
pub(crate) fn compute_rolling(
|
||||
&mut self,
|
||||
starting_height: Height,
|
||||
window_starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
dollars_source: &(impl ReadableVec<Height, Dollars> + Sync),
|
||||
cents_source: &(impl ReadableVec<Height, Cents> + Sync),
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sats
|
||||
.height
|
||||
.compute_rolling_change(starting_height, window_starts, sats_source, exit)?;
|
||||
self.usd
|
||||
self.cents
|
||||
.height
|
||||
.compute_rolling_change(starting_height, window_starts, dollars_source, exit)?;
|
||||
.compute_rolling_change(starting_height, window_starts, cents_source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, SatsToDollars},
|
||||
internal::{ByUnit, SatsToCents},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -44,18 +44,18 @@ impl ValueFromHeightCumulative {
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
.cents
|
||||
.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, RollingFullByUnit, SatsToDollars, WindowStarts},
|
||||
internal::{ByUnit, RollingFullByUnit, SatsToCents, WindowStarts},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -51,25 +51,25 @@ impl ValueFromHeightFull {
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
self.rolling.compute(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
&self.base.usd.height,
|
||||
&self.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes, prices,
|
||||
internal::{ByUnit, SatsToDollars},
|
||||
internal::{ByUnit, SatsToCents},
|
||||
};
|
||||
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
@@ -38,10 +38,10 @@ impl ValueFromHeightLast {
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.base.cents.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -52,7 +52,7 @@ impl ValueFromHeightLast {
|
||||
max_from: Height,
|
||||
window_starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base
|
||||
@@ -60,9 +60,9 @@ impl ValueFromHeightLast {
|
||||
.height
|
||||
.compute_rolling_sum(max_from, window_starts, sats_source, exit)?;
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_rolling_sum(max_from, window_starts, usd_source, exit)?;
|
||||
.compute_rolling_sum(max_from, window_starts, cents_source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ impl ValueFromHeightLast {
|
||||
starting_height: Height,
|
||||
window_starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
dollars_source: &(impl ReadableVec<Height, Dollars> + Sync),
|
||||
cents_source: &(impl ReadableVec<Height, Cents> + Sync),
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base
|
||||
@@ -79,9 +79,9 @@ impl ValueFromHeightLast {
|
||||
.height
|
||||
.compute_rolling_ema(starting_height, window_starts, sats_source, exit)?;
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_rolling_ema(starting_height, window_starts, dollars_source, exit)?;
|
||||
.compute_rolling_ema(starting_height, window_starts, cents_source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ impl ValueFromHeightLastRolling {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute sats height via closure, then USD from price, then rolling windows.
|
||||
/// Compute sats height via closure, then cents from price, then rolling windows.
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
@@ -51,12 +51,12 @@ impl ValueFromHeightLastRolling {
|
||||
compute_sats: impl FnOnce(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
compute_sats(&mut self.value.sats)?;
|
||||
self.value.compute_usd(prices, max_from, exit)?;
|
||||
self.value.compute_cents(prices, max_from, exit)?;
|
||||
self.rolling.compute_rolling_sum(
|
||||
max_from,
|
||||
windows,
|
||||
&self.value.sats,
|
||||
&self.value.usd,
|
||||
&self.value.cents,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, RollingSumByUnit, SatsToDollars, WindowStarts},
|
||||
internal::{ByUnit, RollingSumByUnit, SatsToCents, WindowStarts},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -50,25 +50,25 @@ impl ValueFromHeightSumCumulative {
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
self.sum.compute_rolling_sum(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
&self.base.usd.height,
|
||||
&self.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//! Value type with height-level data only (no period-derived views).
|
||||
//!
|
||||
//! Stores sats and USD per height, plus a lazy btc transform.
|
||||
//! Stores sats and cents per height, plus lazy btc and usd transforms.
|
||||
//! Use when period views are unnecessary (e.g., rolling windows provide windowed data).
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Height, Sats, Version};
|
||||
use vecdb::{
|
||||
Database, EagerVec, Exit, ImportableVec, LazyVecFrom1, PcoVec, ReadableCloneableVec, Rw,
|
||||
StorageMode,
|
||||
};
|
||||
|
||||
use crate::{internal::{SatsToBitcoin, SatsToDollars}, prices};
|
||||
use crate::{internal::{CentsUnsignedToDollars, SatsToBitcoin, SatsToCents}, prices};
|
||||
|
||||
const VERSION: Version = Version::TWO; // Match ValueFromHeightLast versioning
|
||||
|
||||
@@ -19,7 +19,8 @@ const VERSION: Version = Version::TWO; // Match ValueFromHeightLast versioning
|
||||
pub struct ValueFromHeight<M: StorageMode = Rw> {
|
||||
pub sats: M::Stored<EagerVec<PcoVec<Height, Sats>>>,
|
||||
pub btc: LazyVecFrom1<Height, Bitcoin, Height, Sats>,
|
||||
pub usd: M::Stored<EagerVec<PcoVec<Height, Dollars>>>,
|
||||
pub cents: M::Stored<EagerVec<PcoVec<Height, Cents>>>,
|
||||
pub usd: LazyVecFrom1<Height, Dollars, Height, Cents>,
|
||||
}
|
||||
|
||||
impl ValueFromHeight {
|
||||
@@ -36,22 +37,28 @@ impl ValueFromHeight {
|
||||
v,
|
||||
sats.read_only_boxed_clone(),
|
||||
);
|
||||
let usd = EagerVec::forced_import(db, &format!("{name}_usd"), v)?;
|
||||
let cents: EagerVec<PcoVec<Height, Cents>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_cents"), v)?;
|
||||
let usd = LazyVecFrom1::transformed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
cents.read_only_boxed_clone(),
|
||||
);
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self { sats, btc, cents, usd })
|
||||
}
|
||||
|
||||
/// Eagerly compute USD height values: sats[h] * price[h].
|
||||
pub(crate) fn compute_usd(
|
||||
/// Eagerly compute cents height values: sats[h] * price_cents[h] / 1e8.
|
||||
pub(crate) fn compute_cents(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.cents.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.sats,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Lazy value type for Last pattern across all height-derived indexes.
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Sats, Version};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
use crate::internal::{LazyHeightDerivedLast, ValueFromHeightLast};
|
||||
@@ -40,7 +40,7 @@ impl LazyValueHeightDerivedLast {
|
||||
&source.sats.rest,
|
||||
);
|
||||
|
||||
let usd = LazyHeightDerivedLast::from_derived_computed::<DollarsTransform>(
|
||||
let usd = LazyHeightDerivedLast::from_lazy::<DollarsTransform, Cents>(
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
&source.usd.rest,
|
||||
|
||||
@@ -10,7 +10,7 @@ use brk_types::{Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use brk_types::{Dollars, Sats};
|
||||
use brk_types::{Cents, Sats};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
@@ -69,11 +69,11 @@ impl ValueFromHeightLastWindows {
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.compute_rolling_sum(max_from, starts, sats_source, usd_source, exit)?;
|
||||
w.compute_rolling_sum(max_from, starts, sats_source, cents_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
use brk_types::Cents;
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> Cents addition
|
||||
/// Used for computing total = profit + loss
|
||||
pub struct CentsPlus;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, Cents> for CentsPlus {
|
||||
#[inline(always)]
|
||||
fn apply(lhs: Cents, rhs: Cents) -> Cents {
|
||||
lhs + rhs
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use brk_types::Cents;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Cents * (V/10) -> Cents (e.g., V=8 -> * 0.8, V=24 -> * 2.4)
|
||||
pub struct CentsTimesTenths<const V: u16>;
|
||||
|
||||
impl<const V: u16> UnaryTransform<Cents, Cents> for CentsTimesTenths<V> {
|
||||
#[inline(always)]
|
||||
fn apply(c: Cents) -> Cents {
|
||||
// Use u128 to avoid overflow: c * V / 10
|
||||
Cents::from(c.as_u128() * V as u128 / 10)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use brk_types::Dollars;
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Dollars, Dollars) -> Dollars addition
|
||||
/// Used for computing total = profit + loss
|
||||
pub struct DollarsPlus;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, Dollars> for DollarsPlus {
|
||||
#[inline(always)]
|
||||
fn apply(lhs: Dollars, rhs: Dollars) -> Dollars {
|
||||
lhs + rhs
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::Dollars;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Dollars * (V/10) -> Dollars (e.g., V=8 -> * 0.8, V=24 -> * 2.4)
|
||||
pub struct DollarsTimesTenths<const V: u16>;
|
||||
|
||||
impl<const V: u16> UnaryTransform<Dollars, Dollars> for DollarsTimesTenths<V> {
|
||||
#[inline(always)]
|
||||
fn apply(d: Dollars) -> Dollars {
|
||||
d * (V as f64 / 10.0)
|
||||
}
|
||||
}
|
||||
@@ -1,68 +1,80 @@
|
||||
mod block_count_target;
|
||||
mod cents_plus;
|
||||
mod cents_signed_to_dollars;
|
||||
mod cents_times_tenths;
|
||||
mod cents_to_dollars;
|
||||
mod cents_to_sats;
|
||||
mod dollar_halve;
|
||||
mod dollar_identity;
|
||||
mod dollar_plus;
|
||||
mod dollar_times_tenths;
|
||||
mod dollars_to_sats_fract;
|
||||
mod f32_identity;
|
||||
mod neg_cents_to_dollars;
|
||||
mod ohlc_cents_to_dollars;
|
||||
mod ohlc_cents_to_sats;
|
||||
mod percentage_cents_f32;
|
||||
mod percentage_cents_signed_dollars_f32;
|
||||
mod percentage_cents_signed_f32;
|
||||
mod percentage_diff_close_cents;
|
||||
mod percentage_diff_close_dollars;
|
||||
mod percentage_dollars_f32;
|
||||
mod percentage_dollars_f32_neg;
|
||||
mod percentage_sats_f64;
|
||||
mod percentage_u32_f32;
|
||||
mod price_times_ratio;
|
||||
mod price_times_ratio_cents;
|
||||
mod ratio32;
|
||||
mod ratio64;
|
||||
mod ratio_cents64;
|
||||
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 sat_identity;
|
||||
mod sat_mask;
|
||||
mod sat_to_bitcoin;
|
||||
mod sats_to_dollars;
|
||||
mod u16_to_years;
|
||||
mod volatility_sqrt30;
|
||||
mod volatility_sqrt365;
|
||||
mod volatility_sqrt7;
|
||||
|
||||
pub use block_count_target::*;
|
||||
pub use cents_plus::*;
|
||||
pub use cents_signed_to_dollars::*;
|
||||
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 percentage_cents_f32::*;
|
||||
pub use percentage_cents_signed_dollars_f32::*;
|
||||
pub use percentage_cents_signed_f32::*;
|
||||
|
||||
pub use dollar_halve::*;
|
||||
pub use dollar_identity::*;
|
||||
pub use dollar_plus::*;
|
||||
pub use dollar_times_tenths::*;
|
||||
pub use dollars_to_sats_fract::*;
|
||||
pub use f32_identity::*;
|
||||
pub use percentage_diff_close_cents::*;
|
||||
pub use percentage_diff_close_dollars::*;
|
||||
pub use percentage_dollars_f32::*;
|
||||
pub use percentage_dollars_f32_neg::*;
|
||||
pub use percentage_sats_f64::*;
|
||||
pub use percentage_u32_f32::*;
|
||||
pub use price_times_ratio::*;
|
||||
pub use price_times_ratio_cents::*;
|
||||
pub use ratio32::*;
|
||||
pub use ratio64::*;
|
||||
pub use ratio_cents64::*;
|
||||
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 sat_identity::*;
|
||||
pub use sat_mask::*;
|
||||
pub use sat_to_bitcoin::*;
|
||||
pub use sats_to_dollars::*;
|
||||
pub use u16_to_years::*;
|
||||
pub use volatility_sqrt7::*;
|
||||
pub use volatility_sqrt30::*;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> StoredF32 percentage (a/b × 100)
|
||||
pub struct PercentageCentsF32;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, StoredF32> for PercentageCentsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> StoredF32 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / denominator.inner() as f64 * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{CentsSigned, Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (CentsSigned, Dollars) -> StoredF32 percentage (a/b × 100)
|
||||
/// For cross-type percentage when numerator is CentsSigned and denominator is Dollars.
|
||||
pub struct PercentageCentsSignedDollarsF32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Dollars, StoredF32> for PercentageCentsSignedDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Dollars) -> StoredF32 {
|
||||
if denominator == Dollars::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / *denominator * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{Cents, CentsSigned, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (CentsSigned, Cents) -> StoredF32 percentage (a/b × 100)
|
||||
/// For cross-type percentage when numerator is signed.
|
||||
pub struct PercentageCentsSignedCentsF32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Cents, StoredF32> for PercentageCentsSignedCentsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Cents) -> StoredF32 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / denominator.inner() as f64 * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
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,12 +0,0 @@
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// Dollars * StoredF32 -> Dollars (price × ratio)
|
||||
pub struct PriceTimesRatio;
|
||||
|
||||
impl BinaryTransform<Dollars, StoredF32, Dollars> for PriceTimesRatio {
|
||||
#[inline(always)]
|
||||
fn apply(price: Dollars, ratio: StoredF32) -> Dollars {
|
||||
price * ratio
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
pub struct PriceTimesRatioCents;
|
||||
|
||||
impl BinaryTransform<Cents, StoredF32, Cents> for PriceTimesRatioCents {
|
||||
#[inline(always)]
|
||||
fn apply(price: Cents, ratio: StoredF32) -> Cents {
|
||||
Cents::from(f64::from(price) * f64::from(ratio))
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use brk_types::{Dollars, StoredF64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF64 ratio
|
||||
/// Used for computing ratios like SOPR where f64 precision is needed.
|
||||
pub struct Ratio64;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, StoredF64> for Ratio64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF64 {
|
||||
numerator / denominator
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{Cents, StoredF64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> StoredF64 ratio
|
||||
/// Used for computing ratios like SOPR where f64 precision is needed.
|
||||
pub struct RatioCents64;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, StoredF64> for RatioCents64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> StoredF64 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF64::from(1.0)
|
||||
} else {
|
||||
StoredF64::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use brk_types::{Cents, Sats};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// Sats × Cents → Cents (sats × price_cents / 1e8)
|
||||
/// Uses u128 intermediate to avoid overflow.
|
||||
pub struct SatsToCents;
|
||||
|
||||
impl BinaryTransform<Sats, Cents, Cents> for SatsToCents {
|
||||
#[inline(always)]
|
||||
fn apply(sats: Sats, price_cents: Cents) -> Cents {
|
||||
Cents::from(sats.as_u128() * price_cents.as_u128() / Sats::ONE_BTC_U128)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::{Dollars, Sats};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// Sats × Dollars → Dollars (price * sats)
|
||||
pub struct SatsToDollars;
|
||||
|
||||
impl BinaryTransform<Sats, Dollars, Dollars> for SatsToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(sats: Sats, price: Dollars) -> Dollars {
|
||||
price * sats
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user