mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-12 19:48:15 -07:00
global: snapshot
This commit is contained in:
@@ -27,14 +27,14 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.tx_velocity_btc.height.compute_multiply(
|
||||
self.tx_velocity_native.height.compute_multiply(
|
||||
starting_indexes.height,
|
||||
&activity.ratio.height,
|
||||
&supply.velocity.native.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.tx_velocity_usd.height.compute_multiply(
|
||||
self.tx_velocity_fiat.height.compute_multiply(
|
||||
starting_indexes.height,
|
||||
&activity.ratio.height,
|
||||
&supply.velocity.fiat.height,
|
||||
|
||||
@@ -21,15 +21,15 @@ impl Vecs {
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
tx_velocity_btc: PerBlock::forced_import(
|
||||
tx_velocity_native: PerBlock::forced_import(
|
||||
db,
|
||||
"cointime_adj_tx_velocity_btc",
|
||||
"cointime_adj_tx_velocity",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
tx_velocity_usd: PerBlock::forced_import(
|
||||
tx_velocity_fiat: PerBlock::forced_import(
|
||||
db,
|
||||
"cointime_adj_tx_velocity_usd",
|
||||
"cointime_adj_tx_velocity_fiat",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
|
||||
@@ -7,6 +7,6 @@ use crate::internal::{PerBlock, PercentPerBlock};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub inflation_rate: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub tx_velocity_btc: PerBlock<StoredF64, M>,
|
||||
pub tx_velocity_usd: PerBlock<StoredF64, M>,
|
||||
pub tx_velocity_native: PerBlock<StoredF64, M>,
|
||||
pub tx_velocity_fiat: PerBlock<StoredF64, M>,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_cohort::{AmountBucket, ByAddressType};
|
||||
use brk_error::Result;
|
||||
use brk_types::{Age, Cents, CheckedSub, Height, Sats, Timestamp, TypeIndex};
|
||||
use rustc_hash::FxHashSet;
|
||||
use vecdb::{VecIndex, unlikely};
|
||||
use vecdb::VecIndex;
|
||||
|
||||
use crate::distribution::{
|
||||
address::{AddressTypeToActivityCounts, HeightToAddressTypeToVec},
|
||||
@@ -49,8 +49,7 @@ pub(crate) fn process_sent(
|
||||
let prev_timestamp = height_to_timestamp[receive_height.to_usize()];
|
||||
let age = Age::new(current_timestamp, prev_timestamp);
|
||||
|
||||
// Compute peak price during holding period for peak regret
|
||||
// This is the max HIGH price between receive and send heights
|
||||
// Compute peak spot price during holding period for peak regret
|
||||
let peak_price = price_range_max.max_between(receive_height, current_height);
|
||||
|
||||
for (output_type, vec) in by_type.unwrap().into_iter() {
|
||||
@@ -84,72 +83,33 @@ pub(crate) fn process_sent(
|
||||
let new_bucket = AmountBucket::from(new_balance);
|
||||
let crossing_boundary = prev_bucket != new_bucket;
|
||||
|
||||
let cohort_state = cohorts
|
||||
.amount_range
|
||||
.get_mut_by_bucket(prev_bucket)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
|
||||
cohort_state.send(addr_data, value, current_price, prev_price, peak_price, age)?;
|
||||
|
||||
// If crossing a bucket boundary, remove the (now-updated) address from old bucket
|
||||
if will_be_empty || crossing_boundary {
|
||||
// Subtract from old cohort
|
||||
let cohort_state = cohorts
|
||||
.amount_range
|
||||
.get_mut_by_bucket(prev_bucket)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
|
||||
// Debug info for tracking down underflow issues
|
||||
if unlikely(
|
||||
cohort_state.inner.supply.utxo_count < addr_data.utxo_count() as u64,
|
||||
) {
|
||||
panic!(
|
||||
"process_sent: cohort underflow detected!\n\
|
||||
Block context: receive_height={:?}, output_type={:?}, type_index={:?}\n\
|
||||
prev_balance={}, new_balance={}, value={}\n\
|
||||
will_be_empty={}, crossing_boundary={}\n\
|
||||
Address: {:?}",
|
||||
receive_height,
|
||||
output_type,
|
||||
type_index,
|
||||
prev_balance,
|
||||
new_balance,
|
||||
value,
|
||||
will_be_empty,
|
||||
crossing_boundary,
|
||||
addr_data
|
||||
);
|
||||
}
|
||||
|
||||
cohort_state.subtract(addr_data);
|
||||
}
|
||||
|
||||
// Update address data
|
||||
addr_data.send(value, prev_price)?;
|
||||
|
||||
if will_be_empty {
|
||||
// Address becoming empty - invariant check
|
||||
if new_balance.is_not_zero() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
*type_address_count -= 1;
|
||||
*type_empty_count += 1;
|
||||
|
||||
// Move from funded to empty
|
||||
lookup.move_to_empty(output_type, type_index);
|
||||
} else {
|
||||
// Add to new cohort
|
||||
cohorts
|
||||
.amount_range
|
||||
.get_mut_by_bucket(new_bucket)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.add(addr_data);
|
||||
}
|
||||
} else {
|
||||
// Address staying in same cohort - update in place
|
||||
// Migrate address to new bucket or mark as empty
|
||||
if will_be_empty {
|
||||
*type_address_count -= 1;
|
||||
*type_empty_count += 1;
|
||||
lookup.move_to_empty(output_type, type_index);
|
||||
} else if crossing_boundary {
|
||||
cohorts
|
||||
.amount_range
|
||||
.get_mut_by_bucket(new_bucket)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(addr_data, value, current_price, prev_price, peak_price, age)?;
|
||||
.add(addr_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,18 +33,12 @@ impl UTXOCohorts<Rw> {
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
self.epoch
|
||||
.mut_vec_from_height(height)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
self.class
|
||||
.mut_vec_from_timestamp(timestamp)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
if let Some(v) = self.epoch.mut_vec_from_height(height) {
|
||||
v.state.as_mut().unwrap().receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
}
|
||||
if let Some(v) = self.class.mut_vec_from_timestamp(timestamp) {
|
||||
v.state.as_mut().unwrap().receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
}
|
||||
|
||||
// Update output type cohorts (skip types with no outputs this block)
|
||||
self.type_.iter_typed_mut().for_each(|(output_type, vecs)| {
|
||||
|
||||
@@ -63,34 +63,22 @@ impl UTXOCohorts<Rw> {
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
self.epoch
|
||||
.mut_vec_from_height(receive_height)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
self.class
|
||||
.mut_vec_from_timestamp(block_state.timestamp)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
if let Some(v) = self.epoch.mut_vec_from_height(receive_height) {
|
||||
v.state.as_mut().unwrap().send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
}
|
||||
if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) {
|
||||
v.state.as_mut().unwrap().send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
}
|
||||
} else if sent.spendable_supply.utxo_count > 0 {
|
||||
// Zero-value UTXOs: just subtract supply
|
||||
self.age_range.get_mut(age).state.as_mut().unwrap().supply -=
|
||||
&sent.spendable_supply;
|
||||
self.epoch
|
||||
.mut_vec_from_height(receive_height)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.supply -= &sent.spendable_supply;
|
||||
self.class
|
||||
.mut_vec_from_timestamp(block_state.timestamp)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.supply -= &sent.spendable_supply;
|
||||
if let Some(v) = self.epoch.mut_vec_from_height(receive_height) {
|
||||
v.state.as_mut().unwrap().supply -= &sent.spendable_supply;
|
||||
}
|
||||
if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) {
|
||||
v.state.as_mut().unwrap().supply -= &sent.spendable_supply;
|
||||
}
|
||||
}
|
||||
|
||||
// Update output type cohorts (skip zero-supply entries)
|
||||
|
||||
@@ -460,7 +460,7 @@ impl RealizedFull {
|
||||
.change_1m_rel_to_rcap
|
||||
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps32>(
|
||||
starting_indexes.height,
|
||||
&self.core.net_pnl.delta.change._1m.cents.height,
|
||||
&self.core.net_pnl.delta.absolute._1m.cents.height,
|
||||
&self.core.minimal.cap.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
@@ -468,7 +468,7 @@ impl RealizedFull {
|
||||
.change_1m_rel_to_mcap
|
||||
.compute_binary::<CentsSigned, Dollars, RatioCentsSignedDollarsBps32>(
|
||||
starting_indexes.height,
|
||||
&self.core.net_pnl.delta.change._1m.cents.height,
|
||||
&self.core.net_pnl.delta.absolute._1m.cents.height,
|
||||
height_to_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -373,6 +373,7 @@ impl<S: Accumulate> CostBasisOps for CostBasisData<S> {
|
||||
let (base, rest) = CostBasisDistribution::deserialize_with_rest(&data)?;
|
||||
self.map = Some(base);
|
||||
self.raw.state = Some(RawState::deserialize(rest)?);
|
||||
debug_assert!(rest.len() >= 32, "CostBasisData state too short: {} bytes", rest.len());
|
||||
self.investor_cap_raw = CentsSquaredSats::from_bytes(&rest[16..32])?;
|
||||
self.pending.clear();
|
||||
self.raw.pending_cap = PendingCapDelta::default();
|
||||
@@ -431,6 +432,14 @@ impl<S: Accumulate> CostBasisOps for CostBasisData<S> {
|
||||
self.apply_map_pending();
|
||||
self.raw.apply_pending_cap();
|
||||
self.investor_cap_raw += self.pending_investor_cap.inc;
|
||||
debug_assert!(
|
||||
self.investor_cap_raw >= self.pending_investor_cap.dec,
|
||||
"CostBasis investor_cap_raw underflow!\n\
|
||||
Path: {:?}\n\
|
||||
Current (after increments): {:?}\n\
|
||||
Trying to decrement by: {:?}",
|
||||
self.raw.pathbuf, self.investor_cap_raw, self.pending_investor_cap.dec
|
||||
);
|
||||
self.investor_cap_raw -= self.pending_investor_cap.dec;
|
||||
self.pending_investor_cap = PendingInvestorCapDelta::default();
|
||||
}
|
||||
|
||||
@@ -224,20 +224,27 @@ impl SlidingWindowSorted {
|
||||
let rank = p * last;
|
||||
let lo = rank.floor() as usize;
|
||||
let hi = rank.ceil() as usize;
|
||||
let frac = rank - lo as f64;
|
||||
lo_hi[i] = (lo, hi, frac);
|
||||
lo_hi[i] = (lo, hi, rank - lo as f64);
|
||||
|
||||
// Insert unique ranks in sorted order (they're already ~sorted since ps is sorted)
|
||||
if rank_count == 0 || rank_set[rank_count - 1] != lo {
|
||||
rank_set[rank_count] = lo;
|
||||
rank_count += 1;
|
||||
}
|
||||
if hi != lo && (rank_count == 0 || rank_set[rank_count - 1] != hi) {
|
||||
rank_set[rank_count] = lo;
|
||||
rank_count += 1;
|
||||
if hi != lo {
|
||||
rank_set[rank_count] = hi;
|
||||
rank_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort and deduplicate (interleaved lo/hi values aren't necessarily sorted)
|
||||
rank_set[..rank_count].sort_unstable();
|
||||
let mut w = 1;
|
||||
for r in 1..rank_count {
|
||||
if rank_set[r] != rank_set[w - 1] {
|
||||
rank_set[w] = rank_set[r];
|
||||
w += 1;
|
||||
}
|
||||
}
|
||||
rank_count = w;
|
||||
|
||||
// Single pass through blocks to get all values
|
||||
let ranks = &rank_set[..rank_count];
|
||||
let mut values = [0.0f64; 10];
|
||||
|
||||
@@ -9,10 +9,10 @@ use crate::internal::AmountPerBlock;
|
||||
/// All fields are lazy transforms from existing sources - no storage.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyAmount<I: VecIndex> {
|
||||
pub sats: LazyVecFrom1<I, Sats, I, Sats>,
|
||||
pub btc: LazyVecFrom1<I, Bitcoin, I, Sats>,
|
||||
pub cents: LazyVecFrom1<I, Cents, I, Cents>,
|
||||
pub sats: LazyVecFrom1<I, Sats, I, Sats>,
|
||||
pub usd: LazyVecFrom1<I, Dollars, I, Dollars>,
|
||||
pub cents: LazyVecFrom1<I, Cents, I, Cents>,
|
||||
}
|
||||
|
||||
impl LazyAmount<Height> {
|
||||
@@ -57,10 +57,10 @@ impl LazyAmount<Height> {
|
||||
);
|
||||
|
||||
Self {
|
||||
sats,
|
||||
btc,
|
||||
cents,
|
||||
sats,
|
||||
usd,
|
||||
cents,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ use crate::{
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct AmountPerBlock<M: StorageMode = Rw> {
|
||||
pub sats: PerBlock<Sats, M>,
|
||||
pub btc: LazyPerBlock<Bitcoin, Sats>,
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
pub sats: PerBlock<Sats, M>,
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
}
|
||||
|
||||
impl AmountPerBlock {
|
||||
@@ -47,10 +47,10 @@ impl AmountPerBlock {
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
sats,
|
||||
btc,
|
||||
cents,
|
||||
sats,
|
||||
usd,
|
||||
cents,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ use crate::internal::{AmountPerBlock, DerivedResolutions};
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyAmountDerivedResolutions {
|
||||
pub sats: DerivedResolutions<Sats, Sats>,
|
||||
pub btc: DerivedResolutions<Bitcoin, Sats>,
|
||||
pub cents: DerivedResolutions<Cents, Cents>,
|
||||
pub sats: DerivedResolutions<Sats, Sats>,
|
||||
pub usd: DerivedResolutions<Dollars, Dollars>,
|
||||
pub cents: DerivedResolutions<Cents, Cents>,
|
||||
}
|
||||
|
||||
impl LazyAmountDerivedResolutions {
|
||||
@@ -54,10 +54,10 @@ impl LazyAmountDerivedResolutions {
|
||||
);
|
||||
|
||||
Self {
|
||||
sats,
|
||||
btc,
|
||||
cents,
|
||||
sats,
|
||||
usd,
|
||||
cents,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ use crate::{
|
||||
/// Single window slot: lazy rolling sum for Amount (sats + btc + cents + usd).
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyRollingSumAmountFromHeight {
|
||||
pub sats: LazyRollingSumFromHeight<Sats>,
|
||||
pub btc: LazyPerBlock<Bitcoin, Sats>,
|
||||
pub cents: LazyRollingSumFromHeight<Cents>,
|
||||
pub sats: LazyRollingSumFromHeight<Sats>,
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: LazyRollingSumFromHeight<Cents>,
|
||||
}
|
||||
|
||||
/// Lazy rolling sums for all 4 windows, for Amount (sats + btc + cents + usd).
|
||||
@@ -112,10 +112,10 @@ impl LazyRollingSumsAmountFromHeight {
|
||||
};
|
||||
|
||||
LazyRollingSumAmountFromHeight {
|
||||
sats,
|
||||
btc,
|
||||
cents,
|
||||
sats,
|
||||
usd,
|
||||
cents,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ impl CentsType for CentsSigned {
|
||||
/// Generic over `C` to support both `Cents` (unsigned) and `CentsSigned` (signed).
|
||||
#[derive(Traversable)]
|
||||
pub struct FiatPerBlock<C: CentsType, M: StorageMode = Rw> {
|
||||
pub cents: PerBlock<C, M>,
|
||||
pub usd: LazyPerBlock<Dollars, C>,
|
||||
pub cents: PerBlock<C, M>,
|
||||
}
|
||||
|
||||
impl<C: CentsType> FiatPerBlock<C> {
|
||||
@@ -48,6 +48,6 @@ impl<C: CentsType> FiatPerBlock<C> {
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
Ok(Self { cents, usd })
|
||||
Ok(Self { usd, cents })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ use crate::internal::{CentsType, PerBlock, Identity, LazyPerBlock, NumericValue}
|
||||
/// Zero extra stored vecs.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyFiatPerBlock<C: CentsType> {
|
||||
pub cents: LazyPerBlock<C, C>,
|
||||
pub usd: LazyPerBlock<Dollars, C>,
|
||||
pub cents: LazyPerBlock<C, C>,
|
||||
}
|
||||
|
||||
impl<C: CentsType> LazyFiatPerBlock<C> {
|
||||
@@ -33,6 +33,6 @@ impl<C: CentsType> LazyFiatPerBlock<C> {
|
||||
source.height.read_only_boxed_clone(),
|
||||
source,
|
||||
);
|
||||
Self { cents, usd }
|
||||
Self { usd, cents }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ use crate::{
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyRollingSumFiatFromHeight<C: CentsType> {
|
||||
pub cents: LazyRollingSumFromHeight<C>,
|
||||
pub usd: LazyPerBlock<Dollars, C>,
|
||||
pub cents: LazyRollingSumFromHeight<C>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
@@ -69,7 +69,7 @@ impl<C: CentsType> LazyRollingSumsFiatFromHeight<C> {
|
||||
)),
|
||||
};
|
||||
|
||||
LazyRollingSumFiatFromHeight { cents, usd }
|
||||
LazyRollingSumFiatFromHeight { usd, cents }
|
||||
};
|
||||
|
||||
Self(cached_starts.0.map_with_suffix(make_slot))
|
||||
|
||||
@@ -19,8 +19,8 @@ use crate::{
|
||||
/// Generic price metric with cents, USD, and sats representations.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Price<C> {
|
||||
pub cents: C,
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: C,
|
||||
pub sats: LazyPerBlock<SatsFract, Dollars>,
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ impl Price<PerBlock<Cents>> {
|
||||
version,
|
||||
&usd,
|
||||
);
|
||||
Ok(Self { cents, usd, sats })
|
||||
Ok(Self { usd, cents, sats })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,6 @@ where
|
||||
version,
|
||||
&usd,
|
||||
);
|
||||
Self { cents, usd, sats }
|
||||
Self { usd, cents, sats }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ use super::{RatioPerBlock, RatioPerBlockPercentiles};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct PriceWithRatioPerBlock<M: StorageMode = Rw> {
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
pub sats: LazyPerBlock<SatsFract, Dollars>,
|
||||
pub bps: PerBlock<BasisPoints32, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, BasisPoints32>,
|
||||
@@ -28,8 +28,8 @@ impl PriceWithRatioPerBlock {
|
||||
let price = Price::forced_import(db, name, version, indexes)?;
|
||||
let ratio = RatioPerBlock::forced_import(db, name, version, indexes)?;
|
||||
Ok(Self {
|
||||
cents: price.cents,
|
||||
usd: price.usd,
|
||||
cents: price.cents,
|
||||
sats: price.sats,
|
||||
bps: ratio.bps,
|
||||
ratio: ratio.ratio,
|
||||
|
||||
@@ -44,7 +44,7 @@ where
|
||||
|
||||
/// Lazy rolling deltas for all 4 window durations (24h, 1w, 1m, 1y).
|
||||
///
|
||||
/// Tree shape: `change._24h/...`, `rate._24h/...` — matches old `RollingDelta`.
|
||||
/// Tree shape: `absolute._24h/...`, `rate._24h/...` — matches old `RollingDelta`.
|
||||
///
|
||||
/// Replaces `RollingDelta`, `RollingDelta1m`, and `RollingDeltaExcept1m` — since
|
||||
/// there is no storage cost, all 4 windows are always available.
|
||||
@@ -55,7 +55,7 @@ where
|
||||
C: NumericValue + JsonSchema,
|
||||
B: BpsType,
|
||||
{
|
||||
pub change: Windows<LazyDeltaFromHeight<S, C, DeltaChange>>,
|
||||
pub absolute: Windows<LazyDeltaFromHeight<S, C, DeltaChange>>,
|
||||
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ where
|
||||
version,
|
||||
indexes,
|
||||
);
|
||||
let change = LazyDeltaFromHeight {
|
||||
let absolute = LazyDeltaFromHeight {
|
||||
height: change_vec,
|
||||
resolutions: Box::new(change_resolutions),
|
||||
};
|
||||
@@ -154,12 +154,12 @@ where
|
||||
percent,
|
||||
};
|
||||
|
||||
(change, rate)
|
||||
(absolute, rate)
|
||||
};
|
||||
|
||||
let (change, rate) = cached_starts.0.map_with_suffix(make_slot).unzip();
|
||||
let (absolute, rate) = cached_starts.0.map_with_suffix(make_slot).unzip();
|
||||
|
||||
Self { change, rate }
|
||||
Self { absolute, rate }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,13 +174,13 @@ where
|
||||
S: VecValue,
|
||||
C: CentsType,
|
||||
{
|
||||
pub cents: LazyDeltaFromHeight<S, C, DeltaChange>,
|
||||
pub usd: LazyPerBlock<Dollars, C>,
|
||||
pub cents: LazyDeltaFromHeight<S, C, DeltaChange>,
|
||||
}
|
||||
|
||||
/// Lazy fiat rolling deltas for all 4 windows.
|
||||
///
|
||||
/// Tree shape: `change._24h.{cents,usd}/...`, `rate._24h/...` — matches old `FiatRollingDelta`.
|
||||
/// Tree shape: `absolute._24h.{cents,usd}/...`, `rate._24h/...` — matches old `FiatRollingDelta`.
|
||||
///
|
||||
/// Replaces `FiatRollingDelta`, `FiatRollingDelta1m`, and `FiatRollingDeltaExcept1m`.
|
||||
#[derive(Clone, Traversable)]
|
||||
@@ -190,7 +190,7 @@ where
|
||||
C: CentsType,
|
||||
B: BpsType,
|
||||
{
|
||||
pub change: Windows<LazyDeltaFiatFromHeight<S, C>>,
|
||||
pub absolute: Windows<LazyDeltaFiatFromHeight<S, C>>,
|
||||
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ where
|
||||
)),
|
||||
};
|
||||
|
||||
let change = LazyDeltaFiatFromHeight { cents, usd };
|
||||
let absolute = LazyDeltaFiatFromHeight { usd, cents };
|
||||
|
||||
// Rate BPS: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
|
||||
@@ -303,11 +303,11 @@ where
|
||||
percent,
|
||||
};
|
||||
|
||||
(change, rate)
|
||||
(absolute, rate)
|
||||
};
|
||||
|
||||
let (change, rate) = cached_starts.0.map_with_suffix(make_slot).unzip();
|
||||
let (absolute, rate) = cached_starts.0.map_with_suffix(make_slot).unzip();
|
||||
|
||||
Self { change, rate }
|
||||
Self { absolute, rate }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,28 @@ pub struct SplitByUnit<M: StorageMode = Rw> {
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct SplitIndexesByUnit<M: StorageMode = Rw> {
|
||||
pub cents: EagerIndexes<Cents, M>,
|
||||
pub usd: LazyEagerIndexes<Dollars, Cents>,
|
||||
pub cents: EagerIndexes<Cents, M>,
|
||||
pub sats: LazyEagerIndexes<Sats, Cents>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct SplitCloseByUnit {
|
||||
pub cents: Resolutions<Cents>,
|
||||
pub usd: Resolutions<Dollars>,
|
||||
pub cents: Resolutions<Cents>,
|
||||
pub sats: Resolutions<Sats>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct OhlcByUnit<M: StorageMode = Rw> {
|
||||
pub cents: OhlcVecs<OHLCCents, M>,
|
||||
pub usd: LazyOhlcVecs<OHLCDollars, OHLCCents>,
|
||||
pub cents: OhlcVecs<OHLCCents, M>,
|
||||
pub sats: LazyOhlcVecs<OHLCSats, OHLCCents>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct PriceByUnit<M: StorageMode = Rw> {
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
pub sats: LazyPerBlock<Sats, Cents>,
|
||||
}
|
||||
|
||||
@@ -142,36 +142,36 @@ impl Vecs {
|
||||
|
||||
let split = SplitByUnit {
|
||||
open: SplitIndexesByUnit {
|
||||
cents: open_cents,
|
||||
usd: open_usd,
|
||||
cents: open_cents,
|
||||
sats: open_sats,
|
||||
},
|
||||
high: SplitIndexesByUnit {
|
||||
cents: high_cents,
|
||||
usd: high_usd,
|
||||
cents: high_cents,
|
||||
sats: high_sats,
|
||||
},
|
||||
low: SplitIndexesByUnit {
|
||||
cents: low_cents,
|
||||
usd: low_usd,
|
||||
cents: low_cents,
|
||||
sats: low_sats,
|
||||
},
|
||||
close: SplitCloseByUnit {
|
||||
cents: close_cents,
|
||||
usd: close_usd,
|
||||
cents: close_cents,
|
||||
sats: close_sats,
|
||||
},
|
||||
};
|
||||
|
||||
let ohlc = OhlcByUnit {
|
||||
cents: ohlc_cents,
|
||||
usd: ohlc_usd,
|
||||
cents: ohlc_cents,
|
||||
sats: ohlc_sats,
|
||||
};
|
||||
|
||||
let spot = PriceByUnit {
|
||||
cents: price_cents,
|
||||
usd: price_usd,
|
||||
cents: price_cents,
|
||||
sats: price_sats,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user