computer: snapshot

This commit is contained in:
nym21
2026-02-27 01:23:36 +01:00
parent 78fc5ffcf7
commit 72c17096ea
52 changed files with 3011 additions and 2967 deletions

View File

@@ -5,11 +5,9 @@
use brk_traversable::Traversable;
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct BlockWindows<A, B = A> {
#[traversable(rename = "1h")]
pub _1h: A,
#[traversable(rename = "24h")]
pub _24h: B,
}

View File

@@ -5,7 +5,6 @@
use brk_traversable::Traversable;
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct DistributionStats<A, B = A, C = A, D = A, E = A, F = A, G = A, H = A> {
pub average: A,
pub min: B,

View File

@@ -16,13 +16,11 @@ use crate::{
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightCumulative<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
}

View File

@@ -17,15 +17,12 @@ use crate::{
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightCumulativeFull<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
#[traversable(flatten)]
pub rolling: RollingFull<T, M>,
}

View File

@@ -18,15 +18,12 @@ use crate::{
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightCumulativeSum<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
#[traversable(flatten)]
pub rolling: RollingWindows<T, M>,
}

View File

@@ -16,7 +16,6 @@ use crate::indexes;
use crate::internal::{ComputedVecValue, NumericValue, RollingDistribution, WindowStarts};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,

View File

@@ -17,14 +17,12 @@ use crate::{
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightFull<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[traversable(flatten)]
pub height: Full<Height, T, M>,
#[traversable(flatten)]
pub full: Full<Height, T, M>,
pub rolling: RollingFull<T, M>,
}
@@ -45,7 +43,10 @@ where
let height = Full::forced_import(db, name, v)?;
let rolling = RollingFull::forced_import(db, name, v, indexes)?;
Ok(Self { height, rolling })
Ok(Self {
full: height,
rolling,
})
}
/// Compute Full stats via closure, then rolling windows from the per-block sum.
@@ -60,11 +61,11 @@ where
T: From<f64> + Default + SubAssign + Copy + Ord,
f64: From<T>,
{
compute_full(&mut self.height)?;
compute_full(&mut self.full)?;
self.rolling.compute(
max_from,
windows,
self.height.sum_cumulative.sum.inner(),
self.full.sum_cumulative.sum.inner(),
exit,
)?;
Ok(())

View File

@@ -18,7 +18,6 @@ const VERSION: Version = Version::ZERO;
/// Block full aggregation with lazy height transform + cumulative + rolling windows.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyComputedFromHeightFull<T, S = T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
@@ -47,12 +46,7 @@ where
let height = LazyVecFrom1::transformed::<F>(name, v, source.read_only_boxed_clone());
let rest = ComputedHeightDerivedCumulativeFull::forced_import(
db,
name,
v,
indexes,
)?;
let rest = ComputedHeightDerivedCumulativeFull::forced_import(db, name, v, indexes)?;
Ok(Self {
height,

View File

@@ -17,9 +17,7 @@ use crate::{
/// Generic price metric with both USD and sats representations.
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct Price<U> {
#[traversable(flatten)]
pub usd: U,
pub sats: LazyFromHeightLast<SatsFract, Dollars>,
}
@@ -65,4 +63,3 @@ where
Self { usd, sats }
}
}

View File

@@ -9,7 +9,6 @@ use crate::{ComputeIndexes, blocks, indexes, prices};
use super::{ComputedFromHeightRatio, ComputedFromHeightRatioExtension};
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightRatioExtended<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
@@ -44,12 +43,8 @@ impl ComputedFromHeightRatioExtended {
let close_price = &prices.usd.price;
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_rest(blocks, starting_indexes, exit, &self.base.ratio.height)?;
self.extended
.compute_usd_bands(starting_indexes, metric_price, exit)?;
Ok(())

View File

@@ -10,7 +10,6 @@ use crate::{ComputeIndexes, blocks, indexes, prices};
use super::ComputedFromHeightRatioExtended;
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightPriceWithRatioExtended<M: StorageMode = Rw> {
#[deref]
#[deref_mut]

View File

@@ -1,7 +1,10 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, StoredF32, Version};
use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, WritableVec};
use vecdb::{
AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex,
WritableVec,
};
use crate::{ComputeIndexes, blocks, indexes};
@@ -10,7 +13,6 @@ use crate::internal::{ComputedFromHeightLast, Price};
use super::ComputedFromHeightStdDev;
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightStdDevExtended<M: StorageMode = Rw> {
#[traversable(flatten)]
pub base: ComputedFromHeightStdDev<M>,
@@ -68,12 +70,7 @@ impl ComputedFromHeightStdDevExtended {
macro_rules! import_usd {
($suffix:expr) => {
Price::forced_import(
db,
&format!("{name}_{}", $suffix),
version,
indexes,
)?
Price::forced_import(db, &format!("{name}_{}", $suffix), version, indexes)?
};
}
@@ -115,7 +112,8 @@ impl ComputedFromHeightStdDevExtended {
exit: &Exit,
source: &impl ReadableVec<Height, StoredF32>,
) -> Result<()> {
self.base.compute_all(blocks, starting_indexes, exit, source)?;
self.base
.compute_all(blocks, starting_indexes, exit, source)?;
let sma_opt: Option<&EagerVec<PcoVec<Height, StoredF32>>> = None;
self.compute_bands(starting_indexes, exit, sma_opt, source)
@@ -148,37 +146,54 @@ impl ComputedFromHeightStdDevExtended {
let source_len = source.len();
let source_data = source.collect_range_at(start, source_len);
let sma_len = sma_opt.map(|s| s.len()).unwrap_or(self.base.sma.height.len());
let sma_len = sma_opt
.map(|s| s.len())
.unwrap_or(self.base.sma.height.len());
let sma_data: Vec<StoredF32> = if let Some(sma) = sma_opt {
sma.collect_range_at(start, sma_len)
} else {
self.base.sma.height.collect_range_at(start, sma_len)
};
let sd_data = self.base.sd.height.collect_range_at(start, self.base.sd.height.len());
let sd_data = self
.base
.sd
.height
.collect_range_at(start, self.base.sd.height.len());
for (offset, _ratio) in source_data.into_iter().enumerate() {
let index = start + offset;
let average = sma_data[offset];
let sd = sd_data[offset];
self.p0_5sd.height.truncate_push_at(index, average + StoredF32::from(0.5 * *sd))?;
self.p0_5sd
.height
.truncate_push_at(index, average + StoredF32::from(0.5 * *sd))?;
self.p1sd.height.truncate_push_at(index, average + sd)?;
self.p1_5sd.height.truncate_push_at(index, average + StoredF32::from(1.5 * *sd))?;
self.p1_5sd
.height
.truncate_push_at(index, average + StoredF32::from(1.5 * *sd))?;
self.p2sd.height.truncate_push_at(index, average + 2 * sd)?;
self.p2_5sd.height.truncate_push_at(index, average + StoredF32::from(2.5 * *sd))?;
self.p2_5sd
.height
.truncate_push_at(index, average + StoredF32::from(2.5 * *sd))?;
self.p3sd.height.truncate_push_at(index, average + 3 * sd)?;
self.m0_5sd.height.truncate_push_at(index, average - StoredF32::from(0.5 * *sd))?;
self.m0_5sd
.height
.truncate_push_at(index, average - StoredF32::from(0.5 * *sd))?;
self.m1sd.height.truncate_push_at(index, average - sd)?;
self.m1_5sd.height.truncate_push_at(index, average - StoredF32::from(1.5 * *sd))?;
self.m1_5sd
.height
.truncate_push_at(index, average - StoredF32::from(1.5 * *sd))?;
self.m2sd.height.truncate_push_at(index, average - 2 * sd)?;
self.m2_5sd.height.truncate_push_at(index, average - StoredF32::from(2.5 * *sd))?;
self.m2_5sd
.height
.truncate_push_at(index, average - StoredF32::from(2.5 * *sd))?;
self.m3sd.height.truncate_push_at(index, average - 3 * sd)?;
}
{
let _lock = exit.lock();
self.mut_band_height_vecs()
.try_for_each(|v| v.flush())?;
self.mut_band_height_vecs().try_for_each(|v| v.flush())?;
}
if let Some(sma) = sma_opt {
@@ -213,7 +228,8 @@ impl ComputedFromHeightStdDevExtended {
macro_rules! compute_band {
($usd_field:ident, $band_source:expr) => {
self.$usd_field.usd
self.$usd_field
.usd
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
starting_indexes.height,
metric_price,

View File

@@ -16,7 +16,6 @@ use crate::{
};
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct ValueFromHeightLastRolling<M: StorageMode = Rw> {
#[deref]
#[deref_mut]

View File

@@ -1,11 +1,14 @@
//! LazyFromTxDistribution - lazy txindex source + computed distribution.
//! ComputedFromTxDistribution - stored per-tx EagerVec + computed distribution.
//!
//! Like LazyFromTxDistribution, but the per-tx source is eagerly computed
//! and stored rather than lazily derived.
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::TxIndex;
use schemars::JsonSchema;
use vecdb::{Database, Exit, LazyVecFrom2, ReadableVec, Rw, StorageMode, Version};
use vecdb::{Database, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode, Version};
use crate::{
ComputeIndexes, indexes,
@@ -13,30 +16,21 @@ use crate::{
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct LazyFromTxDistribution<T, S1, S2, M: StorageMode = Rw>
pub struct ComputedFromTxDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1: ComputedVecValue,
S2: ComputedVecValue,
{
pub txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
pub txindex: M::Stored<EagerVec<PcoVec<TxIndex, T>>>,
#[traversable(flatten)]
pub distribution: TxDerivedDistribution<T, M>,
}
impl<T, S1, S2> LazyFromTxDistribution<T, S1, S2>
impl<T> ComputedFromTxDistribution<T>
where
T: NumericValue + JsonSchema,
S1: ComputedVecValue + JsonSchema,
S2: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
) -> Result<Self> {
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
let txindex = EagerVec::forced_import(db, name, version)?;
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
Ok(Self {
txindex,
@@ -44,26 +38,28 @@ where
})
}
pub(crate) fn derive_from(
#[allow(clippy::too_many_arguments)]
pub(crate) fn derive_from_with_skip(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
exit: &Exit,
skip_count: usize,
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>: ReadableVec<TxIndex, T>,
{
self.distribution.derive_from(
self.distribution.derive_from_with_skip(
indexer,
indexes,
starting_indexes,
block_windows,
&self.txindex,
exit,
skip_count,
)
}
}

View File

@@ -0,0 +1,68 @@
//! LazyFromTxDistribution - lazy txindex source + computed distribution.
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::TxIndex;
use schemars::JsonSchema;
use vecdb::{Database, Exit, LazyVecFrom2, ReadableVec, Rw, StorageMode, Version};
use crate::{
ComputeIndexes, indexes,
internal::{BlockWindowStarts, ComputedVecValue, NumericValue, TxDerivedDistribution},
};
#[derive(Traversable)]
pub struct LazyFromTxDistribution<T, S1, S2, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1: ComputedVecValue,
S2: ComputedVecValue,
{
pub txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
#[traversable(flatten)]
pub distribution: TxDerivedDistribution<T, M>,
}
impl<T, S1, S2> LazyFromTxDistribution<T, S1, S2>
where
T: NumericValue + JsonSchema,
S1: ComputedVecValue + JsonSchema,
S2: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
) -> Result<Self> {
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
Ok(Self {
txindex,
distribution,
})
}
pub(crate) fn derive_from(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
exit: &Exit,
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>: ReadableVec<TxIndex, T>,
{
self.distribution.derive_from(
indexer,
indexes,
starting_indexes,
block_windows,
&self.txindex,
exit,
)
}
}

View File

@@ -1,3 +1,5 @@
mod distribution;
mod lazy_distribution;
pub use distribution::*;
pub use lazy_distribution::*;

View File

@@ -17,12 +17,10 @@ use crate::{
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedHeightDerivedCumulativeFull<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
#[traversable(flatten)]
pub rolling: RollingFull<T, M>,

View File

@@ -13,11 +13,12 @@ use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, Version};
use crate::{
ComputeIndexes, indexes,
internal::{BlockRollingDistribution, BlockWindowStarts, ComputedVecValue, Distribution, NumericValue},
internal::{
BlockRollingDistribution, BlockWindowStarts, ComputedVecValue, Distribution, NumericValue,
},
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct TxDerivedDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
@@ -31,11 +32,7 @@ impl<T> TxDerivedDistribution<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
) -> Result<Self> {
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
let block = Distribution::forced_import(db, name, version)?;
let rolling = BlockRollingDistribution::forced_import(db, name, version)?;

View File

@@ -18,12 +18,10 @@ use crate::{
/// Sum (4 windows) + Distribution (8 stats × 4 windows) = 36 stored height vecs.
#[derive(Traversable)]
#[traversable(merge)]
pub struct RollingFull<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(flatten)]
pub sum: RollingWindows<T, M>,
#[traversable(flatten)]
pub distribution: RollingDistribution<T, M>,

View File

@@ -24,11 +24,6 @@ impl<I: VecIndex, T: ComputedVecValue + JsonSchema> CumulativeVec<I, T> {
)?))
}
#[inline]
pub(crate) fn inner(&self) -> &EagerVec<PcoVec<I, T>> {
&self.0
}
pub fn read_only_clone(&self) -> CumulativeVec<I, T, Ro> {
CumulativeVec(StoredVec::read_only_clone(&self.0))
}

View File

@@ -5,7 +5,6 @@
use brk_traversable::Traversable;
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct Windows<A, B = A, C = A, D = A> {
#[traversable(rename = "24h")]
pub _24h: A,