mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-08 14:11:56 -07:00
computer: fixes
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
use brk_cohort::{
|
||||
compute_profitability_boundaries, Filter, PROFITABILITY_RANGE_COUNT,
|
||||
};
|
||||
use brk_cohort::{Filter, PROFITABILITY_RANGE_COUNT, compute_profitability_boundaries};
|
||||
use brk_types::{Cents, CentsCompact, Sats};
|
||||
|
||||
use crate::{
|
||||
@@ -60,7 +58,6 @@ pub(super) struct CostBasisFenwick {
|
||||
// to a flat bucket index across two tiers.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
/// Map rounded dollars to a flat bucket index.
|
||||
/// Prices >= $1M are clamped to the last bucket.
|
||||
#[inline]
|
||||
@@ -185,13 +182,6 @@ impl CostBasisFenwick {
|
||||
self.initialized = true;
|
||||
}
|
||||
|
||||
/// Reset to uninitialized empty state.
|
||||
pub(super) fn reset(&mut self) {
|
||||
self.tree.reset();
|
||||
self.totals = CostBasisNode::default();
|
||||
self.initialized = false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Percentile queries
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -268,9 +258,9 @@ impl CostBasisFenwick {
|
||||
self.tree
|
||||
.batch_kth(&usd_targets, &usd_field, &mut usd_buckets);
|
||||
|
||||
for i in 0..PERCENTILES_LEN {
|
||||
(0..PERCENTILES_LEN).for_each(|i| {
|
||||
result.usd_prices[i] = bucket_to_cents(usd_buckets[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
@@ -330,114 +320,3 @@ pub(super) struct PercentileResult {
|
||||
pub min_price: Cents,
|
||||
pub max_price: Cents,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn bucket_round_trip() {
|
||||
// Low prices: exact dollar precision
|
||||
let price = CentsCompact::new(5000_00); // $5000
|
||||
let bucket = price_to_bucket(price);
|
||||
let back = bucket_to_cents(bucket);
|
||||
assert_eq!(u64::from(back), 5000 * 100);
|
||||
|
||||
// High price: $90,000 → rounded to $90,000 (already 5 digits)
|
||||
let price = CentsCompact::new(90_000_00);
|
||||
let bucket = price_to_bucket(price);
|
||||
let back = bucket_to_cents(bucket);
|
||||
assert_eq!(u64::from(back), 90_000 * 100);
|
||||
|
||||
// Tier 1: $123,456 → rounded to $123,460
|
||||
let price = CentsCompact::new(123_456_00);
|
||||
let bucket = price_to_bucket(price);
|
||||
let back = bucket_to_cents(bucket);
|
||||
assert_eq!(u64::from(back), 123_460 * 100);
|
||||
|
||||
// Overflow: $2,000,000 → clamped to $1,000,000
|
||||
let price = CentsCompact::new(2_000_000_00);
|
||||
let bucket = price_to_bucket(price);
|
||||
assert_eq!(bucket, TREE_SIZE - 1);
|
||||
assert_eq!(u64::from(bucket_to_cents(bucket)), 1_000_000 * 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bucket_edge_cases() {
|
||||
// $0
|
||||
assert_eq!(price_to_bucket(CentsCompact::new(0)), 0);
|
||||
assert_eq!(u64::from(bucket_to_cents(0)), 0);
|
||||
|
||||
// $1
|
||||
let bucket = price_to_bucket(CentsCompact::new(100));
|
||||
assert_eq!(bucket, 1);
|
||||
|
||||
// Max CentsCompact
|
||||
let bucket = price_to_bucket(CentsCompact::MAX);
|
||||
assert!(bucket < TREE_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bulk_init_and_percentiles() {
|
||||
let mut fenwick = CostBasisFenwick::new();
|
||||
|
||||
// Create a simple BTreeMap: 100 sats at $10,000, 100 sats at $50,000
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(CentsCompact::new(10_000_00), Sats::from(100u64));
|
||||
map.insert(CentsCompact::new(50_000_00), Sats::from(100u64));
|
||||
|
||||
fenwick.bulk_init(std::iter::once((&map, true)));
|
||||
|
||||
assert!(fenwick.is_initialized());
|
||||
|
||||
let result = fenwick.percentiles_all();
|
||||
// Median (50th percentile) should be at $10,000 (first 100 sats)
|
||||
// since target = 200 * 50/100 = 100, and first 100 sats are at $10,000
|
||||
assert_eq!(u64::from(result.sat_prices[9]), 10_000 * 100); // index 9 = 50th percentile
|
||||
|
||||
// Min should be $10,000, max should be $50,000
|
||||
assert_eq!(u64::from(result.min_price), 10_000 * 100);
|
||||
assert_eq!(u64::from(result.max_price), 50_000 * 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_delta_updates_totals() {
|
||||
let mut fenwick = CostBasisFenwick::new();
|
||||
fenwick.initialized = true;
|
||||
|
||||
let price = CentsCompact::new(10_000_00);
|
||||
fenwick.apply_delta(price, &PendingDelta { inc: Sats::from(500u64), dec: Sats::ZERO }, true);
|
||||
assert_eq!(fenwick.totals.all_sats, 500);
|
||||
assert_eq!(fenwick.totals.sth_sats, 500);
|
||||
|
||||
fenwick.apply_delta(price, &PendingDelta { inc: Sats::ZERO, dec: Sats::from(200u64) }, true);
|
||||
assert_eq!(fenwick.totals.all_sats, 300);
|
||||
assert_eq!(fenwick.totals.sth_sats, 300);
|
||||
|
||||
// Non-STH delta
|
||||
fenwick.apply_delta(price, &PendingDelta { inc: Sats::from(100u64), dec: Sats::ZERO }, false);
|
||||
assert_eq!(fenwick.totals.all_sats, 400);
|
||||
assert_eq!(fenwick.totals.sth_sats, 300);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn profitability_ranges_sum_to_total() {
|
||||
let mut fenwick = CostBasisFenwick::new();
|
||||
|
||||
let mut map = BTreeMap::new();
|
||||
// Spread sats across different prices
|
||||
map.insert(CentsCompact::new(1_000_00), Sats::from(1000u64));
|
||||
map.insert(CentsCompact::new(10_000_00), Sats::from(2000u64));
|
||||
map.insert(CentsCompact::new(50_000_00), Sats::from(3000u64));
|
||||
map.insert(CentsCompact::new(100_000_00), Sats::from(4000u64));
|
||||
|
||||
fenwick.bulk_init(std::iter::once((&map, false)));
|
||||
|
||||
let spot = Cents::from(50_000u64 * 100);
|
||||
let prof = fenwick.profitability(spot);
|
||||
|
||||
let total_sats: u64 = prof.iter().map(|(s, _)| s).sum();
|
||||
assert_eq!(total_sats, 10_000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ impl CoreCohortMetrics {
|
||||
self.realized
|
||||
.compute_rest_part1(blocks, starting_indexes, exit)?;
|
||||
|
||||
self.unrealized.compute_rest(starting_indexes, exit)?;
|
||||
self.unrealized.compute_rest(prices, starting_indexes, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,25 +1,16 @@
|
||||
use brk_cohort::Filter;
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Indexes, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
|
||||
use brk_types::{Indexes, Version};
|
||||
use vecdb::{AnyStoredVec, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::distribution::metrics::unrealized::UnrealizedMinimal;
|
||||
use crate::{blocks, prices};
|
||||
|
||||
use crate::internal::ValueFromHeight;
|
||||
|
||||
use crate::distribution::{
|
||||
metrics::{ActivityCore, ImportConfig, OutputsMetrics, RealizedMinimal, SupplyMetrics},
|
||||
state::UnrealizedState,
|
||||
use crate::distribution::metrics::{
|
||||
ActivityCore, ImportConfig, OutputsMetrics, RealizedMinimal, SupplyMetrics,
|
||||
};
|
||||
|
||||
/// Minimal unrealized metrics: supply in profit/loss only.
|
||||
#[derive(Traversable)]
|
||||
pub struct MinimalUnrealized<M: StorageMode = Rw> {
|
||||
pub supply_in_profit: ValueFromHeight<M>,
|
||||
pub supply_in_loss: ValueFromHeight<M>,
|
||||
}
|
||||
|
||||
/// MinimalCohortMetrics: supply, outputs, sent+ema, realized cap/price/mvrv/profit/loss,
|
||||
/// supply in profit/loss.
|
||||
///
|
||||
@@ -33,71 +24,7 @@ pub struct MinimalCohortMetrics<M: StorageMode = Rw> {
|
||||
pub outputs: Box<OutputsMetrics<M>>,
|
||||
pub activity: Box<ActivityCore<M>>,
|
||||
pub realized: Box<RealizedMinimal<M>>,
|
||||
pub unrealized: Box<MinimalUnrealized<M>>,
|
||||
}
|
||||
|
||||
impl MinimalUnrealized {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
supply_in_profit: cfg.import("supply_in_profit", Version::ZERO)?,
|
||||
supply_in_loss: cfg.import("supply_in_loss", Version::ZERO)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn min_stateful_height_len(&self) -> usize {
|
||||
self.supply_in_profit
|
||||
.sats
|
||||
.height
|
||||
.len()
|
||||
.min(self.supply_in_loss.sats.height.len())
|
||||
}
|
||||
|
||||
pub(crate) fn truncate_push(
|
||||
&mut self,
|
||||
height: Height,
|
||||
state: &UnrealizedState,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.supply_in_profit)?;
|
||||
self.supply_in_loss
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.supply_in_loss)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.supply_in_profit.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_profit.base.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec,
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_sources(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
sum_others!(self, starting_indexes, others, exit; supply_in_profit.base.sats.height);
|
||||
sum_others!(self, starting_indexes, others, exit; supply_in_loss.base.sats.height);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit.compute(prices, max_from, exit)?;
|
||||
self.supply_in_loss.compute(prices, max_from, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
pub unrealized: Box<UnrealizedMinimal<M>>,
|
||||
}
|
||||
|
||||
impl MinimalCohortMetrics {
|
||||
@@ -108,7 +35,7 @@ impl MinimalCohortMetrics {
|
||||
outputs: Box::new(OutputsMetrics::forced_import(cfg)?),
|
||||
activity: Box::new(ActivityCore::forced_import(cfg)?),
|
||||
realized: Box::new(RealizedMinimal::forced_import(cfg)?),
|
||||
unrealized: Box::new(MinimalUnrealized::forced_import(cfg)?),
|
||||
unrealized: Box::new(UnrealizedMinimal::forced_import(cfg)?),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -150,12 +77,18 @@ impl MinimalCohortMetrics {
|
||||
)?;
|
||||
self.outputs.compute_from_stateful(
|
||||
starting_indexes,
|
||||
&others.iter().map(|v| v.outputs.as_ref()).collect::<Vec<_>>(),
|
||||
&others
|
||||
.iter()
|
||||
.map(|v| v.outputs.as_ref())
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
self.activity.compute_from_stateful(
|
||||
starting_indexes,
|
||||
&others.iter().map(|v| v.activity.as_ref()).collect::<Vec<_>>(),
|
||||
&others
|
||||
.iter()
|
||||
.map(|v| v.activity.as_ref())
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
self.realized.compute_from_stateful(
|
||||
@@ -184,12 +117,10 @@ impl MinimalCohortMetrics {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply
|
||||
.compute(prices, starting_indexes.height, exit)?;
|
||||
self.supply.compute(prices, starting_indexes.height, exit)?;
|
||||
self.supply
|
||||
.compute_rest_part1(blocks, starting_indexes, exit)?;
|
||||
self.outputs
|
||||
.compute_rest(blocks, starting_indexes, exit)?;
|
||||
self.outputs.compute_rest(blocks, starting_indexes, exit)?;
|
||||
self.activity
|
||||
.compute_rest_part1(blocks, starting_indexes, exit)?;
|
||||
self.realized
|
||||
|
||||
@@ -4,9 +4,7 @@ use brk_types::{CentsSats, CentsSquaredSats, Height, Indexes, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::distribution::state::UnrealizedState;
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
use crate::{distribution::{metrics::ImportConfig, state::UnrealizedState}, prices};
|
||||
|
||||
use super::UnrealizedCore;
|
||||
|
||||
@@ -163,10 +161,11 @@ impl UnrealizedBase {
|
||||
|
||||
pub(crate) fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.core.compute_rest(starting_indexes, exit)?;
|
||||
self.core.compute_rest(prices, starting_indexes, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, CentsSigned, Height, Indexes, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
distribution::state::UnrealizedState,
|
||||
distribution::{
|
||||
metrics::{ImportConfig, unrealized::UnrealizedMinimal},
|
||||
state::UnrealizedState,
|
||||
},
|
||||
internal::{
|
||||
CentsSubtractToCentsSigned, FiatFromHeight, LazyFromHeight, NegCentsUnsignedToDollars,
|
||||
ValueFromHeight,
|
||||
},
|
||||
prices,
|
||||
};
|
||||
|
||||
use brk_types::Dollars;
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
|
||||
#[derive(Traversable)]
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct UnrealizedCore<M: StorageMode = Rw> {
|
||||
pub supply_in_profit: ValueFromHeight<M>,
|
||||
pub supply_in_loss: ValueFromHeight<M>,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub minimal: UnrealizedMinimal<M>,
|
||||
|
||||
pub unrealized_profit: FiatFromHeight<Cents, M>,
|
||||
pub unrealized_loss: FiatFromHeight<Cents, M>,
|
||||
@@ -31,8 +35,8 @@ pub struct UnrealizedCore<M: StorageMode = Rw> {
|
||||
impl UnrealizedCore {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let v0 = Version::ZERO;
|
||||
let supply_in_profit = cfg.import("supply_in_profit", v0)?;
|
||||
let supply_in_loss = cfg.import("supply_in_loss", v0)?;
|
||||
|
||||
let minimal = UnrealizedMinimal::forced_import(cfg)?;
|
||||
|
||||
let unrealized_profit = cfg.import("unrealized_profit", v0)?;
|
||||
let unrealized_loss: FiatFromHeight<Cents> = cfg.import("unrealized_loss", v0)?;
|
||||
@@ -47,8 +51,7 @@ impl UnrealizedCore {
|
||||
let net_unrealized_pnl = cfg.import("net_unrealized_pnl", v0)?;
|
||||
|
||||
Ok(Self {
|
||||
supply_in_profit,
|
||||
supply_in_loss,
|
||||
minimal,
|
||||
unrealized_profit,
|
||||
unrealized_loss,
|
||||
neg_unrealized_loss,
|
||||
@@ -57,11 +60,8 @@ impl UnrealizedCore {
|
||||
}
|
||||
|
||||
pub(crate) fn min_stateful_height_len(&self) -> usize {
|
||||
self.supply_in_profit
|
||||
.sats
|
||||
.height
|
||||
.len()
|
||||
.min(self.supply_in_loss.sats.height.len())
|
||||
self.minimal
|
||||
.min_stateful_height_len()
|
||||
.min(self.unrealized_profit.cents.height.len())
|
||||
.min(self.unrealized_loss.cents.height.len())
|
||||
}
|
||||
@@ -71,14 +71,7 @@ impl UnrealizedCore {
|
||||
height: Height,
|
||||
height_state: &UnrealizedState,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, height_state.supply_in_profit)?;
|
||||
self.supply_in_loss
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, height_state.supply_in_loss)?;
|
||||
self.minimal.truncate_push(height, height_state)?;
|
||||
self.unrealized_profit
|
||||
.cents
|
||||
.height
|
||||
@@ -92,14 +85,10 @@ impl UnrealizedCore {
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.supply_in_profit.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_profit.base.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.unrealized_profit.cents.height,
|
||||
&mut self.unrealized_loss.cents.height,
|
||||
]
|
||||
let mut vecs = self.minimal.collect_vecs_mut();
|
||||
vecs.push(&mut self.unrealized_profit.cents.height);
|
||||
vecs.push(&mut self.unrealized_loss.cents.height);
|
||||
vecs
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_stateful(
|
||||
@@ -108,8 +97,10 @@ impl UnrealizedCore {
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
sum_others!(self, starting_indexes, others, exit; supply_in_profit.sats.height);
|
||||
sum_others!(self, starting_indexes, others, exit; supply_in_loss.sats.height);
|
||||
let minimal_refs: Vec<&UnrealizedMinimal> = others.iter().map(|o| &o.minimal).collect();
|
||||
self.minimal
|
||||
.compute_from_sources(starting_indexes, &minimal_refs, exit)?;
|
||||
|
||||
sum_others!(self, starting_indexes, others, exit; unrealized_profit.cents.height);
|
||||
sum_others!(self, starting_indexes, others, exit; unrealized_loss.cents.height);
|
||||
|
||||
@@ -119,9 +110,13 @@ impl UnrealizedCore {
|
||||
/// Compute derived metrics from stored values.
|
||||
pub(crate) fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.minimal
|
||||
.compute_rest(prices, starting_indexes.height, exit)?;
|
||||
|
||||
self.net_unrealized_pnl
|
||||
.cents
|
||||
.height
|
||||
|
||||
@@ -84,7 +84,7 @@ impl UnrealizedFull {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.inner.compute_rest(starting_indexes, exit)?;
|
||||
self.inner.compute_rest(prices, starting_indexes, exit)?;
|
||||
|
||||
self.gross_pnl.cents.height.compute_add(
|
||||
starting_indexes.height,
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Indexes, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::prices;
|
||||
|
||||
use crate::internal::ValueFromHeight;
|
||||
|
||||
use crate::distribution::{metrics::ImportConfig, state::UnrealizedState};
|
||||
|
||||
/// Minimal unrealized metrics: supply in profit/loss only.
|
||||
#[derive(Traversable)]
|
||||
pub struct UnrealizedMinimal<M: StorageMode = Rw> {
|
||||
pub supply_in_profit: ValueFromHeight<M>,
|
||||
pub supply_in_loss: ValueFromHeight<M>,
|
||||
}
|
||||
|
||||
impl UnrealizedMinimal {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
supply_in_profit: cfg.import("supply_in_profit", Version::ZERO)?,
|
||||
supply_in_loss: cfg.import("supply_in_loss", Version::ZERO)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn min_stateful_height_len(&self) -> usize {
|
||||
self.supply_in_profit
|
||||
.sats
|
||||
.height
|
||||
.len()
|
||||
.min(self.supply_in_loss.sats.height.len())
|
||||
}
|
||||
|
||||
pub(crate) fn truncate_push(&mut self, height: Height, state: &UnrealizedState) -> Result<()> {
|
||||
self.supply_in_profit
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.supply_in_profit)?;
|
||||
self.supply_in_loss
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.supply_in_loss)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.supply_in_profit.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_profit.base.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec,
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_sources(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
sum_others!(self, starting_indexes, others, exit; supply_in_profit.base.sats.height);
|
||||
sum_others!(self, starting_indexes, others, exit; supply_in_loss.base.sats.height);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit.compute(prices, max_from, exit)?;
|
||||
self.supply_in_loss.compute(prices, max_from, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
mod base;
|
||||
mod core;
|
||||
mod full;
|
||||
mod minimal;
|
||||
|
||||
pub use base::UnrealizedBase;
|
||||
pub use self::core::UnrealizedCore;
|
||||
pub use base::UnrealizedBase;
|
||||
pub use full::UnrealizedFull;
|
||||
pub use minimal::UnrealizedMinimal;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_types::{Height, Indexes};
|
||||
@@ -17,36 +19,75 @@ pub trait UnrealizedLike: Send + Sync {
|
||||
fn as_base_mut(&mut self) -> &mut UnrealizedBase;
|
||||
fn min_stateful_height_len(&self) -> usize;
|
||||
fn truncate_push(&mut self, height: Height, state: &UnrealizedState) -> Result<()>;
|
||||
fn compute_rest(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
fn compute_net_sentiment_height(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()>;
|
||||
fn compute_net_sentiment_height(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
impl UnrealizedLike for UnrealizedBase {
|
||||
fn as_base(&self) -> &UnrealizedBase { self }
|
||||
fn as_base_mut(&mut self) -> &mut UnrealizedBase { self }
|
||||
fn min_stateful_height_len(&self) -> usize { self.min_stateful_height_len() }
|
||||
fn as_base(&self) -> &UnrealizedBase {
|
||||
self
|
||||
}
|
||||
fn as_base_mut(&mut self) -> &mut UnrealizedBase {
|
||||
self
|
||||
}
|
||||
fn min_stateful_height_len(&self) -> usize {
|
||||
self.min_stateful_height_len()
|
||||
}
|
||||
fn truncate_push(&mut self, height: Height, state: &UnrealizedState) -> Result<()> {
|
||||
self.truncate_push(height, state)
|
||||
}
|
||||
fn compute_rest(&mut self, _prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
self.compute_rest(starting_indexes, exit)
|
||||
fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_rest(prices, starting_indexes, exit)
|
||||
}
|
||||
fn compute_net_sentiment_height(&mut self, _starting_indexes: &Indexes, _exit: &Exit) -> Result<()> {
|
||||
fn compute_net_sentiment_height(
|
||||
&mut self,
|
||||
_starting_indexes: &Indexes,
|
||||
_exit: &Exit,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl UnrealizedLike for UnrealizedFull {
|
||||
fn as_base(&self) -> &UnrealizedBase { &self.inner }
|
||||
fn as_base_mut(&mut self) -> &mut UnrealizedBase { &mut self.inner }
|
||||
fn min_stateful_height_len(&self) -> usize { self.inner.min_stateful_height_len() }
|
||||
fn as_base(&self) -> &UnrealizedBase {
|
||||
&self.inner
|
||||
}
|
||||
fn as_base_mut(&mut self) -> &mut UnrealizedBase {
|
||||
&mut self.inner
|
||||
}
|
||||
fn min_stateful_height_len(&self) -> usize {
|
||||
self.inner.min_stateful_height_len()
|
||||
}
|
||||
fn truncate_push(&mut self, height: Height, state: &UnrealizedState) -> Result<()> {
|
||||
self.truncate_push_all(height, state)
|
||||
}
|
||||
fn compute_rest(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
fn compute_rest(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_rest_all(prices, starting_indexes, exit)
|
||||
}
|
||||
fn compute_net_sentiment_height(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
fn compute_net_sentiment_height(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_net_sentiment_height(starting_indexes, exit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,6 @@ impl<N: FenwickNode> FenwickTree<N> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.tree.fill(N::default());
|
||||
}
|
||||
@@ -73,7 +68,7 @@ impl<N: FenwickNode> FenwickTree<N> {
|
||||
debug_assert!(self.size > 0);
|
||||
let mut pos = 0usize;
|
||||
let mut remaining = k;
|
||||
let mut bit = 1usize << (usize::BITS - 1 - self.size.leading_zeros() as u32);
|
||||
let mut bit = 1usize << (usize::BITS - 1 - self.size.leading_zeros());
|
||||
while bit > 0 {
|
||||
let next = pos + bit;
|
||||
if next <= self.size {
|
||||
@@ -105,7 +100,7 @@ impl<N: FenwickNode> FenwickTree<N> {
|
||||
out.fill(0);
|
||||
// Copy targets so we can subtract in-place
|
||||
let mut remaining: smallvec::SmallVec<[V; 24]> = sorted_targets.into();
|
||||
let mut bit = 1usize << (usize::BITS - 1 - self.size.leading_zeros() as u32);
|
||||
let mut bit = 1usize << (usize::BITS - 1 - self.size.leading_zeros());
|
||||
while bit > 0 {
|
||||
for i in 0..k {
|
||||
let next = out[i] + bit;
|
||||
|
||||
@@ -12,4 +12,3 @@ pub(crate) use expanding_percentiles::*;
|
||||
pub(crate) use fenwick::*;
|
||||
pub(crate) use sliding_distribution::*;
|
||||
pub(crate) use sliding_median::*;
|
||||
pub(crate) use sliding_window::*;
|
||||
|
||||
@@ -5,7 +5,7 @@ use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Height, Version};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{AnyVec, Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
@@ -152,8 +152,11 @@ where
|
||||
source: &impl ReadableVec<Height, S>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let changes: [&mut FiatFromHeight<C>; 3] =
|
||||
[&mut self.change_24h, &mut self.change_1w, &mut self.change_1y];
|
||||
let changes: [&mut FiatFromHeight<C>; 3] = [
|
||||
&mut self.change_24h,
|
||||
&mut self.change_1w,
|
||||
&mut self.change_1y,
|
||||
];
|
||||
let rates = [&mut self.rate_24h, &mut self.rate_1w, &mut self.rate_1y];
|
||||
let starts = [windows._24h, windows._1w, windows._1y];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user