computer: snapshot

This commit is contained in:
nym21
2026-02-27 10:54:36 +01:00
parent 72c17096ea
commit c75421f46e
44 changed files with 1079 additions and 722 deletions
+21 -13
View File
@@ -19,12 +19,24 @@ impl Vecs {
exit: &Exit,
) -> Result<()> {
self.compute_prices(indexer, starting_indexes, exit)?;
self.open
self.split
.open
.compute_first(starting_indexes, &self.price, indexes, exit)?;
self.high
self.split
.high
.compute_max(starting_indexes, &self.price, indexes, exit)?;
self.low
self.split
.low
.compute_min(starting_indexes, &self.price, indexes, exit)?;
self.ohlc.compute_from_split(
starting_indexes,
&self.split.open,
&self.split.high,
&self.split.low,
&self.split.close,
indexes,
exit,
)?;
Ok(())
}
@@ -132,6 +144,10 @@ impl Vecs {
// across blocks, so the cursor only advances forward.
let mut txout_cursor = indexer.vecs.transactions.first_txoutindex.cursor();
// Reusable buffers — avoid per-block allocation
let mut values: Vec<Sats> = Vec::new();
let mut output_types: Vec<OutputType> = Vec::new();
for (idx, _h) in range.enumerate() {
let first_txindex = first_txindexes[idx];
let next_first_txindex = first_txindexes
@@ -156,16 +172,8 @@ impl Vecs {
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
let values: Vec<Sats> = indexer
.vecs
.outputs
.value
.collect_range_at(out_start, out_end);
let output_types: Vec<OutputType> = indexer
.vecs
.outputs
.outputtype
.collect_range_at(out_start, out_end);
indexer.vecs.outputs.value.collect_range_into_at(out_start, out_end, &mut values);
indexer.vecs.outputs.outputtype.collect_range_into_at(out_start, out_end, &mut output_types);
let mut hist = [0u32; NUM_BINS];
for i in 0..values.len() {
+11 -7
View File
@@ -5,6 +5,7 @@ use vecdb::{Database, ImportableVec, PcoVec, ReadableCloneableVec};
use super::Vecs;
use crate::indexes;
use crate::internal::{ComputedHeightDerivedLast, EagerIndexes};
use crate::prices::{ohlcs::OhlcVecs, split::SplitOhlc};
impl Vecs {
pub(crate) fn forced_import(
@@ -16,23 +17,26 @@ impl Vecs {
let price = PcoVec::forced_import(db, "price_cents", version)?;
let open = EagerIndexes::forced_import(db, "price_cents_open", version)?;
let high = EagerIndexes::forced_import(db, "price_cents_high", version)?;
let low = EagerIndexes::forced_import(db, "price_cents_low", version)?;
let open = EagerIndexes::forced_import(db, "price_open_cents", version)?;
let high = EagerIndexes::forced_import(db, "price_high_cents", version)?;
let low = EagerIndexes::forced_import(db, "price_low_cents", version)?;
let close = ComputedHeightDerivedLast::forced_import(
"price_cents_close",
"price_close_cents",
price.read_only_boxed_clone(),
version,
indexes,
);
Ok(Self {
price,
let split = SplitOhlc {
open,
high,
low,
close,
})
};
let ohlc = OhlcVecs::forced_import(db, "price_ohlc_cents", version)?;
Ok(Self { split, ohlc, price })
}
}
+10 -5
View File
@@ -1,14 +1,19 @@
use brk_traversable::Traversable;
use brk_types::{Cents, Height};
use brk_types::{Cents, Height, OHLCCents};
use vecdb::{PcoVec, Rw, StorageMode};
use crate::internal::{ComputedHeightDerivedLast, EagerIndexes};
use crate::prices::{ohlcs::OhlcVecs, split::SplitOhlc};
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
#[allow(clippy::type_complexity)]
pub split: SplitOhlc<
EagerIndexes<Cents, M>,
EagerIndexes<Cents, M>,
EagerIndexes<Cents, M>,
ComputedHeightDerivedLast<Cents>,
>,
pub ohlc: OhlcVecs<OHLCCents, M>,
pub price: M::Stored<PcoVec<Height, Cents>>,
pub open: EagerIndexes<Cents, M>,
pub high: EagerIndexes<Cents, M>,
pub low: EagerIndexes<Cents, M>,
pub close: ComputedHeightDerivedLast<Cents>,
}
+2
View File
@@ -1,4 +1,6 @@
mod compute;
pub(crate) mod ohlcs;
pub(crate) mod split;
pub mod cents;
pub mod sats;
+205
View File
@@ -0,0 +1,205 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
Cents, Close, Day1, Day3, DifficultyEpoch, HalvingEpoch, High, Hour1, Hour4, Hour12, Low,
Minute1, Minute5, Minute10, Minute30, Month1, Month3, Month6, OHLCCents, Open, Version, Week1,
Year1, Year10,
};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use serde::Serialize;
use vecdb::{
BytesVec, BytesVecValue, Database, EagerVec, Exit, Formattable, ImportableVec, LazyVecFrom1,
ReadableCloneableVec, ReadableVec, Rw, StorageMode, UnaryTransform,
};
use crate::{
ComputeIndexes, indexes, indexes_from,
internal::{ComputedHeightDerivedLast, EagerIndexes, Indexes},
};
// ── EagerOhlcIndexes ─────────────────────────────────────────────────
#[derive(Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct OhlcVecs<T, M: StorageMode = Rw>(
#[allow(clippy::type_complexity)]
pub Indexes<
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute5, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute10, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute30, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour4, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour12, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Day1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Day3, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Week1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Month1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Month3, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Month6, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Year1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Year10, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<HalvingEpoch, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<DifficultyEpoch, T>>>,
>,
)
where
T: BytesVecValue + Formattable + Serialize + JsonSchema;
const EAGER_VERSION: Version = Version::ZERO;
impl<T> OhlcVecs<T>
where
T: BytesVecValue + Formattable + Serialize + JsonSchema,
{
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
let v = version + EAGER_VERSION;
macro_rules! period {
($idx:ident) => {
ImportableVec::forced_import(db, &format!("{name}_{}", stringify!($idx)), v)?
};
}
Ok(Self(indexes_from!(period)))
}
}
impl OhlcVecs<OHLCCents> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_from_split(
&mut self,
starting_indexes: &ComputeIndexes,
open: &EagerIndexes<Cents>,
high: &EagerIndexes<Cents>,
low: &EagerIndexes<Cents>,
close: &ComputedHeightDerivedLast<Cents>,
indexes: &indexes::Vecs,
exit: &Exit,
) -> Result<()> {
macro_rules! period {
($field:ident) => {
self.0.$field.compute_transform(
starting_indexes.$field,
&indexes.$field.first_height,
|(idx, _first_h, _)| {
let o = open.$field.collect_one(idx).unwrap_or_default();
let h = high.$field.collect_one(idx).unwrap_or_default();
let l = low.$field.collect_one(idx).unwrap_or_default();
let c = close.$field.collect_one(idx).flatten().unwrap_or_default();
(
idx,
OHLCCents {
open: Open::new(o),
high: High::new(h),
low: Low::new(l),
close: Close::new(c),
},
)
},
exit,
)?;
};
}
macro_rules! epoch {
($field:ident) => {
self.0.$field.compute_transform(
starting_indexes.$field,
&indexes.$field.first_height,
|(idx, _first_h, _)| {
let o = open.$field.collect_one(idx).unwrap_or_default();
let h = high.$field.collect_one(idx).unwrap_or_default();
let l = low.$field.collect_one(idx).unwrap_or_default();
let c = close.$field.collect_one(idx).unwrap_or_default();
(
idx,
OHLCCents {
open: Open::new(o),
high: High::new(h),
low: Low::new(l),
close: Close::new(c),
},
)
},
exit,
)?;
};
}
period!(minute1);
period!(minute5);
period!(minute10);
period!(minute30);
period!(hour1);
period!(hour4);
period!(hour12);
period!(day1);
period!(day3);
period!(week1);
period!(month1);
period!(month3);
period!(month6);
period!(year1);
period!(year10);
epoch!(halvingepoch);
epoch!(difficultyepoch);
Ok(())
}
}
// ── LazyOhlcIndexes ──────────────────────────────────────────────────
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyOhlcVecs<T, S>(
#[allow(clippy::type_complexity)]
pub Indexes<
LazyVecFrom1<Minute1, T, Minute1, S>,
LazyVecFrom1<Minute5, T, Minute5, S>,
LazyVecFrom1<Minute10, T, Minute10, S>,
LazyVecFrom1<Minute30, T, Minute30, S>,
LazyVecFrom1<Hour1, T, Hour1, S>,
LazyVecFrom1<Hour4, T, Hour4, S>,
LazyVecFrom1<Hour12, T, Hour12, S>,
LazyVecFrom1<Day1, T, Day1, S>,
LazyVecFrom1<Day3, T, Day3, S>,
LazyVecFrom1<Week1, T, Week1, S>,
LazyVecFrom1<Month1, T, Month1, S>,
LazyVecFrom1<Month3, T, Month3, S>,
LazyVecFrom1<Month6, T, Month6, S>,
LazyVecFrom1<Year1, T, Year1, S>,
LazyVecFrom1<Year10, T, Year10, S>,
LazyVecFrom1<HalvingEpoch, T, HalvingEpoch, S>,
LazyVecFrom1<DifficultyEpoch, T, DifficultyEpoch, S>,
>,
)
where
T: BytesVecValue + Formattable + Serialize + JsonSchema,
S: BytesVecValue;
impl<T, S> LazyOhlcVecs<T, S>
where
T: BytesVecValue + Formattable + Serialize + JsonSchema,
S: BytesVecValue + Formattable + Serialize + JsonSchema,
{
pub(crate) fn from_eager_ohlc_indexes<Transform: UnaryTransform<S, T>>(
name: &str,
version: Version,
source: &OhlcVecs<S>,
) -> Self {
macro_rules! period {
($idx:ident) => {
LazyVecFrom1::transformed::<Transform>(
&format!("{name}_{}", stringify!($idx)),
version,
source.$idx.read_only_boxed_clone(),
)
};
}
Self(indexes_from!(period))
}
}
+29 -11
View File
@@ -3,9 +3,10 @@ use vecdb::{LazyVecFrom1, ReadableCloneableVec};
use super::super::cents;
use super::Vecs;
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
use crate::{
indexes,
internal::{CentsUnsignedToSats, ComputedHeightDerivedLast, LazyEagerIndexes},
internal::{CentsUnsignedToSats, ComputedHeightDerivedLast, LazyEagerIndexes, OhlcCentsToSats},
};
impl Vecs {
@@ -21,26 +22,43 @@ impl Vecs {
);
// Sats are inversely related to cents (sats = 10B/cents), so high↔low are swapped
let open =
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>("price_sats_open", version, &cents.open);
let high =
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>("price_sats_high", version, &cents.low);
let low =
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>("price_sats_low", version, &cents.high);
let open = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>(
"price_open_sats",
version,
&cents.split.open,
);
let high = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>(
"price_high_sats",
version,
&cents.split.low,
);
let low = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>(
"price_low_sats",
version,
&cents.split.high,
);
let close = ComputedHeightDerivedLast::forced_import(
"price_sats_close",
"price_close_sats",
price.read_only_boxed_clone(),
version,
indexes,
);
Self {
price,
let split = SplitOhlc {
open,
high,
low,
close,
}
};
// OhlcCentsToSats handles the high↔low swap internally
let ohlc = LazyOhlcVecs::from_eager_ohlc_indexes::<OhlcCentsToSats>(
"price_ohlc_sats",
version,
&cents.ohlc,
);
Self { split, ohlc, price }
}
}
+10 -5
View File
@@ -1,14 +1,19 @@
use brk_traversable::Traversable;
use brk_types::{Cents, Height, Sats};
use brk_types::{Cents, Height, OHLCCents, OHLCSats, Sats};
use vecdb::LazyVecFrom1;
use crate::internal::{ComputedHeightDerivedLast, LazyEagerIndexes};
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
#[derive(Clone, Traversable)]
pub struct Vecs {
#[allow(clippy::type_complexity)]
pub split: SplitOhlc<
LazyEagerIndexes<Sats, Cents>,
LazyEagerIndexes<Sats, Cents>,
LazyEagerIndexes<Sats, Cents>,
ComputedHeightDerivedLast<Sats>,
>,
pub ohlc: LazyOhlcVecs<OHLCSats, OHLCCents>,
pub price: LazyVecFrom1<Height, Sats, Height, Cents>,
pub open: LazyEagerIndexes<Sats, Cents>,
pub high: LazyEagerIndexes<Sats, Cents>,
pub low: LazyEagerIndexes<Sats, Cents>,
pub close: ComputedHeightDerivedLast<Sats>,
}
+9
View File
@@ -0,0 +1,9 @@
use brk_traversable::Traversable;
#[derive(Clone, Traversable)]
pub struct SplitOhlc<O, H, L, C> {
pub open: O,
pub high: H,
pub low: L,
pub close: C,
}
+31 -12
View File
@@ -3,9 +3,12 @@ use vecdb::{LazyVecFrom1, ReadableCloneableVec};
use super::super::cents;
use super::Vecs;
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
use crate::{
indexes,
internal::{CentsUnsignedToDollars, ComputedHeightDerivedLast, LazyEagerIndexes},
internal::{
CentsUnsignedToDollars, ComputedHeightDerivedLast, LazyEagerIndexes, OhlcCentsToDollars,
},
};
impl Vecs {
@@ -15,32 +18,48 @@ impl Vecs {
cents: &cents::Vecs,
) -> Self {
let price = LazyVecFrom1::transformed::<CentsUnsignedToDollars>(
"price_usd",
"price",
version,
cents.price.read_only_boxed_clone(),
);
// Dollars are monotonically increasing from cents, so open→open, high→high, low→low
let open =
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>("price_usd_open", version, &cents.open);
let high =
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>("price_usd_high", version, &cents.high);
let low =
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>("price_usd_low", version, &cents.low);
let open = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>(
"price_open",
version,
&cents.split.open,
);
let high = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>(
"price_high",
version,
&cents.split.high,
);
let low = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>(
"price_low",
version,
&cents.split.low,
);
let close = ComputedHeightDerivedLast::forced_import(
"price_usd_close",
"price_close",
price.read_only_boxed_clone(),
version,
indexes,
);
Self {
price,
let split = SplitOhlc {
open,
high,
low,
close,
}
};
let ohlc = LazyOhlcVecs::from_eager_ohlc_indexes::<OhlcCentsToDollars>(
"price_ohlc",
version,
&cents.ohlc,
);
Self { split, ohlc, price }
}
}
+10 -5
View File
@@ -1,14 +1,19 @@
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height};
use brk_types::{Cents, Dollars, Height, OHLCCents, OHLCDollars};
use vecdb::LazyVecFrom1;
use crate::internal::{ComputedHeightDerivedLast, LazyEagerIndexes};
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
#[derive(Clone, Traversable)]
pub struct Vecs {
#[allow(clippy::type_complexity)]
pub split: SplitOhlc<
LazyEagerIndexes<Dollars, Cents>,
LazyEagerIndexes<Dollars, Cents>,
LazyEagerIndexes<Dollars, Cents>,
ComputedHeightDerivedLast<Dollars>,
>,
pub ohlc: LazyOhlcVecs<OHLCDollars, OHLCCents>,
pub price: LazyVecFrom1<Height, Dollars, Height, Cents>,
pub open: LazyEagerIndexes<Dollars, Cents>,
pub high: LazyEagerIndexes<Dollars, Cents>,
pub low: LazyEagerIndexes<Dollars, Cents>,
pub close: ComputedHeightDerivedLast<Dollars>,
}