pub(crate) mod by_unit; mod compute; pub(crate) mod ohlcs; use std::path::Path; use brk_traversable::Traversable; use brk_types::Version; use vecdb::{Database, ReadOnlyClone, Rw, StorageMode}; use crate::{ indexes, internal::{ CachedPerBlock, CentsUnsignedToDollars, CentsUnsignedToSats, EagerIndexes, LazyEagerIndexes, LazyPerBlock, OhlcCentsToDollars, OhlcCentsToSats, Resolutions, db_utils::{finalize_db, open_db}, }, }; use by_unit::{OhlcByUnit, PriceByUnit, SplitByUnit, SplitCloseByUnit, SplitIndexesByUnit}; use ohlcs::{LazyOhlcVecs, OhlcVecs}; pub const DB_NAME: &str = "prices"; #[derive(Traversable)] pub struct Vecs { #[traversable(skip)] pub db: Database, pub split: SplitByUnit, pub ohlc: OhlcByUnit, pub spot: PriceByUnit, } impl Vecs { pub(crate) fn forced_import( parent: &Path, version: Version, indexes: &indexes::Vecs, ) -> brk_error::Result { let db = open_db(parent, DB_NAME, 100_000)?; let this = Self::forced_import_inner(&db, version, indexes)?; finalize_db(&this.db, &this)?; Ok(this) } fn forced_import_inner( db: &Database, version: Version, indexes: &indexes::Vecs, ) -> brk_error::Result { let version = version + Version::new(11); let price_cents = CachedPerBlock::forced_import(db, "price_cents", version, indexes)?; let open_cents = EagerIndexes::forced_import(db, "price_open_cents", version)?; let high_cents = EagerIndexes::forced_import(db, "price_high_cents", version)?; let low_cents = EagerIndexes::forced_import(db, "price_low_cents", version)?; let close_cents = Resolutions::forced_import( "price_close_cents", price_cents.height.read_only_clone(), version, indexes, ); let ohlc_cents = OhlcVecs::forced_import(db, "price_ohlc_cents", version)?; let price_usd = LazyPerBlock::from_cached_computed::( "price", version, price_cents.height.read_only_boxed_clone(), &price_cents, ); let open_usd = LazyEagerIndexes::from_eager_indexes::( "price_open", version, &open_cents, ); let high_usd = LazyEagerIndexes::from_eager_indexes::( "price_high", version, &high_cents, ); let low_usd = LazyEagerIndexes::from_eager_indexes::( "price_low", version, &low_cents, ); let close_usd = Resolutions::forced_import("price_close", price_usd.height.clone(), version, indexes); let ohlc_usd = LazyOhlcVecs::from_eager_ohlc_indexes::( "price_ohlc", version, &ohlc_cents, ); let price_sats = LazyPerBlock::from_cached_computed::( "price_sats", version, price_cents.height.read_only_boxed_clone(), &price_cents, ); let open_sats = LazyEagerIndexes::from_eager_indexes::( "price_open_sats", version, &open_cents, ); // Sats are inversely related to cents (sats = 10B/cents), so high↔low are swapped let high_sats = LazyEagerIndexes::from_eager_indexes::( "price_high_sats", version, &low_cents, ); let low_sats = LazyEagerIndexes::from_eager_indexes::( "price_low_sats", version, &high_cents, ); let close_sats = Resolutions::forced_import( "price_close_sats", price_sats.height.clone(), version, indexes, ); // OhlcCentsToSats handles the high↔low swap internally let ohlc_sats = LazyOhlcVecs::from_eager_ohlc_indexes::( "price_ohlc_sats", version, &ohlc_cents, ); let split = SplitByUnit { open: SplitIndexesByUnit { usd: open_usd, cents: open_cents, sats: open_sats, }, high: SplitIndexesByUnit { usd: high_usd, cents: high_cents, sats: high_sats, }, low: SplitIndexesByUnit { usd: low_usd, cents: low_cents, sats: low_sats, }, close: SplitCloseByUnit { usd: close_usd, cents: close_cents, sats: close_sats, }, }; let ohlc = OhlcByUnit { usd: ohlc_usd, cents: ohlc_cents, sats: ohlc_sats, }; let spot = PriceByUnit { usd: price_usd, cents: price_cents, sats: price_sats, }; Ok(Self { db: db.clone(), split, ohlc, spot, }) } }