global: snapshot

This commit is contained in:
nym21
2026-03-05 18:08:10 +01:00
parent 2ae542ecdb
commit 266342cd98
10 changed files with 684 additions and 556 deletions

View File

@@ -6,8 +6,8 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{
blocks,
internal::{
ComputedFromHeightRatioExtension, PercentFromHeight, RatioCents64, RatioDollarsBp32,
RollingWindows,
ComputedFromHeightRatioPercentiles, ComputedFromHeightRatioStdDevBands,
PercentFromHeight, RatioCents64, RatioDollarsBp32, RollingWindows,
},
};
@@ -24,8 +24,10 @@ pub struct RealizedExtended<M: StorageMode = Rw> {
pub realized_profit_to_loss_ratio: RollingWindows<StoredF64, M>,
pub realized_price_ratio_ext: ComputedFromHeightRatioExtension<M>,
pub investor_price_ratio_ext: ComputedFromHeightRatioExtension<M>,
pub realized_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub realized_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands<M>,
pub investor_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub investor_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands<M>,
}
impl RealizedExtended {
@@ -37,13 +39,27 @@ impl RealizedExtended {
realized_loss_sum: cfg.import_rolling("realized_loss", Version::ONE)?,
realized_profit_to_loss_ratio: cfg
.import_rolling("realized_profit_to_loss_ratio", Version::ONE)?,
realized_price_ratio_ext: ComputedFromHeightRatioExtension::forced_import(
realized_price_ratio_percentiles:
ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&cfg.name("realized_price"),
cfg.version + Version::ONE,
cfg.indexes,
)?,
realized_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
cfg.db,
&cfg.name("realized_price"),
cfg.version + Version::ONE,
cfg.indexes,
)?,
investor_price_ratio_ext: ComputedFromHeightRatioExtension::forced_import(
investor_price_ratio_percentiles:
ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&cfg.name("investor_price"),
cfg.version,
cfg.indexes,
)?,
investor_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
cfg.db,
&cfg.name("investor_price"),
cfg.version,
@@ -101,29 +117,36 @@ impl RealizedExtended {
)?;
}
// Extended ratio metrics
self.realized_price_ratio_ext.compute_rest(
// Realized price ratio: percentiles + stddev
self.realized_price_ratio_percentiles.compute(
blocks,
starting_indexes,
exit,
&base.realized_price_ratio.ratio.height,
)?;
self.realized_price_ratio_ext.compute_cents_bands(
starting_indexes,
&base.realized_price.cents.height,
)?;
self.realized_price_ratio_std_dev.compute(
blocks,
starting_indexes,
exit,
&base.realized_price_ratio.ratio.height,
&base.realized_price.cents.height,
)?;
self.investor_price_ratio_ext.compute_rest(
// Investor price ratio: percentiles + stddev
self.investor_price_ratio_percentiles.compute(
blocks,
starting_indexes,
exit,
&base.investor_price_ratio.ratio.height,
)?;
self.investor_price_ratio_ext.compute_cents_bands(
starting_indexes,
&base.investor_price.cents.height,
)?;
self.investor_price_ratio_std_dev.compute(
blocks,
starting_indexes,
exit,
&base.investor_price_ratio.ratio.height,
&base.investor_price.cents.height,
)?;
Ok(())

View File

@@ -6,7 +6,7 @@ use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, indexes, prices};
use super::{ComputedFromHeightRatio, ComputedFromHeightRatioExtension};
use super::{ComputedFromHeightRatio, ComputedFromHeightRatioPercentiles};
#[derive(Deref, DerefMut, Traversable)]
pub struct ComputedFromHeightRatioExtended<M: StorageMode = Rw> {
@@ -15,7 +15,7 @@ pub struct ComputedFromHeightRatioExtended<M: StorageMode = Rw> {
#[traversable(flatten)]
pub base: ComputedFromHeightRatio<M>,
#[traversable(flatten)]
pub extended: ComputedFromHeightRatioExtension<M>,
pub percentiles: ComputedFromHeightRatioPercentiles<M>,
}
impl ComputedFromHeightRatioExtended {
@@ -27,11 +27,13 @@ impl ComputedFromHeightRatioExtended {
) -> Result<Self> {
Ok(Self {
base: ComputedFromHeightRatio::forced_import(db, name, version, indexes)?,
extended: ComputedFromHeightRatioExtension::forced_import(db, name, version, indexes)?,
percentiles: ComputedFromHeightRatioPercentiles::forced_import(
db, name, version, indexes,
)?,
})
}
/// Compute ratio and all extended metrics from an externally-provided metric price (in cents).
/// Compute ratio and all percentile metrics from an externally-provided metric price (in cents).
pub(crate) fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
@@ -43,10 +45,8 @@ impl ComputedFromHeightRatioExtended {
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_cents_bands(starting_indexes, metric_price, exit)?;
self.percentiles
.compute(blocks, starting_indexes, exit, &self.base.ratio.height, metric_price)?;
Ok(())
}
}

View File

@@ -0,0 +1,51 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, indexes, prices};
use super::{ComputedFromHeightRatioExtended, ComputedFromHeightRatioStdDevBands};
#[derive(Deref, DerefMut, Traversable)]
pub struct ComputedFromHeightRatioFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: ComputedFromHeightRatioExtended<M>,
#[traversable(flatten)]
pub std_dev: ComputedFromHeightRatioStdDevBands<M>,
}
impl ComputedFromHeightRatioFull {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self {
base: ComputedFromHeightRatioExtended::forced_import(db, name, version, indexes)?,
std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
db, name, version, indexes,
)?,
})
}
/// Compute ratio, percentiles, and all stddev bands from an externally-provided metric price (in cents).
pub(crate) fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
metric_price: &impl ReadableVec<Height, Cents>,
) -> Result<()> {
self.base
.compute_rest(blocks, prices, starting_indexes, exit, metric_price)?;
self.std_dev
.compute(blocks, starting_indexes, exit, &self.base.base.ratio.height, metric_price)?;
Ok(())
}
}

View File

@@ -1,10 +1,14 @@
mod extended;
mod extension;
mod full;
mod percentiles;
mod price_extended;
mod std_dev_bands;
pub use extended::*;
pub use extension::*;
pub use full::*;
pub use percentiles::*;
pub use price_extended::*;
pub use std_dev_bands::*;
use brk_error::Result;
use brk_traversable::Traversable;

View File

@@ -8,13 +8,13 @@ use vecdb::{
use crate::{
blocks, indexes,
internal::{ComputedFromHeightStdDevExtended, ExpandingPercentiles, Price, PriceTimesRatioBp32Cents},
internal::{ExpandingPercentiles, Price, PriceTimesRatioBp32Cents},
};
use super::{super::ComputedFromHeight, ComputedFromHeightRatio};
#[derive(Traversable)]
pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
pub struct ComputedFromHeightRatioPercentiles<M: StorageMode = Rw> {
pub ratio_sma_1w: ComputedFromHeightRatio<M>,
pub ratio_sma_1m: ComputedFromHeightRatio<M>,
pub ratio_pct99: ComputedFromHeightRatio<M>,
@@ -30,18 +30,13 @@ pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
pub ratio_pct2_price: Price<ComputedFromHeight<Cents, M>>,
pub ratio_pct1_price: Price<ComputedFromHeight<Cents, M>>,
pub ratio_sd: ComputedFromHeightStdDevExtended<M>,
pub ratio_sd_4y: ComputedFromHeightStdDevExtended<M>,
pub ratio_sd_2y: ComputedFromHeightStdDevExtended<M>,
pub ratio_sd_1y: ComputedFromHeightStdDevExtended<M>,
#[traversable(skip)]
expanding_pct: ExpandingPercentiles,
}
const VERSION: Version = Version::new(4);
impl ComputedFromHeightRatioExtension {
impl ComputedFromHeightRatioPercentiles {
pub(crate) fn forced_import(
db: &Database,
name: &str,
@@ -61,19 +56,6 @@ impl ComputedFromHeightRatioExtension {
};
}
macro_rules! import_sd {
($suffix:expr, $period:expr, $days:expr) => {
ComputedFromHeightStdDevExtended::forced_import(
db,
&format!("{name}_{}", $suffix),
$period,
$days,
v,
indexes,
)?
};
}
macro_rules! import_price {
($suffix:expr) => {
Price::forced_import(db, &format!("{name}_{}", $suffix), v, indexes)?
@@ -83,10 +65,6 @@ impl ComputedFromHeightRatioExtension {
Ok(Self {
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!("ratio_pct99"),
ratio_pct98: import_ratio!("ratio_pct98"),
ratio_pct95: import_ratio!("ratio_pct95"),
@@ -103,14 +81,14 @@ impl ComputedFromHeightRatioExtension {
})
}
pub(crate) fn compute_rest(
pub(crate) fn compute(
&mut self,
blocks: &blocks::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
ratio_source: &impl ReadableVec<Height, StoredF32>,
metric_price: &impl ReadableVec<Height, Cents>,
) -> Result<()> {
// SMA using lookback vecs
self.ratio_sma_1w.bps.height.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1w_ago,
@@ -151,7 +129,6 @@ 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, BasisPoints32>>; 6] = [
&mut self.ratio_pct1.bps.height,
@@ -179,25 +156,7 @@ impl ComputedFromHeightRatioExtension {
self.mut_pct_vecs().try_for_each(|v| v.flush())?;
}
// Compute stddev at height level
for sd in [
&mut self.ratio_sd,
&mut self.ratio_sd_4y,
&mut self.ratio_sd_2y,
&mut self.ratio_sd_1y,
] {
sd.compute_all(blocks, starting_indexes, exit, ratio_source)?;
}
Ok(())
}
pub(crate) fn compute_cents_bands(
&mut self,
starting_indexes: &Indexes,
metric_price: &impl ReadableVec<Height, Cents>,
exit: &Exit,
) -> Result<()> {
// Cents bands
macro_rules! compute_band {
($usd_field:ident, $band_source:expr) => {
self.$usd_field
@@ -218,16 +177,6 @@ impl ComputedFromHeightRatioExtension {
compute_band!(ratio_pct2_price, &self.ratio_pct2.bps.height);
compute_band!(ratio_pct1_price, &self.ratio_pct1.bps.height);
// Stddev cents bands
for sd in [
&mut self.ratio_sd,
&mut self.ratio_sd_4y,
&mut self.ratio_sd_2y,
&mut self.ratio_sd_1y,
] {
sd.compute_cents_bands(starting_indexes, metric_price, exit)?;
}
Ok(())
}

View File

@@ -0,0 +1,68 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Height, Indexes, StoredF32, Version};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, indexes, internal::ComputedFromHeightStdDevExtended};
#[derive(Traversable)]
pub struct ComputedFromHeightRatioStdDevBands<M: StorageMode = Rw> {
pub ratio_sd: ComputedFromHeightStdDevExtended<M>,
pub ratio_sd_4y: ComputedFromHeightStdDevExtended<M>,
pub ratio_sd_2y: ComputedFromHeightStdDevExtended<M>,
pub ratio_sd_1y: ComputedFromHeightStdDevExtended<M>,
}
const VERSION: Version = Version::new(4);
impl ComputedFromHeightRatioStdDevBands {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
macro_rules! import_sd {
($suffix:expr, $period:expr, $days:expr) => {
ComputedFromHeightStdDevExtended::forced_import(
db,
&format!("{name}_{}", $suffix),
$period,
$days,
v,
indexes,
)?
};
}
Ok(Self {
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),
})
}
pub(crate) fn compute(
&mut self,
blocks: &blocks::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
ratio_source: &impl ReadableVec<Height, StoredF32>,
metric_price: &impl ReadableVec<Height, Cents>,
) -> Result<()> {
for sd in [
&mut self.ratio_sd,
&mut self.ratio_sd_4y,
&mut self.ratio_sd_2y,
&mut self.ratio_sd_1y,
] {
sd.compute_all(blocks, starting_indexes, exit, ratio_source)?;
sd.compute_cents_bands(starting_indexes, metric_price, exit)?;
}
Ok(())
}
}

View File

@@ -61,12 +61,12 @@ impl Vecs {
}
// DCA by period - average price (derived from stack)
let sh = starting_indexes.height.to_usize();
let starting_height = starting_indexes.height.to_usize();
for (average_price, stack, days) in
self.period_cost_basis.zip_mut_with_days(&self.period_stack)
{
let days = days as usize;
let start = average_price.cents.height.len().min(starting_indexes.height.to_usize());
let start = average_price.cents.height.len().min(starting_height);
let stack_data = stack
.sats
.height
@@ -124,7 +124,7 @@ impl Vecs {
self.period_lump_sum_stack.zip_mut_with_days(&lookback_dca)
{
let total_invested = DCA_AMOUNT * days as usize;
let ls_start = stack.sats.height.len().min(starting_indexes.height.to_usize());
let ls_start = stack.sats.height.len().min(starting_height);
let lookback_data = lookback_price
.cents
.height
@@ -163,8 +163,8 @@ impl Vecs {
let start_days = super::ByDcaClass::<()>::start_days();
for (stack, day1) in self.class_stack.iter_mut().zip(start_days) {
let mut last_di: Option<Day1> = None;
let mut prev_value = if sh > 0 {
stack.sats.height.collect_one_at(sh - 1).unwrap_or_default()
let mut prev_value = if starting_height > 0 {
stack.sats.height.collect_one_at(starting_height - 1).unwrap_or_default()
} else {
Sats::ZERO
};
@@ -219,7 +219,7 @@ impl Vecs {
.zip(start_days)
{
let from_usize = from.to_usize();
let cls_start = average_price.cents.height.len().min(starting_indexes.height.to_usize());
let cls_start = average_price.cents.height.len().min(starting_height);
let stack_data = stack
.sats
.height