mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Cents;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::super::{activity, cap, supply};
|
||||
@@ -32,13 +33,16 @@ impl Vecs {
|
||||
.metrics
|
||||
.realized
|
||||
.realized_price
|
||||
.usd
|
||||
.cents
|
||||
.height;
|
||||
|
||||
self.vaulted_price.usd.height.compute_divide(
|
||||
self.vaulted_price.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
realized_price,
|
||||
&activity.vaultedness.height,
|
||||
|(i, price, vaultedness, ..)| {
|
||||
(i, Cents::from(f64::from(price) / f64::from(vaultedness)))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -47,13 +51,16 @@ impl Vecs {
|
||||
prices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.vaulted_price.usd.height,
|
||||
&self.vaulted_price.cents.height,
|
||||
)?;
|
||||
|
||||
self.active_price.usd.height.compute_multiply(
|
||||
self.active_price.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
realized_price,
|
||||
&activity.liveliness.height,
|
||||
|(i, price, liveliness, ..)| {
|
||||
(i, Cents::from(f64::from(price) * f64::from(liveliness)))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -62,13 +69,16 @@ impl Vecs {
|
||||
prices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.active_price.usd.height,
|
||||
&self.active_price.cents.height,
|
||||
)?;
|
||||
|
||||
self.true_market_mean.usd.height.compute_divide(
|
||||
self.true_market_mean.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&cap.investor_cap.height,
|
||||
&supply.active_supply.btc.height,
|
||||
|(i, cap_dollars, supply_btc, ..)| {
|
||||
(i, Cents::from(f64::from(Cents::from(cap_dollars)) / f64::from(supply_btc)))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -77,14 +87,17 @@ impl Vecs {
|
||||
prices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.true_market_mean.usd.height,
|
||||
&self.true_market_mean.cents.height,
|
||||
)?;
|
||||
|
||||
// cointime_price = cointime_cap / circulating_supply
|
||||
self.cointime_price.usd.height.compute_divide(
|
||||
self.cointime_price.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&cap.cointime_cap.height,
|
||||
circulating_supply,
|
||||
|(i, cap_dollars, supply_btc, ..)| {
|
||||
(i, Cents::from(f64::from(Cents::from(cap_dollars)) / f64::from(supply_btc)))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -93,7 +106,7 @@ impl Vecs {
|
||||
prices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.cointime_price.usd.height,
|
||||
&self.cointime_price.cents.height,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::Dollars;
|
||||
use brk_types::Cents;
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeightLast, ComputedFromHeightRatioExtended, Price};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub vaulted_price: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub vaulted_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub vaulted_price_ratio: ComputedFromHeightRatioExtended<M>,
|
||||
pub active_price: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub active_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub active_price_ratio: ComputedFromHeightRatioExtended<M>,
|
||||
pub true_market_mean: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub true_market_mean: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub true_market_mean_ratio: ComputedFromHeightRatioExtended<M>,
|
||||
pub cointime_price: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub cointime_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub cointime_price_ratio: ComputedFromHeightRatioExtended<M>,
|
||||
}
|
||||
|
||||
@@ -828,7 +828,7 @@ impl UTXOCohorts<Rw> {
|
||||
pub(crate) fn truncate_push_aggregate_percentiles(
|
||||
&mut self,
|
||||
height: Height,
|
||||
spot: Dollars,
|
||||
spot: Cents,
|
||||
day1_opt: Option<Day1>,
|
||||
states_path: &Path,
|
||||
) -> Result<()> {
|
||||
@@ -895,7 +895,7 @@ impl UTXOCohorts<Rw> {
|
||||
.collect();
|
||||
|
||||
if total_sats == 0 {
|
||||
let nan_prices = [Dollars::NAN; PERCENTILES_LEN];
|
||||
let nan_prices = [Cents::ZERO; PERCENTILES_LEN];
|
||||
target
|
||||
.extended
|
||||
.percentiles
|
||||
@@ -928,8 +928,8 @@ impl UTXOCohorts<Rw> {
|
||||
let sat_targets = PERCENTILES.map(|p| total_sats * u64::from(p) / 100);
|
||||
let usd_targets = PERCENTILES.map(|p| total_usd * u128::from(p) / 100);
|
||||
|
||||
let mut sat_result = [Dollars::NAN; PERCENTILES_LEN];
|
||||
let mut usd_result = [Dollars::NAN; PERCENTILES_LEN];
|
||||
let mut sat_result = [Cents::ZERO; PERCENTILES_LEN];
|
||||
let mut usd_result = [Cents::ZERO; PERCENTILES_LEN];
|
||||
|
||||
let mut cumsum_sats: u64 = 0;
|
||||
let mut cumsum_usd: u128 = 0;
|
||||
@@ -953,13 +953,12 @@ impl UTXOCohorts<Rw> {
|
||||
cumsum_usd += usd;
|
||||
|
||||
if sat_idx < PERCENTILES_LEN || usd_idx < PERCENTILES_LEN {
|
||||
let dollars = price.to_dollars();
|
||||
while sat_idx < PERCENTILES_LEN && cumsum_sats >= sat_targets[sat_idx] {
|
||||
sat_result[sat_idx] = dollars;
|
||||
sat_result[sat_idx] = price;
|
||||
sat_idx += 1;
|
||||
}
|
||||
while usd_idx < PERCENTILES_LEN && cumsum_usd >= usd_targets[usd_idx] {
|
||||
usd_result[usd_idx] = dollars;
|
||||
usd_result[usd_idx] = price;
|
||||
usd_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,10 +451,9 @@ pub(crate) fn process_blocks(
|
||||
)?;
|
||||
|
||||
// Compute and push percentiles for aggregate cohorts (all, sth, lth)
|
||||
let spot = block_price.to_dollars();
|
||||
vecs.utxo_cohorts.truncate_push_aggregate_percentiles(
|
||||
height,
|
||||
spot,
|
||||
block_price,
|
||||
day1_opt,
|
||||
&vecs.states_path,
|
||||
)?;
|
||||
|
||||
@@ -170,7 +170,7 @@ impl ActivityMetrics {
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent.base.sats.height,
|
||||
&self.sent.base.usd.height,
|
||||
&self.sent.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -99,8 +99,8 @@ impl AdjustedCohortMetrics {
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
all_supply_sats: &impl ReadableVec<Height, Sats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
|
||||
@@ -87,10 +87,9 @@ impl CohortMetricsBase for AllCohortMetrics {
|
||||
self.unrealized
|
||||
.base
|
||||
.truncate_push(height, &height_unrealized_state)?;
|
||||
let spot = height_price.to_dollars();
|
||||
self.cost_basis
|
||||
.extended
|
||||
.truncate_push_percentiles(height, state, spot)?;
|
||||
.truncate_push_percentiles(height, state, height_price)?;
|
||||
Ok(())
|
||||
}
|
||||
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
@@ -140,8 +139,8 @@ impl AllCohortMetrics {
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.realized.compute_rest_part2(
|
||||
|
||||
@@ -56,8 +56,7 @@ impl CohortMetricsBase for ExtendedCohortMetrics {
|
||||
self.cost_basis.truncate_push_minmax(height, state)?;
|
||||
let (height_unrealized_state, _) = state.compute_unrealized_states(height_price, None);
|
||||
self.unrealized.base.truncate_push(height, &height_unrealized_state)?;
|
||||
let spot = height_price.to_dollars();
|
||||
self.cost_basis.extended.truncate_push_percentiles(height, state, spot)?;
|
||||
self.cost_basis.extended.truncate_push_percentiles(height, state, height_price)?;
|
||||
Ok(())
|
||||
}
|
||||
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
|
||||
@@ -55,8 +55,7 @@ impl CohortMetricsBase for ExtendedAdjustedCohortMetrics {
|
||||
self.cost_basis.truncate_push_minmax(height, state)?;
|
||||
let (height_unrealized_state, _) = state.compute_unrealized_states(height_price, None);
|
||||
self.unrealized.base.truncate_push(height, &height_unrealized_state)?;
|
||||
let spot = height_price.to_dollars();
|
||||
self.cost_basis.extended.truncate_push_percentiles(height, state, spot)?;
|
||||
self.cost_basis.extended.truncate_push_percentiles(height, state, height_price)?;
|
||||
Ok(())
|
||||
}
|
||||
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
@@ -102,8 +101,8 @@ impl ExtendedAdjustedCohortMetrics {
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
all_supply_sats: &impl ReadableVec<Height, Sats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height};
|
||||
use brk_types::{Cents, Height};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -15,10 +15,10 @@ use crate::distribution::metrics::ImportConfig;
|
||||
#[derive(Traversable)]
|
||||
pub struct CostBasisBase<M: StorageMode = Rw> {
|
||||
/// Minimum cost basis for any UTXO at this height
|
||||
pub min: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub min: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
|
||||
/// Maximum cost basis for any UTXO at this height
|
||||
pub max: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub max: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
}
|
||||
|
||||
impl CostBasisBase {
|
||||
@@ -40,7 +40,7 @@ impl CostBasisBase {
|
||||
}
|
||||
|
||||
pub(crate) fn min_stateful_height_len(&self) -> usize {
|
||||
self.min.usd.height.len().min(self.max.usd.height.len())
|
||||
self.min.cents.height.len().min(self.max.cents.height.len())
|
||||
}
|
||||
|
||||
pub(crate) fn truncate_push_minmax(
|
||||
@@ -48,27 +48,27 @@ impl CostBasisBase {
|
||||
height: Height,
|
||||
state: &CohortState,
|
||||
) -> Result<()> {
|
||||
self.min.usd.height.truncate_push(
|
||||
self.min.cents.height.truncate_push(
|
||||
height,
|
||||
state
|
||||
.cost_basis_data_first_key_value()
|
||||
.map(|(cents, _)| cents.into())
|
||||
.unwrap_or(Dollars::NAN),
|
||||
.map(|(cents, _)| cents)
|
||||
.unwrap_or(Cents::ZERO),
|
||||
)?;
|
||||
self.max.usd.height.truncate_push(
|
||||
self.max.cents.height.truncate_push(
|
||||
height,
|
||||
state
|
||||
.cost_basis_data_last_key_value()
|
||||
.map(|(cents, _)| cents.into())
|
||||
.unwrap_or(Dollars::NAN),
|
||||
.map(|(cents, _)| cents)
|
||||
.unwrap_or(Cents::ZERO),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.min.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.max.usd.height,
|
||||
&mut self.min.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.max.cents.height,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -78,14 +78,14 @@ impl CostBasisBase {
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.min.usd.height.compute_min_of_others(
|
||||
self.min.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
&others.iter().map(|v| &v.min.usd.height).collect::<Vec<_>>(),
|
||||
&others.iter().map(|v| &v.min.cents.height).collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
self.max.usd.height.compute_max_of_others(
|
||||
self.max.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
&others.iter().map(|v| &v.max.usd.height).collect::<Vec<_>>(),
|
||||
&others.iter().map(|v| &v.max.cents.height).collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{AnyStoredVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -62,14 +62,14 @@ impl CostBasisExtended {
|
||||
&mut self,
|
||||
height: Height,
|
||||
state: &mut CohortState,
|
||||
spot: Dollars,
|
||||
spot: Cents,
|
||||
) -> Result<()> {
|
||||
let computed = state.compute_percentiles();
|
||||
|
||||
let sat_prices = computed
|
||||
.as_ref()
|
||||
.map(|p| p.sat_weighted.map(|c| c.to_dollars()))
|
||||
.unwrap_or([Dollars::NAN; PERCENTILES_LEN]);
|
||||
.map(|p| p.sat_weighted)
|
||||
.unwrap_or([Cents::ZERO; PERCENTILES_LEN]);
|
||||
|
||||
self.percentiles.truncate_push(height, &sat_prices)?;
|
||||
let rank = compute_spot_percentile_rank(&sat_prices, spot);
|
||||
@@ -79,8 +79,8 @@ impl CostBasisExtended {
|
||||
|
||||
let usd_prices = computed
|
||||
.as_ref()
|
||||
.map(|p| p.usd_weighted.map(|c| c.to_dollars()))
|
||||
.unwrap_or([Dollars::NAN; PERCENTILES_LEN]);
|
||||
.map(|p| p.usd_weighted)
|
||||
.unwrap_or([Cents::ZERO; PERCENTILES_LEN]);
|
||||
|
||||
self.invested_capital.truncate_push(height, &usd_prices)?;
|
||||
let rank = compute_spot_percentile_rank(&usd_prices, spot);
|
||||
@@ -97,13 +97,13 @@ impl CostBasisExtended {
|
||||
self.percentiles
|
||||
.vecs
|
||||
.iter_mut()
|
||||
.map(|v| &mut v.usd.height as &mut dyn AnyStoredVec),
|
||||
.map(|v| &mut v.cents.height as &mut dyn AnyStoredVec),
|
||||
);
|
||||
vecs.extend(
|
||||
self.invested_capital
|
||||
.vecs
|
||||
.iter_mut()
|
||||
.map(|v| &mut v.usd.height as &mut dyn AnyStoredVec),
|
||||
.map(|v| &mut v.cents.height as &mut dyn AnyStoredVec),
|
||||
);
|
||||
vecs.push(&mut self.spot_cost_basis_percentile.height);
|
||||
vecs.push(&mut self.spot_invested_capital_percentile.height);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF64, Version};
|
||||
use brk_types::{Cents, Height, StoredF64, Version};
|
||||
use vecdb::{Exit, Ident, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, Ratio64},
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, RatioCents64},
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
@@ -14,18 +14,18 @@ use crate::distribution::metrics::ImportConfig;
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedAdjusted<M: StorageMode = Rw> {
|
||||
// === Adjusted Value (computed: cohort - up_to_1h) ===
|
||||
pub adjusted_value_created: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_destroyed: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_created: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_destroyed: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Adjusted Value Created/Destroyed Rolling Sums ===
|
||||
pub adjusted_value_created_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_created_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_created_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_created_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_destroyed_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_destroyed_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_destroyed_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_destroyed_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub adjusted_value_created_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_created_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_created_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_created_1y: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_destroyed_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_destroyed_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_destroyed_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub adjusted_value_destroyed_1y: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Adjusted SOPR (rolling window ratios) ===
|
||||
pub adjusted_sopr: LazyFromHeightLast<StoredF64>,
|
||||
@@ -150,10 +150,10 @@ impl RealizedAdjusted {
|
||||
&mut self,
|
||||
blocks: &blocks::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
base_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
base_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
base_value_created: &impl ReadableVec<Height, Cents>,
|
||||
base_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// Compute adjusted_value_created = base.value_created - up_to_1h.value_created
|
||||
@@ -231,28 +231,28 @@ impl RealizedAdjusted {
|
||||
|
||||
// SOPR ratios from rolling sums
|
||||
self.adjusted_sopr_24h
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.adjusted_value_created_24h.height,
|
||||
&self.adjusted_value_destroyed_24h.height,
|
||||
exit,
|
||||
)?;
|
||||
self.adjusted_sopr_7d
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.adjusted_value_created_7d.height,
|
||||
&self.adjusted_value_destroyed_7d.height,
|
||||
exit,
|
||||
)?;
|
||||
self.adjusted_sopr_30d
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.adjusted_value_created_30d.height,
|
||||
&self.adjusted_value_destroyed_30d.height,
|
||||
exit,
|
||||
)?;
|
||||
self.adjusted_sopr_1y
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.adjusted_value_created_1y.height,
|
||||
&self.adjusted_value_destroyed_1y.height,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Bitcoin, Cents, CentsSats, CentsSquaredSats, Dollars, Height, StoredF32, StoredF64, Version,
|
||||
Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats, Dollars, Height, Sats, StoredF32, StoredF64, Version,
|
||||
};
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, BytesVec, Exit, Ident, ImportableVec, Negate, ReadableCloneableVec,
|
||||
AnyStoredVec, AnyVec, BytesVec, Exit, Ident, ImportableVec, ReadableCloneableVec,
|
||||
ReadableVec, Rw, StorageMode, WritableVec,
|
||||
};
|
||||
|
||||
@@ -12,9 +12,9 @@ use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
distribution::state::RealizedState,
|
||||
internal::{
|
||||
CentsUnsignedToDollars, ComputedFromHeightCumulative, ComputedFromHeightLast,
|
||||
ComputedFromHeightRatio, DollarsPlus, ValueFromHeightCumulative, LazyFromHeightLast,
|
||||
PercentageDollarsF32, Price, Ratio64,
|
||||
CentsPlus, CentsUnsignedToDollars, ComputedFromHeightCumulative, ComputedFromHeightLast,
|
||||
ComputedFromHeightRatio, NegCentsUnsignedToDollars, ValueFromHeightCumulative, LazyFromHeightLast,
|
||||
PercentageCentsF32, PercentageCentsSignedCentsF32, PercentageCentsSignedDollarsF32, Price, RatioCents64,
|
||||
StoredF32Identity, ValueFromHeightLast,
|
||||
},
|
||||
prices,
|
||||
@@ -28,18 +28,17 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
// === Realized Cap ===
|
||||
pub realized_cap_cents: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_cap: LazyFromHeightLast<Dollars, Cents>,
|
||||
pub realized_price: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub realized_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub realized_price_extra: ComputedFromHeightRatio<M>,
|
||||
pub realized_cap_30d_delta: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_cap_30d_delta: ComputedFromHeightLast<CentsSigned, M>,
|
||||
|
||||
// === Investor Price ===
|
||||
pub investor_price_cents: ComputedFromHeightLast<Cents, M>,
|
||||
pub investor_price: Price<LazyFromHeightLast<Dollars, Cents>>,
|
||||
pub investor_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub investor_price_extra: ComputedFromHeightRatio<M>,
|
||||
|
||||
// === Floor/Ceiling Price Bands ===
|
||||
pub lower_price_band: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub upper_price_band: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub lower_price_band: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub upper_price_band: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
|
||||
// === Raw values for aggregation ===
|
||||
pub cap_raw: M::Stored<BytesVec<Height, CentsSats>>,
|
||||
@@ -49,14 +48,14 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
pub mvrv: LazyFromHeightLast<StoredF32>,
|
||||
|
||||
// === Realized Profit/Loss ===
|
||||
pub realized_profit: ComputedFromHeightCumulative<Dollars, M>,
|
||||
pub realized_profit_7d_ema: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_loss: ComputedFromHeightCumulative<Dollars, M>,
|
||||
pub realized_loss_7d_ema: ComputedFromHeightLast<Dollars, M>,
|
||||
pub neg_realized_loss: LazyFromHeightLast<Dollars>,
|
||||
pub net_realized_pnl: ComputedFromHeightCumulative<Dollars, M>,
|
||||
pub net_realized_pnl_7d_ema: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_value: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_profit: ComputedFromHeightCumulative<Cents, M>,
|
||||
pub realized_profit_7d_ema: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_loss: ComputedFromHeightCumulative<Cents, M>,
|
||||
pub realized_loss_7d_ema: ComputedFromHeightLast<Cents, M>,
|
||||
pub neg_realized_loss: LazyFromHeightLast<Dollars, Cents>,
|
||||
pub net_realized_pnl: ComputedFromHeightCumulative<CentsSigned, M>,
|
||||
pub net_realized_pnl_7d_ema: ComputedFromHeightLast<CentsSigned, M>,
|
||||
pub realized_value: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Realized vs Realized Cap Ratios ===
|
||||
pub realized_profit_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
|
||||
@@ -64,31 +63,31 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
pub net_realized_pnl_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
// === Total Realized PnL ===
|
||||
pub total_realized_pnl: LazyFromHeightLast<Dollars>,
|
||||
pub total_realized_pnl: LazyFromHeightLast<Dollars, Cents>,
|
||||
|
||||
// === Value Created/Destroyed Splits (stored) ===
|
||||
pub profit_value_created: ComputedFromHeightLast<Dollars, M>,
|
||||
pub profit_value_destroyed: ComputedFromHeightLast<Dollars, M>,
|
||||
pub loss_value_created: ComputedFromHeightLast<Dollars, M>,
|
||||
pub loss_value_destroyed: ComputedFromHeightLast<Dollars, M>,
|
||||
pub profit_value_created: ComputedFromHeightLast<Cents, M>,
|
||||
pub profit_value_destroyed: ComputedFromHeightLast<Cents, M>,
|
||||
pub loss_value_created: ComputedFromHeightLast<Cents, M>,
|
||||
pub loss_value_destroyed: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Value Created/Destroyed Totals ===
|
||||
pub value_created: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_destroyed: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_created: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_destroyed: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Capitulation/Profit Flow (lazy aliases) ===
|
||||
pub capitulation_flow: LazyFromHeightLast<Dollars>,
|
||||
pub profit_flow: LazyFromHeightLast<Dollars>,
|
||||
pub capitulation_flow: LazyFromHeightLast<Dollars, Cents>,
|
||||
pub profit_flow: LazyFromHeightLast<Dollars, Cents>,
|
||||
|
||||
// === Value Created/Destroyed Rolling Sums ===
|
||||
pub value_created_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_created_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_created_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_created_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_destroyed_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_destroyed_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_destroyed_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_destroyed_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub value_created_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_created_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_created_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_created_1y: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_destroyed_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_destroyed_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_destroyed_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub value_destroyed_1y: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === SOPR (rolling window ratios) ===
|
||||
pub sopr: LazyFromHeightLast<StoredF64>,
|
||||
@@ -102,10 +101,10 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
pub sopr_30d_ema: LazyFromHeightLast<StoredF64>,
|
||||
|
||||
// === Sell Side Risk Rolling Sum Intermediates ===
|
||||
pub realized_value_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_value_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_value_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_value_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_value_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_value_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_value_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_value_1y: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Sell Side Risk (rolling window ratios) ===
|
||||
pub sell_side_risk_ratio: LazyFromHeightLast<StoredF32>,
|
||||
@@ -119,14 +118,14 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
pub sell_side_risk_ratio_30d_ema: LazyFromHeightLast<StoredF32>,
|
||||
|
||||
// === Net Realized PnL Deltas ===
|
||||
pub net_realized_pnl_cumulative_30d_delta: ComputedFromHeightLast<Dollars, M>,
|
||||
pub net_realized_pnl_cumulative_30d_delta: ComputedFromHeightLast<CentsSigned, M>,
|
||||
pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap:
|
||||
ComputedFromHeightLast<StoredF32, M>,
|
||||
pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap:
|
||||
ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
// === Peak Regret ===
|
||||
pub peak_regret: ComputedFromHeightCumulative<Dollars, M>,
|
||||
pub peak_regret: ComputedFromHeightCumulative<Cents, M>,
|
||||
pub peak_regret_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
// === Sent in Profit/Loss ===
|
||||
@@ -185,7 +184,7 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let neg_realized_loss = LazyFromHeightLast::from_height_source::<Negate>(
|
||||
let neg_realized_loss = LazyFromHeightLast::from_height_source::<NegCentsUnsignedToDollars>(
|
||||
&cfg.name("neg_realized_loss"),
|
||||
cfg.version + v1,
|
||||
realized_loss.height.read_only_boxed_clone(),
|
||||
@@ -220,7 +219,7 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let total_realized_pnl = LazyFromHeightLast::from_computed::<Ident>(
|
||||
let total_realized_pnl = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("total_realized_pnl"),
|
||||
cfg.version + v1,
|
||||
realized_value.height.read_only_boxed_clone(),
|
||||
@@ -255,19 +254,13 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let investor_price_cents = ComputedFromHeightLast::forced_import(
|
||||
let investor_price = Price::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("investor_price_cents"),
|
||||
&cfg.name("investor_price"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let investor_price = Price::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("investor_price"),
|
||||
cfg.version,
|
||||
&investor_price_cents,
|
||||
);
|
||||
|
||||
let investor_price_extra = ComputedFromHeightRatio::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("investor_price"),
|
||||
@@ -331,13 +324,13 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let capitulation_flow = LazyFromHeightLast::from_computed::<Ident>(
|
||||
let capitulation_flow = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("capitulation_flow"),
|
||||
cfg.version,
|
||||
loss_value_destroyed.height.read_only_boxed_clone(),
|
||||
&loss_value_destroyed,
|
||||
);
|
||||
let profit_flow = LazyFromHeightLast::from_computed::<Ident>(
|
||||
let profit_flow = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("profit_flow"),
|
||||
cfg.version,
|
||||
profit_value_destroyed.height.read_only_boxed_clone(),
|
||||
@@ -460,7 +453,6 @@ impl RealizedBase {
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
investor_price_cents,
|
||||
investor_price,
|
||||
investor_price_extra,
|
||||
lower_price_band,
|
||||
@@ -574,7 +566,7 @@ impl RealizedBase {
|
||||
.len()
|
||||
.min(self.realized_profit.height.len())
|
||||
.min(self.realized_loss.height.len())
|
||||
.min(self.investor_price_cents.height.len())
|
||||
.min(self.investor_price.cents.height.len())
|
||||
.min(self.cap_raw.len())
|
||||
.min(self.investor_cap_raw.len())
|
||||
.min(self.profit_value_created.height.len())
|
||||
@@ -593,11 +585,11 @@ impl RealizedBase {
|
||||
.truncate_push(height, state.cap())?;
|
||||
self.realized_profit
|
||||
.height
|
||||
.truncate_push(height, state.profit().to_dollars())?;
|
||||
.truncate_push(height, state.profit())?;
|
||||
self.realized_loss
|
||||
.height
|
||||
.truncate_push(height, state.loss().to_dollars())?;
|
||||
self.investor_price_cents
|
||||
.truncate_push(height, state.loss())?;
|
||||
self.investor_price.cents
|
||||
.height
|
||||
.truncate_push(height, state.investor_price())?;
|
||||
self.cap_raw.truncate_push(height, state.cap_raw())?;
|
||||
@@ -605,19 +597,19 @@ impl RealizedBase {
|
||||
.truncate_push(height, state.investor_cap_raw())?;
|
||||
self.profit_value_created
|
||||
.height
|
||||
.truncate_push(height, state.profit_value_created().to_dollars())?;
|
||||
.truncate_push(height, state.profit_value_created())?;
|
||||
self.profit_value_destroyed
|
||||
.height
|
||||
.truncate_push(height, state.profit_value_destroyed().to_dollars())?;
|
||||
.truncate_push(height, state.profit_value_destroyed())?;
|
||||
self.loss_value_created
|
||||
.height
|
||||
.truncate_push(height, state.loss_value_created().to_dollars())?;
|
||||
.truncate_push(height, state.loss_value_created())?;
|
||||
self.loss_value_destroyed
|
||||
.height
|
||||
.truncate_push(height, state.loss_value_destroyed().to_dollars())?;
|
||||
.truncate_push(height, state.loss_value_destroyed())?;
|
||||
self.peak_regret
|
||||
.height
|
||||
.truncate_push(height, state.peak_regret().to_dollars())?;
|
||||
.truncate_push(height, state.peak_regret())?;
|
||||
self.sent_in_profit
|
||||
.base
|
||||
.sats
|
||||
@@ -638,7 +630,7 @@ impl RealizedBase {
|
||||
&mut self.realized_cap_cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.realized_profit.height,
|
||||
&mut self.realized_loss.height,
|
||||
&mut self.investor_price_cents.height,
|
||||
&mut self.investor_price.cents.height,
|
||||
&mut self.cap_raw as &mut dyn AnyStoredVec,
|
||||
&mut self.investor_cap_raw as &mut dyn AnyStoredVec,
|
||||
&mut self.profit_value_created.height,
|
||||
@@ -686,9 +678,9 @@ impl RealizedBase {
|
||||
// Aggregate raw values for investor_price computation
|
||||
let investor_price_dep_version = others
|
||||
.iter()
|
||||
.map(|o| o.investor_price_cents.height.version())
|
||||
.map(|o| o.investor_price.cents.height.version())
|
||||
.fold(vecdb::Version::ZERO, |acc, v| acc + v);
|
||||
self.investor_price_cents
|
||||
self.investor_price.cents
|
||||
.height
|
||||
.validate_computed_version_or_reset(investor_price_dep_version)?;
|
||||
|
||||
@@ -696,7 +688,7 @@ impl RealizedBase {
|
||||
.cap_raw
|
||||
.len()
|
||||
.min(self.investor_cap_raw.len())
|
||||
.min(self.investor_price_cents.height.len());
|
||||
.min(self.investor_price.cents.height.len());
|
||||
let end = others.iter().map(|o| o.cap_raw.len()).min().unwrap_or(0);
|
||||
|
||||
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
|
||||
@@ -730,14 +722,14 @@ impl RealizedBase {
|
||||
} else {
|
||||
Cents::new((sum_investor_cap / sum_cap.inner()) as u64)
|
||||
};
|
||||
self.investor_price_cents
|
||||
self.investor_price.cents
|
||||
.height
|
||||
.truncate_push(height, investor_price)?;
|
||||
}
|
||||
|
||||
{
|
||||
let _lock = exit.lock();
|
||||
self.investor_price_cents.height.write()?;
|
||||
self.investor_price.cents.height.write()?;
|
||||
}
|
||||
|
||||
self.profit_value_created.height.compute_sum_of_others(
|
||||
@@ -813,10 +805,13 @@ impl RealizedBase {
|
||||
|
||||
self.net_realized_pnl
|
||||
.compute(starting_indexes.height, exit, |vec| {
|
||||
vec.compute_subtract(
|
||||
vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit.height,
|
||||
&self.realized_loss.height,
|
||||
|(i, profit, loss, ..)| {
|
||||
(i, CentsSigned::new(profit.inner() as i64 - loss.inner() as i64))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -846,47 +841,64 @@ impl RealizedBase {
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.realized_price.usd.height.compute_divide(
|
||||
self.realized_price.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
height_to_supply,
|
||||
|(i, cap_cents, supply, ..)| {
|
||||
let cap = cap_cents.as_u128();
|
||||
let supply_sats = Sats::from(supply).as_u128();
|
||||
if supply_sats == 0 {
|
||||
(i, Cents::ZERO)
|
||||
} else {
|
||||
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.realized_price_extra.compute_ratio(
|
||||
starting_indexes,
|
||||
&prices.price.usd.height,
|
||||
&self.realized_price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
&self.realized_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.investor_price_extra.compute_ratio(
|
||||
starting_indexes,
|
||||
&prices.price.usd.height,
|
||||
&self.investor_price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
&self.investor_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.lower_price_band.usd.height.compute_transform2(
|
||||
self.lower_price_band.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.realized_price.usd.height,
|
||||
&self.investor_price.usd.height,
|
||||
&self.realized_price.cents.height,
|
||||
&self.investor_price.cents.height,
|
||||
|(i, rp, ip, ..)| {
|
||||
let rp = f64::from(rp);
|
||||
let ip = f64::from(ip);
|
||||
(i, Dollars::from(rp * rp / ip))
|
||||
let rp = rp.as_u128();
|
||||
let ip = ip.as_u128();
|
||||
if ip == 0 {
|
||||
(i, Cents::ZERO)
|
||||
} else {
|
||||
(i, Cents::from(rp * rp / ip))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.upper_price_band.usd.height.compute_transform2(
|
||||
self.upper_price_band.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.investor_price.usd.height,
|
||||
&self.realized_price.usd.height,
|
||||
&self.investor_price.cents.height,
|
||||
&self.realized_price.cents.height,
|
||||
|(i, ip, rp, ..)| {
|
||||
let ip = f64::from(ip);
|
||||
let rp = f64::from(rp);
|
||||
(i, Dollars::from(ip * ip / rp))
|
||||
let ip = ip.as_u128();
|
||||
let rp = rp.as_u128();
|
||||
if rp == 0 {
|
||||
(i, Cents::ZERO)
|
||||
} else {
|
||||
(i, Cents::from(ip * ip / rp))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
@@ -894,20 +906,20 @@ impl RealizedBase {
|
||||
self.realized_cap_30d_delta.height.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Compute value_created/destroyed from stored components
|
||||
self.value_created
|
||||
.compute_binary::<Dollars, Dollars, DollarsPlus>(
|
||||
.compute_binary::<Cents, Cents, CentsPlus>(
|
||||
starting_indexes.height,
|
||||
&self.profit_value_created.height,
|
||||
&self.loss_value_created.height,
|
||||
exit,
|
||||
)?;
|
||||
self.value_destroyed
|
||||
.compute_binary::<Dollars, Dollars, DollarsPlus>(
|
||||
.compute_binary::<Cents, Cents, CentsPlus>(
|
||||
starting_indexes.height,
|
||||
&self.profit_value_destroyed.height,
|
||||
&self.loss_value_destroyed.height,
|
||||
@@ -990,25 +1002,25 @@ impl RealizedBase {
|
||||
);
|
||||
|
||||
// Compute SOPR from rolling sums
|
||||
self.sopr_24h.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
self.sopr_24h.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.value_created_24h.height,
|
||||
&self.value_destroyed_24h.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sopr_7d.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
self.sopr_7d.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.value_created_7d.height,
|
||||
&self.value_destroyed_7d.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sopr_30d.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
self.sopr_30d.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.value_created_30d.height,
|
||||
&self.value_destroyed_30d.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sopr_1y.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
self.sopr_1y.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.value_created_1y.height,
|
||||
&self.value_destroyed_1y.height,
|
||||
@@ -1017,31 +1029,31 @@ impl RealizedBase {
|
||||
|
||||
// Compute sell-side risk ratios
|
||||
self.sell_side_risk_ratio_24h
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.realized_value_24h.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sell_side_risk_ratio_7d
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.realized_value_7d.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sell_side_risk_ratio_30d
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.realized_value_30d.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sell_side_risk_ratio_1y
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.realized_value_1y.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -1072,14 +1084,14 @@ impl RealizedBase {
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent_in_profit.base.sats.height,
|
||||
&self.sent_in_profit.base.usd.height,
|
||||
&self.sent_in_profit.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sent_in_loss_14d_ema.compute_ema(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent_in_loss.base.sats.height,
|
||||
&self.sent_in_loss.base.usd.height,
|
||||
&self.sent_in_loss.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -1117,31 +1129,31 @@ impl RealizedBase {
|
||||
|
||||
// Realized profit/loss/net relative to realized cap
|
||||
self.realized_profit_rel_to_realized_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.realized_loss_rel_to_realized_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.realized_loss.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.net_realized_pnl_rel_to_realized_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<CentsSigned, Cents, PercentageCentsSignedCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.net_realized_pnl.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.peak_regret_rel_to_realized_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.peak_regret.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -1156,17 +1168,15 @@ impl RealizedBase {
|
||||
)?;
|
||||
|
||||
self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap
|
||||
.height
|
||||
.compute_percentage(
|
||||
.compute_binary::<CentsSigned, Cents, PercentageCentsSignedCentsF32>(
|
||||
starting_indexes.height,
|
||||
&self.net_realized_pnl_cumulative_30d_delta.height,
|
||||
&self.realized_cap.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap
|
||||
.height
|
||||
.compute_percentage(
|
||||
.compute_binary::<CentsSigned, Dollars, PercentageCentsSignedDollarsF32>(
|
||||
starting_indexes.height,
|
||||
&self.net_realized_pnl_cumulative_30d_delta.height,
|
||||
height_to_market_cap,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, StoredF64, Version};
|
||||
use brk_types::{Cents, Dollars, Height, StoredF32, StoredF64, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
internal::{ComputedFromHeightLast, ComputedFromHeightRatioExtension, Ratio64},
|
||||
internal::{ComputedFromHeightLast, ComputedFromHeightRatioExtension, RatioCents64},
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
@@ -18,14 +18,14 @@ pub struct RealizedExtended<M: StorageMode = Rw> {
|
||||
pub realized_cap_rel_to_own_market_cap: ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
// === Realized Profit/Loss Rolling Sums ===
|
||||
pub realized_profit_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_profit_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_profit_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_profit_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_loss_24h: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_loss_7d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_loss_30d: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_loss_1y: ComputedFromHeightLast<Dollars, M>,
|
||||
pub realized_profit_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_profit_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_profit_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_profit_1y: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_loss_24h: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_loss_7d: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_loss_30d: ComputedFromHeightLast<Cents, M>,
|
||||
pub realized_loss_1y: ComputedFromHeightLast<Cents, M>,
|
||||
|
||||
// === Realized Profit to Loss Ratio (from rolling sums) ===
|
||||
pub realized_profit_to_loss_ratio_24h: ComputedFromHeightLast<StoredF64, M>,
|
||||
@@ -158,28 +158,28 @@ impl RealizedExtended {
|
||||
|
||||
// Realized profit to loss ratios
|
||||
self.realized_profit_to_loss_ratio_24h
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit_24h.height,
|
||||
&self.realized_loss_24h.height,
|
||||
exit,
|
||||
)?;
|
||||
self.realized_profit_to_loss_ratio_7d
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit_7d.height,
|
||||
&self.realized_loss_7d.height,
|
||||
exit,
|
||||
)?;
|
||||
self.realized_profit_to_loss_ratio_30d
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit_30d.height,
|
||||
&self.realized_loss_30d.height,
|
||||
exit,
|
||||
)?;
|
||||
self.realized_profit_to_loss_ratio_1y
|
||||
.compute_binary::<Dollars, Dollars, Ratio64>(
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit_1y.height,
|
||||
&self.realized_loss_1y.height,
|
||||
@@ -193,9 +193,9 @@ impl RealizedExtended {
|
||||
exit,
|
||||
&base.realized_price_extra.ratio.height,
|
||||
)?;
|
||||
self.realized_price_ratio_ext.compute_usd_bands(
|
||||
self.realized_price_ratio_ext.compute_cents_bands(
|
||||
starting_indexes,
|
||||
&base.realized_price.usd.height,
|
||||
&base.realized_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -205,9 +205,9 @@ impl RealizedExtended {
|
||||
exit,
|
||||
&base.investor_price_extra.ratio.height,
|
||||
)?;
|
||||
self.investor_price_ratio_ext.compute_usd_bands(
|
||||
self.investor_price_ratio_ext.compute_cents_bands(
|
||||
starting_indexes,
|
||||
&base.investor_price.usd.height,
|
||||
&base.investor_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Height};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -36,8 +36,8 @@ impl RealizedWithAdjusted {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base.compute_rest_part2_base(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Height};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -43,8 +43,8 @@ impl RealizedWithExtendedAdjusted {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base.compute_rest_part2_base(
|
||||
|
||||
@@ -67,7 +67,7 @@ impl SupplyMetrics {
|
||||
pub(crate) fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.total.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.total.base.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.total.base.cents.height as &mut dyn AnyStoredVec,
|
||||
]
|
||||
.into_par_iter()
|
||||
}
|
||||
@@ -117,7 +117,7 @@ impl SupplyMetrics {
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.total.sats.height,
|
||||
&self.total.usd.height,
|
||||
&self.total.cents.height,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -237,9 +237,9 @@ impl UnrealizedBase {
|
||||
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.usd.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.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.unrealized_profit.height,
|
||||
&mut self.unrealized_loss.height,
|
||||
&mut self.invested_capital_in_profit.height,
|
||||
|
||||
@@ -4,12 +4,14 @@ mod windows;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Sats, Version};
|
||||
use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
|
||||
internal::{
|
||||
CentsUnsignedToDollars, ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin,
|
||||
},
|
||||
};
|
||||
|
||||
pub use rolling_full::*;
|
||||
@@ -19,7 +21,8 @@ pub use rolling_sum::*;
|
||||
pub struct ByUnit<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
pub cents: ComputedFromHeightLast<Cents, M>,
|
||||
pub usd: LazyFromHeightLast<Dollars, Cents>,
|
||||
}
|
||||
|
||||
impl ByUnit {
|
||||
@@ -38,9 +41,25 @@ impl ByUnit {
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd =
|
||||
ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), version, indexes)?;
|
||||
let cents = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_cents"),
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
sats,
|
||||
btc,
|
||||
cents,
|
||||
usd,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -47,11 +47,11 @@ impl RollingFullSlot {
|
||||
max_from: Height,
|
||||
starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sum.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?;
|
||||
self.sum.usd.height.compute_rolling_sum(max_from, starts, usd_source, exit)?;
|
||||
self.sum.cents.height.compute_rolling_sum(max_from, starts, cents_source, exit)?;
|
||||
|
||||
let d = &mut self.distribution;
|
||||
|
||||
@@ -64,11 +64,11 @@ impl RollingFullSlot {
|
||||
)?;
|
||||
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, starts, usd_source,
|
||||
&mut d.average.usd.height, &mut d.min.usd.height,
|
||||
&mut d.max.usd.height, &mut d.pct10.usd.height,
|
||||
&mut d.pct25.usd.height, &mut d.median.usd.height,
|
||||
&mut d.pct75.usd.height, &mut d.pct90.usd.height, exit,
|
||||
max_from, starts, cents_source,
|
||||
&mut d.average.cents.height, &mut d.min.cents.height,
|
||||
&mut d.max.cents.height, &mut d.pct10.cents.height,
|
||||
&mut d.pct25.cents.height, &mut d.median.cents.height,
|
||||
&mut d.pct75.cents.height, &mut d.pct90.cents.height, exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@@ -105,11 +105,11 @@ impl RollingFullByUnit {
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (slot, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
slot.compute(max_from, starts, sats_source, usd_source, exit)?;
|
||||
slot.compute(max_from, starts, sats_source, cents_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -34,12 +34,12 @@ impl RollingSumByUnit {
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?;
|
||||
w.usd.height.compute_rolling_sum(max_from, starts, usd_source, exit)?;
|
||||
w.cents.height.compute_rolling_sum(max_from, starts, cents_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::{Traversable, TreeNode};
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{AnyExportableVec, Database, ReadOnlyClone, Ro, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::indexes;
|
||||
@@ -14,10 +14,10 @@ pub const PERCENTILES_LEN: usize = PERCENTILES.len();
|
||||
/// Compute spot percentile rank by interpolating within percentile bands.
|
||||
/// Returns a value between 0 and 100 indicating where spot sits in the distribution.
|
||||
pub(crate) fn compute_spot_percentile_rank(
|
||||
percentile_prices: &[Dollars; PERCENTILES_LEN],
|
||||
spot: Dollars,
|
||||
percentile_prices: &[Cents; PERCENTILES_LEN],
|
||||
spot: Cents,
|
||||
) -> StoredF32 {
|
||||
if spot.is_nan() || percentile_prices[0].is_nan() {
|
||||
if spot == Cents::ZERO && percentile_prices[0] == Cents::ZERO {
|
||||
return StoredF32::NAN;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ pub(crate) fn compute_spot_percentile_rank(
|
||||
}
|
||||
|
||||
pub struct PercentilesVecs<M: StorageMode = Rw> {
|
||||
pub vecs: [Price<ComputedFromHeightLast<Dollars, M>>; PERCENTILES_LEN],
|
||||
pub vecs: [Price<ComputedFromHeightLast<Cents, M>>; PERCENTILES_LEN],
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
@@ -94,14 +94,14 @@ impl PercentilesVecs {
|
||||
Ok(Self { vecs })
|
||||
}
|
||||
|
||||
/// Push percentile prices at this height.
|
||||
/// Push percentile prices at this height (in cents).
|
||||
pub(crate) fn truncate_push(
|
||||
&mut self,
|
||||
height: Height,
|
||||
percentile_prices: &[Dollars; PERCENTILES_LEN],
|
||||
percentile_prices: &[Cents; PERCENTILES_LEN],
|
||||
) -> Result<()> {
|
||||
for (i, v) in self.vecs.iter_mut().enumerate() {
|
||||
v.usd.height.truncate_push(height, percentile_prices[i])?;
|
||||
v.cents.height.truncate_push(height, percentile_prices[i])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -109,7 +109,7 @@ impl PercentilesVecs {
|
||||
/// Validate computed versions or reset if mismatched.
|
||||
pub(crate) fn validate_computed_version_or_reset(&mut self, version: Version) -> Result<()> {
|
||||
for vec in self.vecs.iter_mut() {
|
||||
vec.usd.height.validate_computed_version_or_reset(version)?;
|
||||
vec.cents.height.validate_computed_version_or_reset(version)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -130,7 +130,7 @@ impl ReadOnlyClone for PercentilesVecs {
|
||||
|
||||
impl<M: StorageMode> Traversable for PercentilesVecs<M>
|
||||
where
|
||||
Price<ComputedFromHeightLast<Dollars, M>>: Traversable,
|
||||
Price<ComputedFromHeightLast<Cents, M>>: Traversable,
|
||||
{
|
||||
fn to_tree_node(&self) -> TreeNode {
|
||||
TreeNode::Branch(
|
||||
|
||||
@@ -1,65 +1,104 @@
|
||||
//! Generic price wrapper with both USD and sats representations.
|
||||
//! Generic price wrapper with cents, USD, and sats representations.
|
||||
//!
|
||||
//! All prices use this single struct with different USD types.
|
||||
//! All prices use this single struct with different cents types.
|
||||
//! USD is always lazily derived from cents via CentsUnsignedToDollars.
|
||||
//! Sats is always lazily derived from USD via DollarsToSatsFract.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, SatsFract, Version};
|
||||
use brk_types::{Cents, Dollars, SatsFract, Version};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{Database, ReadableCloneableVec, UnaryTransform};
|
||||
|
||||
use super::{ComputedFromHeightLast, LazyFromHeightLast};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedVecValue, DollarsToSatsFract, NumericValue},
|
||||
internal::{CentsUnsignedToDollars, ComputedVecValue, DollarsToSatsFract, NumericValue},
|
||||
};
|
||||
|
||||
/// Generic price metric with both USD and sats representations.
|
||||
/// Generic price metric with cents, USD, and sats representations.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Price<U> {
|
||||
pub usd: U,
|
||||
pub struct Price<C> {
|
||||
pub cents: C,
|
||||
pub usd: LazyFromHeightLast<Dollars, Cents>,
|
||||
pub sats: LazyFromHeightLast<SatsFract, Dollars>,
|
||||
}
|
||||
|
||||
impl Price<ComputedFromHeightLast<Dollars>> {
|
||||
impl Price<ComputedFromHeightLast<Cents>> {
|
||||
/// Import from database: stored cents, lazy USD + sats.
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let usd = ComputedFromHeightLast::forced_import(db, name, version, indexes)?;
|
||||
let sats = LazyFromHeightLast::from_computed::<DollarsToSatsFract>(
|
||||
let cents = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_cents"),
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
|
||||
&format!("{name}_sats"),
|
||||
version,
|
||||
usd.height.read_only_boxed_clone(),
|
||||
&usd,
|
||||
);
|
||||
Ok(Self { usd, sats })
|
||||
Ok(Self { cents, usd, sats })
|
||||
}
|
||||
|
||||
/// Wrap an already-imported ComputedFromHeightLast<Cents> with lazy USD + sats.
|
||||
pub(crate) fn from_cents(
|
||||
name: &str,
|
||||
version: Version,
|
||||
cents: ComputedFromHeightLast<Cents>,
|
||||
) -> Self {
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
|
||||
&format!("{name}_sats"),
|
||||
version,
|
||||
&usd,
|
||||
);
|
||||
Self { cents, usd, sats }
|
||||
}
|
||||
}
|
||||
|
||||
impl<ST> Price<LazyFromHeightLast<Dollars, ST>>
|
||||
impl<ST> Price<LazyFromHeightLast<Cents, ST>>
|
||||
where
|
||||
ST: ComputedVecValue + NumericValue + JsonSchema + 'static,
|
||||
{
|
||||
pub(crate) fn from_computed<F: UnaryTransform<ST, Dollars>>(
|
||||
/// Create from a computed source, applying a transform to produce Cents.
|
||||
pub(crate) fn from_cents_source<F: UnaryTransform<ST, Cents>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
source: &ComputedFromHeightLast<ST>,
|
||||
) -> Self {
|
||||
let usd = LazyFromHeightLast::from_computed::<F>(
|
||||
name,
|
||||
let cents = LazyFromHeightLast::from_computed::<F>(
|
||||
&format!("{name}_cents"),
|
||||
version,
|
||||
source.height.read_only_boxed_clone(),
|
||||
source,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, ST>(
|
||||
let usd = LazyFromHeightLast::from_lazy::<CentsUnsignedToDollars, ST>(
|
||||
&format!("{name}_usd"),
|
||||
version,
|
||||
¢s,
|
||||
);
|
||||
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
|
||||
&format!("{name}_sats"),
|
||||
version,
|
||||
&usd,
|
||||
);
|
||||
Self { usd, sats }
|
||||
Self { cents, usd, sats }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Version};
|
||||
use brk_types::{Cents, Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -31,22 +31,22 @@ impl ComputedFromHeightRatioExtended {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute ratio and all extended metrics from an externally-provided metric price.
|
||||
/// Compute ratio and all extended metrics from an externally-provided metric price (in cents).
|
||||
pub(crate) fn compute_rest(
|
||||
&mut self,
|
||||
blocks: &blocks::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
) -> Result<()> {
|
||||
let close_price = &prices.price.usd.height;
|
||||
let close_price = &prices.price.cents.height;
|
||||
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_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -21,12 +21,12 @@ pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
|
||||
pub ratio_pct5: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub ratio_pct2: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub ratio_pct1: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub ratio_pct99_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct98_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct95_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct5_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct2_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct1_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub ratio_pct99_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct98_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct95_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct5_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct2_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub ratio_pct1_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
|
||||
pub ratio_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_4y_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
@@ -68,7 +68,7 @@ impl ComputedFromHeightRatioExtension {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! import_usd {
|
||||
macro_rules! import_price {
|
||||
($suffix:expr) => {
|
||||
Price::forced_import(db, &format!("{name}_{}", $suffix), v, indexes)?
|
||||
};
|
||||
@@ -87,12 +87,12 @@ impl ComputedFromHeightRatioExtension {
|
||||
ratio_pct5: import!("ratio_pct5"),
|
||||
ratio_pct2: import!("ratio_pct2"),
|
||||
ratio_pct1: import!("ratio_pct1"),
|
||||
ratio_pct99_usd: import_usd!("ratio_pct99_usd"),
|
||||
ratio_pct98_usd: import_usd!("ratio_pct98_usd"),
|
||||
ratio_pct95_usd: import_usd!("ratio_pct95_usd"),
|
||||
ratio_pct5_usd: import_usd!("ratio_pct5_usd"),
|
||||
ratio_pct2_usd: import_usd!("ratio_pct2_usd"),
|
||||
ratio_pct1_usd: import_usd!("ratio_pct1_usd"),
|
||||
ratio_pct99_price: import_price!("ratio_pct99"),
|
||||
ratio_pct98_price: import_price!("ratio_pct98"),
|
||||
ratio_pct95_price: import_price!("ratio_pct95"),
|
||||
ratio_pct5_price: import_price!("ratio_pct5"),
|
||||
ratio_pct2_price: import_price!("ratio_pct2"),
|
||||
ratio_pct1_price: import_price!("ratio_pct1"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -219,20 +219,20 @@ impl ComputedFromHeightRatioExtension {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute USD ratio bands: usd_band = metric_price * ratio_percentile
|
||||
pub(crate) fn compute_usd_bands(
|
||||
/// Compute cents ratio bands: cents_band = metric_price_cents * ratio_percentile
|
||||
pub(crate) fn compute_cents_bands(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
use crate::internal::PriceTimesRatio;
|
||||
use crate::internal::PriceTimesRatioCents;
|
||||
|
||||
macro_rules! compute_band {
|
||||
($usd_field:ident, $band_source:expr) => {
|
||||
self.$usd_field
|
||||
.usd
|
||||
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
|
||||
.cents
|
||||
.compute_binary::<Cents, StoredF32, PriceTimesRatioCents>(
|
||||
starting_indexes.height,
|
||||
metric_price,
|
||||
$band_source,
|
||||
@@ -241,22 +241,22 @@ impl ComputedFromHeightRatioExtension {
|
||||
};
|
||||
}
|
||||
|
||||
compute_band!(ratio_pct99_usd, &self.ratio_pct99.height);
|
||||
compute_band!(ratio_pct98_usd, &self.ratio_pct98.height);
|
||||
compute_band!(ratio_pct95_usd, &self.ratio_pct95.height);
|
||||
compute_band!(ratio_pct5_usd, &self.ratio_pct5.height);
|
||||
compute_band!(ratio_pct2_usd, &self.ratio_pct2.height);
|
||||
compute_band!(ratio_pct1_usd, &self.ratio_pct1.height);
|
||||
compute_band!(ratio_pct99_price, &self.ratio_pct99.height);
|
||||
compute_band!(ratio_pct98_price, &self.ratio_pct98.height);
|
||||
compute_band!(ratio_pct95_price, &self.ratio_pct95.height);
|
||||
compute_band!(ratio_pct5_price, &self.ratio_pct5.height);
|
||||
compute_band!(ratio_pct2_price, &self.ratio_pct2.height);
|
||||
compute_band!(ratio_pct1_price, &self.ratio_pct1.height);
|
||||
|
||||
// Stddev USD bands
|
||||
// Stddev cents bands
|
||||
self.ratio_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_4y_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_2y_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_1y_sd
|
||||
.compute_usd_bands(starting_indexes, metric_price, exit)?;
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pub use price_extended::*;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{ComputeIndexes, indexes};
|
||||
@@ -36,12 +36,12 @@ impl ComputedFromHeightRatio {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute ratio = close_price / metric_price at height level
|
||||
/// Compute ratio = close_price / metric_price at height level (both in cents)
|
||||
pub(crate) fn compute_ratio(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
close_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
close_price: &impl ReadableVec<Height, Cents>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.ratio.height.compute_transform2(
|
||||
@@ -49,10 +49,10 @@ impl ComputedFromHeightRatio {
|
||||
close_price,
|
||||
metric_price,
|
||||
|(i, close, price, ..)| {
|
||||
if price == Dollars::ZERO {
|
||||
if price == Cents::ZERO {
|
||||
(i, StoredF32::from(1.0))
|
||||
} else {
|
||||
(i, StoredF32::from(close / price))
|
||||
(i, StoredF32::from(f64::from(close) / f64::from(price)))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Version};
|
||||
use brk_types::{Cents, Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct ComputedFromHeightPriceWithRatioExtended<M: StorageMode = Rw> {
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub inner: ComputedFromHeightRatioExtended<M>,
|
||||
pub price: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
}
|
||||
|
||||
impl ComputedFromHeightPriceWithRatioExtended {
|
||||
@@ -32,7 +32,7 @@ impl ComputedFromHeightPriceWithRatioExtended {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute price via closure, then compute ratio + extended metrics.
|
||||
/// Compute price via closure (in cents), then compute ratio + extended metrics.
|
||||
pub(crate) fn compute_all<F>(
|
||||
&mut self,
|
||||
blocks: &blocks::Vecs,
|
||||
@@ -42,15 +42,15 @@ impl ComputedFromHeightPriceWithRatioExtended {
|
||||
mut compute_price: F,
|
||||
) -> Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<PcoVec<Height, Dollars>>) -> Result<()>,
|
||||
F: FnMut(&mut EagerVec<PcoVec<Height, Cents>>) -> Result<()>,
|
||||
{
|
||||
compute_price(&mut self.price.usd.height)?;
|
||||
compute_price(&mut self.price.cents.height)?;
|
||||
self.inner.compute_rest(
|
||||
blocks,
|
||||
prices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.price.usd.height,
|
||||
&self.price.cents.height,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex,
|
||||
WritableVec,
|
||||
@@ -32,19 +32,19 @@ pub struct ComputedFromHeightStdDevExtended<M: StorageMode = Rw> {
|
||||
pub m2_5sd: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub m3sd: ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
pub _0sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p0_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p1sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p1_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p2sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p2_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub p3sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m0_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m1sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m1_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m2sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m2_5sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub m3sd_usd: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub _0sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p0_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p1sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p1_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p2sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p2_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub p3sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m0_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m1sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m1_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m2sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m2_5sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub m3sd_price: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
}
|
||||
|
||||
impl ComputedFromHeightStdDevExtended {
|
||||
@@ -68,7 +68,7 @@ impl ComputedFromHeightStdDevExtended {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! import_usd {
|
||||
macro_rules! import_price {
|
||||
($suffix:expr) => {
|
||||
Price::forced_import(db, &format!("{name}_{}", $suffix), version, indexes)?
|
||||
};
|
||||
@@ -89,19 +89,19 @@ impl ComputedFromHeightStdDevExtended {
|
||||
m2sd: import!("m2sd"),
|
||||
m2_5sd: import!("m2_5sd"),
|
||||
m3sd: import!("m3sd"),
|
||||
_0sd_usd: import_usd!("0sd_usd"),
|
||||
p0_5sd_usd: import_usd!("p0_5sd_usd"),
|
||||
p1sd_usd: import_usd!("p1sd_usd"),
|
||||
p1_5sd_usd: import_usd!("p1_5sd_usd"),
|
||||
p2sd_usd: import_usd!("p2sd_usd"),
|
||||
p2_5sd_usd: import_usd!("p2_5sd_usd"),
|
||||
p3sd_usd: import_usd!("p3sd_usd"),
|
||||
m0_5sd_usd: import_usd!("m0_5sd_usd"),
|
||||
m1sd_usd: import_usd!("m1sd_usd"),
|
||||
m1_5sd_usd: import_usd!("m1_5sd_usd"),
|
||||
m2sd_usd: import_usd!("m2sd_usd"),
|
||||
m2_5sd_usd: import_usd!("m2_5sd_usd"),
|
||||
m3sd_usd: import_usd!("m3sd_usd"),
|
||||
_0sd_price: import_price!("0sd"),
|
||||
p0_5sd_price: import_price!("p0_5sd"),
|
||||
p1sd_price: import_price!("p1sd"),
|
||||
p1_5sd_price: import_price!("p1_5sd"),
|
||||
p2sd_price: import_price!("p2sd"),
|
||||
p2_5sd_price: import_price!("p2_5sd"),
|
||||
p3sd_price: import_price!("p3sd"),
|
||||
m0_5sd_price: import_price!("m0_5sd"),
|
||||
m1sd_price: import_price!("m1sd"),
|
||||
m1_5sd_price: import_price!("m1_5sd"),
|
||||
m2sd_price: import_price!("m2sd"),
|
||||
m2_5sd_price: import_price!("m2_5sd"),
|
||||
m3sd_price: import_price!("m3sd"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -217,20 +217,20 @@ impl ComputedFromHeightStdDevExtended {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute USD price bands: usd_band = metric_price * band_ratio
|
||||
pub(crate) fn compute_usd_bands(
|
||||
/// Compute cents price bands: cents_band = metric_price_cents * band_ratio
|
||||
pub(crate) fn compute_cents_bands(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
metric_price: &impl ReadableVec<Height, Dollars>,
|
||||
metric_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
use crate::internal::PriceTimesRatio;
|
||||
use crate::internal::PriceTimesRatioCents;
|
||||
|
||||
macro_rules! compute_band {
|
||||
($usd_field:ident, $band_source:expr) => {
|
||||
self.$usd_field
|
||||
.usd
|
||||
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
|
||||
.cents
|
||||
.compute_binary::<Cents, StoredF32, PriceTimesRatioCents>(
|
||||
starting_indexes.height,
|
||||
metric_price,
|
||||
$band_source,
|
||||
@@ -239,19 +239,19 @@ impl ComputedFromHeightStdDevExtended {
|
||||
};
|
||||
}
|
||||
|
||||
compute_band!(_0sd_usd, &self.base.sma.height);
|
||||
compute_band!(p0_5sd_usd, &self.p0_5sd.height);
|
||||
compute_band!(p1sd_usd, &self.p1sd.height);
|
||||
compute_band!(p1_5sd_usd, &self.p1_5sd.height);
|
||||
compute_band!(p2sd_usd, &self.p2sd.height);
|
||||
compute_band!(p2_5sd_usd, &self.p2_5sd.height);
|
||||
compute_band!(p3sd_usd, &self.p3sd.height);
|
||||
compute_band!(m0_5sd_usd, &self.m0_5sd.height);
|
||||
compute_band!(m1sd_usd, &self.m1sd.height);
|
||||
compute_band!(m1_5sd_usd, &self.m1_5sd.height);
|
||||
compute_band!(m2sd_usd, &self.m2sd.height);
|
||||
compute_band!(m2_5sd_usd, &self.m2_5sd.height);
|
||||
compute_band!(m3sd_usd, &self.m3sd.height);
|
||||
compute_band!(_0sd_price, &self.base.sma.height);
|
||||
compute_band!(p0_5sd_price, &self.p0_5sd.height);
|
||||
compute_band!(p1sd_price, &self.p1sd.height);
|
||||
compute_band!(p1_5sd_price, &self.p1_5sd.height);
|
||||
compute_band!(p2sd_price, &self.p2sd.height);
|
||||
compute_band!(p2_5sd_price, &self.p2_5sd.height);
|
||||
compute_band!(p3sd_price, &self.p3sd.height);
|
||||
compute_band!(m0_5sd_price, &self.m0_5sd.height);
|
||||
compute_band!(m1sd_price, &self.m1sd.height);
|
||||
compute_band!(m1_5sd_price, &self.m1_5sd.height);
|
||||
compute_band!(m2sd_price, &self.m2sd.height);
|
||||
compute_band!(m2_5sd_price, &self.m2_5sd.height);
|
||||
compute_band!(m3sd_price, &self.m3sd.height);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,22 +2,25 @@
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, SatsSigned, Version};
|
||||
use brk_types::{Bitcoin, Cents, CentsSigned, Dollars, Height, Sats, SatsSigned, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsSignedToBitcoin},
|
||||
internal::{
|
||||
CentsSignedToDollars, ComputedFromHeightLast, LazyFromHeightLast, SatsSignedToBitcoin,
|
||||
},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
/// Change values indexed by height - sats (stored), btc (lazy), usd (stored).
|
||||
/// Change values indexed by height - sats (stored), btc (lazy), cents (stored), usd (lazy).
|
||||
#[derive(Traversable)]
|
||||
pub struct ValueFromHeightChange<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<SatsSigned, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, SatsSigned>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
pub cents: ComputedFromHeightLast<CentsSigned, M>,
|
||||
pub usd: LazyFromHeightLast<Dollars, CentsSigned>,
|
||||
}
|
||||
|
||||
impl ValueFromHeightChange {
|
||||
@@ -38,31 +41,38 @@ impl ValueFromHeightChange {
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd = ComputedFromHeightLast::forced_import(
|
||||
let cents = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_usd"),
|
||||
&format!("{name}_cents"),
|
||||
v,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
let usd = LazyFromHeightLast::from_computed::<CentsSignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
);
|
||||
|
||||
Ok(Self { sats, btc, cents, usd })
|
||||
}
|
||||
|
||||
/// Compute rolling change for both sats and dollars in one call.
|
||||
/// Compute rolling change for both sats and cents in one call.
|
||||
pub(crate) fn compute_rolling(
|
||||
&mut self,
|
||||
starting_height: Height,
|
||||
window_starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
dollars_source: &(impl ReadableVec<Height, Dollars> + Sync),
|
||||
cents_source: &(impl ReadableVec<Height, Cents> + Sync),
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sats
|
||||
.height
|
||||
.compute_rolling_change(starting_height, window_starts, sats_source, exit)?;
|
||||
self.usd
|
||||
self.cents
|
||||
.height
|
||||
.compute_rolling_change(starting_height, window_starts, dollars_source, exit)?;
|
||||
.compute_rolling_change(starting_height, window_starts, cents_source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, SatsToDollars},
|
||||
internal::{ByUnit, SatsToCents},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -44,18 +44,18 @@ impl ValueFromHeightCumulative {
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
.cents
|
||||
.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, RollingFullByUnit, SatsToDollars, WindowStarts},
|
||||
internal::{ByUnit, RollingFullByUnit, SatsToCents, WindowStarts},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -51,25 +51,25 @@ impl ValueFromHeightFull {
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
self.rolling.compute(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
&self.base.usd.height,
|
||||
&self.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes, prices,
|
||||
internal::{ByUnit, SatsToDollars},
|
||||
internal::{ByUnit, SatsToCents},
|
||||
};
|
||||
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
@@ -38,10 +38,10 @@ impl ValueFromHeightLast {
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.base.cents.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -52,7 +52,7 @@ impl ValueFromHeightLast {
|
||||
max_from: Height,
|
||||
window_starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base
|
||||
@@ -60,9 +60,9 @@ impl ValueFromHeightLast {
|
||||
.height
|
||||
.compute_rolling_sum(max_from, window_starts, sats_source, exit)?;
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_rolling_sum(max_from, window_starts, usd_source, exit)?;
|
||||
.compute_rolling_sum(max_from, window_starts, cents_source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ impl ValueFromHeightLast {
|
||||
starting_height: Height,
|
||||
window_starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
dollars_source: &(impl ReadableVec<Height, Dollars> + Sync),
|
||||
cents_source: &(impl ReadableVec<Height, Cents> + Sync),
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base
|
||||
@@ -79,9 +79,9 @@ impl ValueFromHeightLast {
|
||||
.height
|
||||
.compute_rolling_ema(starting_height, window_starts, sats_source, exit)?;
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_rolling_ema(starting_height, window_starts, dollars_source, exit)?;
|
||||
.compute_rolling_ema(starting_height, window_starts, cents_source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ impl ValueFromHeightLastRolling {
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute sats height via closure, then USD from price, then rolling windows.
|
||||
/// Compute sats height via closure, then cents from price, then rolling windows.
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
@@ -51,12 +51,12 @@ impl ValueFromHeightLastRolling {
|
||||
compute_sats: impl FnOnce(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
compute_sats(&mut self.value.sats)?;
|
||||
self.value.compute_usd(prices, max_from, exit)?;
|
||||
self.value.compute_cents(prices, max_from, exit)?;
|
||||
self.rolling.compute_rolling_sum(
|
||||
max_from,
|
||||
windows,
|
||||
&self.value.sats,
|
||||
&self.value.usd,
|
||||
&self.value.cents,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, RollingSumByUnit, SatsToDollars, WindowStarts},
|
||||
internal::{ByUnit, RollingSumByUnit, SatsToCents, WindowStarts},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -50,25 +50,25 @@ impl ValueFromHeightSumCumulative {
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.cents
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
self.sum.compute_rolling_sum(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
&self.base.usd.height,
|
||||
&self.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//! Value type with height-level data only (no period-derived views).
|
||||
//!
|
||||
//! Stores sats and USD per height, plus a lazy btc transform.
|
||||
//! Stores sats and cents per height, plus lazy btc and usd transforms.
|
||||
//! Use when period views are unnecessary (e.g., rolling windows provide windowed data).
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Height, Sats, Version};
|
||||
use vecdb::{
|
||||
Database, EagerVec, Exit, ImportableVec, LazyVecFrom1, PcoVec, ReadableCloneableVec, Rw,
|
||||
StorageMode,
|
||||
};
|
||||
|
||||
use crate::{internal::{SatsToBitcoin, SatsToDollars}, prices};
|
||||
use crate::{internal::{CentsUnsignedToDollars, SatsToBitcoin, SatsToCents}, prices};
|
||||
|
||||
const VERSION: Version = Version::TWO; // Match ValueFromHeightLast versioning
|
||||
|
||||
@@ -19,7 +19,8 @@ const VERSION: Version = Version::TWO; // Match ValueFromHeightLast versioning
|
||||
pub struct ValueFromHeight<M: StorageMode = Rw> {
|
||||
pub sats: M::Stored<EagerVec<PcoVec<Height, Sats>>>,
|
||||
pub btc: LazyVecFrom1<Height, Bitcoin, Height, Sats>,
|
||||
pub usd: M::Stored<EagerVec<PcoVec<Height, Dollars>>>,
|
||||
pub cents: M::Stored<EagerVec<PcoVec<Height, Cents>>>,
|
||||
pub usd: LazyVecFrom1<Height, Dollars, Height, Cents>,
|
||||
}
|
||||
|
||||
impl ValueFromHeight {
|
||||
@@ -36,22 +37,28 @@ impl ValueFromHeight {
|
||||
v,
|
||||
sats.read_only_boxed_clone(),
|
||||
);
|
||||
let usd = EagerVec::forced_import(db, &format!("{name}_usd"), v)?;
|
||||
let cents: EagerVec<PcoVec<Height, Cents>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_cents"), v)?;
|
||||
let usd = LazyVecFrom1::transformed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
cents.read_only_boxed_clone(),
|
||||
);
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self { sats, btc, cents, usd })
|
||||
}
|
||||
|
||||
/// Eagerly compute USD height values: sats[h] * price[h].
|
||||
pub(crate) fn compute_usd(
|
||||
/// Eagerly compute cents height values: sats[h] * price_cents[h] / 1e8.
|
||||
pub(crate) fn compute_cents(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.cents.compute_binary::<Sats, Cents, SatsToCents>(
|
||||
max_from,
|
||||
&self.sats,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Lazy value type for Last pattern across all height-derived indexes.
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Sats, Version};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
use crate::internal::{LazyHeightDerivedLast, ValueFromHeightLast};
|
||||
@@ -40,7 +40,7 @@ impl LazyValueHeightDerivedLast {
|
||||
&source.sats.rest,
|
||||
);
|
||||
|
||||
let usd = LazyHeightDerivedLast::from_derived_computed::<DollarsTransform>(
|
||||
let usd = LazyHeightDerivedLast::from_lazy::<DollarsTransform, Cents>(
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
&source.usd.rest,
|
||||
|
||||
@@ -10,7 +10,7 @@ use brk_types::{Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use brk_types::{Dollars, Sats};
|
||||
use brk_types::{Cents, Sats};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
@@ -69,11 +69,11 @@ impl ValueFromHeightLastWindows {
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
cents_source: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.compute_rolling_sum(max_from, starts, sats_source, usd_source, exit)?;
|
||||
w.compute_rolling_sum(max_from, starts, sats_source, cents_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
13
crates/brk_computer/src/internal/transform/cents_plus.rs
Normal file
13
crates/brk_computer/src/internal/transform/cents_plus.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use brk_types::Cents;
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> Cents addition
|
||||
/// Used for computing total = profit + loss
|
||||
pub struct CentsPlus;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, Cents> for CentsPlus {
|
||||
#[inline(always)]
|
||||
fn apply(lhs: Cents, rhs: Cents) -> Cents {
|
||||
lhs + rhs
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use brk_types::{CentsSigned, Dollars};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// CentsSigned -> Dollars (convert signed cents to dollars for display)
|
||||
pub struct CentsSignedToDollars;
|
||||
|
||||
impl UnaryTransform<CentsSigned, Dollars> for CentsSignedToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: CentsSigned) -> Dollars {
|
||||
cents.into()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use brk_types::Cents;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Cents * (V/10) -> Cents (e.g., V=8 -> * 0.8, V=24 -> * 2.4)
|
||||
pub struct CentsTimesTenths<const V: u16>;
|
||||
|
||||
impl<const V: u16> UnaryTransform<Cents, Cents> for CentsTimesTenths<V> {
|
||||
#[inline(always)]
|
||||
fn apply(c: Cents) -> Cents {
|
||||
// Use u128 to avoid overflow: c * V / 10
|
||||
Cents::from(c.as_u128() * V as u128 / 10)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use brk_types::Dollars;
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Dollars, Dollars) -> Dollars addition
|
||||
/// Used for computing total = profit + loss
|
||||
pub struct DollarsPlus;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, Dollars> for DollarsPlus {
|
||||
#[inline(always)]
|
||||
fn apply(lhs: Dollars, rhs: Dollars) -> Dollars {
|
||||
lhs + rhs
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::Dollars;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Dollars * (V/10) -> Dollars (e.g., V=8 -> * 0.8, V=24 -> * 2.4)
|
||||
pub struct DollarsTimesTenths<const V: u16>;
|
||||
|
||||
impl<const V: u16> UnaryTransform<Dollars, Dollars> for DollarsTimesTenths<V> {
|
||||
#[inline(always)]
|
||||
fn apply(d: Dollars) -> Dollars {
|
||||
d * (V as f64 / 10.0)
|
||||
}
|
||||
}
|
||||
@@ -1,68 +1,80 @@
|
||||
mod block_count_target;
|
||||
mod cents_plus;
|
||||
mod cents_signed_to_dollars;
|
||||
mod cents_times_tenths;
|
||||
mod cents_to_dollars;
|
||||
mod cents_to_sats;
|
||||
mod dollar_halve;
|
||||
mod dollar_identity;
|
||||
mod dollar_plus;
|
||||
mod dollar_times_tenths;
|
||||
mod dollars_to_sats_fract;
|
||||
mod f32_identity;
|
||||
mod neg_cents_to_dollars;
|
||||
mod ohlc_cents_to_dollars;
|
||||
mod ohlc_cents_to_sats;
|
||||
mod percentage_cents_f32;
|
||||
mod percentage_cents_signed_dollars_f32;
|
||||
mod percentage_cents_signed_f32;
|
||||
mod percentage_diff_close_cents;
|
||||
mod percentage_diff_close_dollars;
|
||||
mod percentage_dollars_f32;
|
||||
mod percentage_dollars_f32_neg;
|
||||
mod percentage_sats_f64;
|
||||
mod percentage_u32_f32;
|
||||
mod price_times_ratio;
|
||||
mod price_times_ratio_cents;
|
||||
mod ratio32;
|
||||
mod ratio64;
|
||||
mod ratio_cents64;
|
||||
mod ratio_u64_f32;
|
||||
mod return_f32_tenths;
|
||||
mod return_i8;
|
||||
mod return_u16;
|
||||
mod sats_to_cents;
|
||||
|
||||
mod sat_halve;
|
||||
mod sat_halve_to_bitcoin;
|
||||
mod sat_identity;
|
||||
mod sat_mask;
|
||||
mod sat_to_bitcoin;
|
||||
mod sats_to_dollars;
|
||||
mod u16_to_years;
|
||||
mod volatility_sqrt30;
|
||||
mod volatility_sqrt365;
|
||||
mod volatility_sqrt7;
|
||||
|
||||
pub use block_count_target::*;
|
||||
pub use cents_plus::*;
|
||||
pub use cents_signed_to_dollars::*;
|
||||
pub use cents_times_tenths::*;
|
||||
pub use cents_to_dollars::*;
|
||||
pub use cents_to_sats::*;
|
||||
pub use neg_cents_to_dollars::*;
|
||||
pub use ohlc_cents_to_dollars::*;
|
||||
pub use ohlc_cents_to_sats::*;
|
||||
pub use percentage_cents_f32::*;
|
||||
pub use percentage_cents_signed_dollars_f32::*;
|
||||
pub use percentage_cents_signed_f32::*;
|
||||
|
||||
pub use dollar_halve::*;
|
||||
pub use dollar_identity::*;
|
||||
pub use dollar_plus::*;
|
||||
pub use dollar_times_tenths::*;
|
||||
pub use dollars_to_sats_fract::*;
|
||||
pub use f32_identity::*;
|
||||
pub use percentage_diff_close_cents::*;
|
||||
pub use percentage_diff_close_dollars::*;
|
||||
pub use percentage_dollars_f32::*;
|
||||
pub use percentage_dollars_f32_neg::*;
|
||||
pub use percentage_sats_f64::*;
|
||||
pub use percentage_u32_f32::*;
|
||||
pub use price_times_ratio::*;
|
||||
pub use price_times_ratio_cents::*;
|
||||
pub use ratio32::*;
|
||||
pub use ratio64::*;
|
||||
pub use ratio_cents64::*;
|
||||
pub use ratio_u64_f32::*;
|
||||
pub use return_f32_tenths::*;
|
||||
pub use return_i8::*;
|
||||
pub use return_u16::*;
|
||||
pub use sats_to_cents::*;
|
||||
pub use sat_halve::*;
|
||||
pub use sat_halve_to_bitcoin::*;
|
||||
pub use sat_identity::*;
|
||||
pub use sat_mask::*;
|
||||
pub use sat_to_bitcoin::*;
|
||||
pub use sats_to_dollars::*;
|
||||
pub use u16_to_years::*;
|
||||
pub use volatility_sqrt7::*;
|
||||
pub use volatility_sqrt30::*;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
use brk_types::{Cents, Dollars};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Cents -> -Dollars (negate after converting to dollars)
|
||||
/// Avoids lazy-from-lazy by combining both transforms.
|
||||
pub struct NegCentsUnsignedToDollars;
|
||||
|
||||
impl UnaryTransform<Cents, Dollars> for NegCentsUnsignedToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: Cents) -> Dollars {
|
||||
-Dollars::from(cents)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> StoredF32 percentage (a/b × 100)
|
||||
pub struct PercentageCentsF32;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, StoredF32> for PercentageCentsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> StoredF32 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / denominator.inner() as f64 * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{CentsSigned, Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (CentsSigned, Dollars) -> StoredF32 percentage (a/b × 100)
|
||||
/// For cross-type percentage when numerator is CentsSigned and denominator is Dollars.
|
||||
pub struct PercentageCentsSignedDollarsF32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Dollars, StoredF32> for PercentageCentsSignedDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Dollars) -> StoredF32 {
|
||||
if denominator == Dollars::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / *denominator * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{Cents, CentsSigned, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (CentsSigned, Cents) -> StoredF32 percentage (a/b × 100)
|
||||
/// For cross-type percentage when numerator is signed.
|
||||
pub struct PercentageCentsSignedCentsF32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Cents, StoredF32> for PercentageCentsSignedCentsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Cents) -> StoredF32 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / denominator.inner() as f64 * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> StoredF32 percentage difference ((a/b - 1) * 100)
|
||||
pub struct PercentageDiffCents;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, StoredF32> for PercentageDiffCents {
|
||||
#[inline(always)]
|
||||
fn apply(close: Cents, base: Cents) -> StoredF32 {
|
||||
let base_f64 = f64::from(base);
|
||||
if base_f64 == 0.0 {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from((f64::from(close) / base_f64 - 1.0) * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// Dollars * StoredF32 -> Dollars (price × ratio)
|
||||
pub struct PriceTimesRatio;
|
||||
|
||||
impl BinaryTransform<Dollars, StoredF32, Dollars> for PriceTimesRatio {
|
||||
#[inline(always)]
|
||||
fn apply(price: Dollars, ratio: StoredF32) -> Dollars {
|
||||
price * ratio
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
pub struct PriceTimesRatioCents;
|
||||
|
||||
impl BinaryTransform<Cents, StoredF32, Cents> for PriceTimesRatioCents {
|
||||
#[inline(always)]
|
||||
fn apply(price: Cents, ratio: StoredF32) -> Cents {
|
||||
Cents::from(f64::from(price) * f64::from(ratio))
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use brk_types::{Dollars, StoredF64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF64 ratio
|
||||
/// Used for computing ratios like SOPR where f64 precision is needed.
|
||||
pub struct Ratio64;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, StoredF64> for Ratio64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF64 {
|
||||
numerator / denominator
|
||||
}
|
||||
}
|
||||
17
crates/brk_computer/src/internal/transform/ratio_cents64.rs
Normal file
17
crates/brk_computer/src/internal/transform/ratio_cents64.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use brk_types::{Cents, StoredF64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> StoredF64 ratio
|
||||
/// Used for computing ratios like SOPR where f64 precision is needed.
|
||||
pub struct RatioCents64;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, StoredF64> for RatioCents64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> StoredF64 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF64::from(1.0)
|
||||
} else {
|
||||
StoredF64::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
13
crates/brk_computer/src/internal/transform/sats_to_cents.rs
Normal file
13
crates/brk_computer/src/internal/transform/sats_to_cents.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use brk_types::{Cents, Sats};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// Sats × Cents → Cents (sats × price_cents / 1e8)
|
||||
/// Uses u128 intermediate to avoid overflow.
|
||||
pub struct SatsToCents;
|
||||
|
||||
impl BinaryTransform<Sats, Cents, Cents> for SatsToCents {
|
||||
#[inline(always)]
|
||||
fn apply(sats: Sats, price_cents: Cents) -> Cents {
|
||||
Cents::from(sats.as_u128() * price_cents.as_u128() / Sats::ONE_BTC_U128)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::{Dollars, Sats};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// Sats × Dollars → Dollars (price * sats)
|
||||
pub struct SatsToDollars;
|
||||
|
||||
impl BinaryTransform<Sats, Dollars, Dollars> for SatsToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(sats: Sats, price: Dollars) -> Dollars {
|
||||
price * sats
|
||||
}
|
||||
}
|
||||
@@ -12,17 +12,17 @@ impl Vecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.price_ath.usd.height.compute_all_time_high(
|
||||
self.price_ath.cents.height.compute_all_time_high(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let mut prev = None;
|
||||
self.days_since_price_ath.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.price_ath.usd.height,
|
||||
&prices.price.usd.height,
|
||||
&self.price_ath.cents.height,
|
||||
&prices.price.cents.height,
|
||||
|(i, ath, price, slf)| {
|
||||
if prev.is_none() {
|
||||
let i = i.to_usize();
|
||||
@@ -32,7 +32,7 @@ impl Vecs {
|
||||
StoredU16::default()
|
||||
});
|
||||
}
|
||||
let days = if *price == *ath {
|
||||
let days = if price == ath {
|
||||
StoredU16::default()
|
||||
} else {
|
||||
prev.unwrap() + StoredU16::new(1)
|
||||
@@ -65,8 +65,8 @@ impl Vecs {
|
||||
|
||||
self.price_drawdown.height.compute_drawdown(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&self.price_ath.usd.height,
|
||||
&prices.price.cents.height,
|
||||
&self.price_ath.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, StoredF32, StoredU16};
|
||||
use brk_types::{Cents, StoredF32, StoredU16};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeightLast, LazyHeightDerivedLast, Price};
|
||||
@@ -7,7 +7,7 @@ use crate::internal::{ComputedFromHeightLast, LazyHeightDerivedLast, Price};
|
||||
/// All-time high related metrics
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_ath: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_ath: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_drawdown: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub days_since_price_ath: ComputedFromHeightLast<StoredU16, M>,
|
||||
pub years_since_price_ath: LazyHeightDerivedLast<StoredF32, StoredU16>,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Bitcoin, Day1, Date, Dollars, Height, Sats, StoredF32, StoredU32};
|
||||
use brk_types::{Bitcoin, Cents, Day1, Date, Dollars, Height, Sats, StoredF32, StoredU32};
|
||||
use vecdb::{AnyVec, EagerVec, Exit, ReadableOptionVec, ReadableVec, PcoVec, PcoVecValue, VecIndex};
|
||||
|
||||
use super::{ByDcaClass, ByDcaPeriod, Vecs};
|
||||
use crate::{
|
||||
ComputeIndexes, blocks, indexes,
|
||||
internal::{ComputedFromHeightLast, PercentageDiffDollars},
|
||||
internal::{ComputedFromHeightLast, PercentageDiffCents},
|
||||
market::lookback,
|
||||
prices,
|
||||
};
|
||||
@@ -69,7 +69,7 @@ impl Vecs {
|
||||
{
|
||||
let days = days as usize;
|
||||
let stack_data = stack.sats.height.collect_range_at(sh, stack.sats.height.len());
|
||||
average_price.usd.height.compute_transform(
|
||||
average_price.cents.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, di, _)| {
|
||||
@@ -79,9 +79,9 @@ impl Vecs {
|
||||
let num_days = days
|
||||
.min(di_usize + 1)
|
||||
.min(di_usize + 1 - first_price_di);
|
||||
DCA_AMOUNT * num_days / Bitcoin::from(stack_sats)
|
||||
Cents::from(DCA_AMOUNT * num_days / Bitcoin::from(stack_sats))
|
||||
} else {
|
||||
Dollars::NAN
|
||||
Cents::ZERO
|
||||
};
|
||||
(h, avg)
|
||||
},
|
||||
@@ -95,10 +95,10 @@ impl Vecs {
|
||||
.iter_mut()
|
||||
.zip(self.period_average_price.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Dollars, Dollars, PercentageDiffDollars>(
|
||||
returns.compute_binary::<Cents, Cents, PercentageDiffCents>(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&average_price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
&average_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
@@ -139,16 +139,16 @@ impl Vecs {
|
||||
self.period_lump_sum_stack.zip_mut_with_days(&lookback_dca)
|
||||
{
|
||||
let total_invested = DCA_AMOUNT * days as usize;
|
||||
let lookback_data = lookback_price.usd.height.collect_range_at(sh, lookback_price.usd.height.len());
|
||||
let lookback_data = lookback_price.cents.height.collect_range_at(sh, lookback_price.cents.height.len());
|
||||
stack.sats.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, _di, _)| {
|
||||
let lp = lookback_data[h.to_usize() - sh];
|
||||
let sats = if lp == Dollars::ZERO {
|
||||
let sats = if lp == Cents::ZERO {
|
||||
Sats::ZERO
|
||||
} else {
|
||||
Sats::from(Bitcoin::from(total_invested / lp))
|
||||
Sats::from(Bitcoin::from(total_invested / Dollars::from(lp)))
|
||||
};
|
||||
(h, sats)
|
||||
},
|
||||
@@ -163,10 +163,10 @@ impl Vecs {
|
||||
.iter_mut()
|
||||
.zip(lookback_dca2.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Dollars, Dollars, PercentageDiffDollars>(
|
||||
returns.compute_binary::<Cents, Cents, PercentageDiffCents>(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&lookback_price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
&lookback_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
@@ -242,17 +242,17 @@ impl Vecs {
|
||||
{
|
||||
let from_usize = from.to_usize();
|
||||
let stack_data = stack.sats.height.collect_range_at(sh, stack.sats.height.len());
|
||||
average_price.usd.height.compute_transform(
|
||||
average_price.cents.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, di, _)| {
|
||||
let di_usize = di.to_usize();
|
||||
if di_usize < from_usize {
|
||||
return (h, Dollars::NAN);
|
||||
return (h, Cents::ZERO);
|
||||
}
|
||||
let stack_sats = stack_data[h.to_usize() - sh];
|
||||
let num_days = di_usize + 1 - from_usize;
|
||||
let avg = DCA_AMOUNT * num_days / Bitcoin::from(stack_sats);
|
||||
let avg = Cents::from(DCA_AMOUNT * num_days / Bitcoin::from(stack_sats));
|
||||
(h, avg)
|
||||
},
|
||||
exit,
|
||||
@@ -266,10 +266,10 @@ impl Vecs {
|
||||
.zip(self.class_average_price.iter())
|
||||
{
|
||||
|
||||
returns.compute_binary::<Dollars, Dollars, PercentageDiffDollars>(
|
||||
returns.compute_binary::<Cents, Cents, PercentageDiffCents>(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&average_price.usd.height,
|
||||
&prices.price.cents.height,
|
||||
&average_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, StoredF32, StoredU32};
|
||||
use brk_types::{Cents, Height, Sats, StoredF32, StoredU32};
|
||||
use vecdb::{EagerVec, PcoVec, Rw, StorageMode};
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod};
|
||||
@@ -16,7 +16,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
// DCA by period - KISS types
|
||||
pub period_stack: ByDcaPeriod<ValueFromHeightLast<M>>,
|
||||
pub period_average_price: ByDcaPeriod<Price<ComputedFromHeightLast<Dollars, M>>>,
|
||||
pub period_average_price: ByDcaPeriod<Price<ComputedFromHeightLast<Cents, M>>>,
|
||||
pub period_returns: ByDcaPeriod<ComputedFromHeightLast<StoredF32, M>>,
|
||||
pub period_cagr: ByDcaCagr<ComputedFromHeightLast<StoredF32, M>>,
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
// DCA by year class - KISS types
|
||||
pub class_stack: ByDcaClass<ValueFromHeightLast<M>>,
|
||||
pub class_average_price: ByDcaClass<Price<ComputedFromHeightLast<Dollars, M>>>,
|
||||
pub class_average_price: ByDcaClass<Price<ComputedFromHeightLast<Cents, M>>>,
|
||||
pub class_returns: ByDcaClass<ComputedFromHeightLast<StoredF32, M>>,
|
||||
|
||||
// DCA by year class - profitability
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Dollars;
|
||||
use brk_types::Cents;
|
||||
use vecdb::{Exit, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
@@ -13,11 +13,11 @@ impl Vecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let close_data: Vec<Dollars> = prices.price.usd.height.collect();
|
||||
let close_data: Vec<Cents> = prices.price.cents.height.collect();
|
||||
|
||||
for (price_ago, days) in self.price_ago.iter_mut_with_days() {
|
||||
let window_starts = blocks.count.start_vec(days as usize);
|
||||
price_ago.usd.height.compute_transform(
|
||||
price_ago.cents.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
window_starts,
|
||||
|(h, start_h, _)| {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::Dollars;
|
||||
use brk_types::Cents;
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use super::ByLookbackPeriod;
|
||||
@@ -9,5 +9,5 @@ use crate::internal::{ComputedFromHeightLast, Price};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub price_ago: ByLookbackPeriod<Price<ComputedFromHeightLast<Dollars, M>>>,
|
||||
pub price_ago: ByLookbackPeriod<Price<ComputedFromHeightLast<Cents, M>>>,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Dollars;
|
||||
use brk_types::Cents;
|
||||
use vecdb::{Exit, ReadableOptionVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let close = &prices.price.usd.height;
|
||||
let close = &prices.price.cents.height;
|
||||
|
||||
for (sma, period) in [
|
||||
(&mut self.price_1w_sma, 7),
|
||||
@@ -42,7 +42,7 @@ impl Vecs {
|
||||
}
|
||||
|
||||
let h2d = &indexes.height.day1;
|
||||
let closes: Vec<Dollars> = prices.split.close.usd.day1.collect_or_default();
|
||||
let closes: Vec<Cents> = prices.split.close.cents.day1.collect_or_default();
|
||||
|
||||
for (ema, period) in [
|
||||
(&mut self.price_1w_ema, 7),
|
||||
@@ -71,7 +71,7 @@ impl Vecs {
|
||||
v.compute_transform(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, date, ..)| (h, Dollars::from(date_ema[date.to_usize()])),
|
||||
|(h, date, ..)| (h, Cents::from(date_ema[date.to_usize()])),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -82,7 +82,7 @@ impl Vecs {
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_date_ema(closes: &[Dollars], k: f64) -> Vec<f64> {
|
||||
fn compute_date_ema(closes: &[Cents], k: f64) -> Vec<f64> {
|
||||
let mut date_ema: Vec<f64> = Vec::with_capacity(closes.len());
|
||||
let mut ema_val = 0.0f64;
|
||||
for (d, close) in closes.iter().enumerate() {
|
||||
|
||||
@@ -5,7 +5,7 @@ use vecdb::Database;
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightPriceWithRatioExtended, DollarsTimesTenths, Price},
|
||||
internal::{CentsTimesTenths, ComputedFromHeightPriceWithRatioExtended, Price},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -28,20 +28,20 @@ impl Vecs {
|
||||
let price_200d_sma = import!("price_200d_sma");
|
||||
let price_350d_sma = import!("price_350d_sma");
|
||||
|
||||
let price_200d_sma_source = &price_200d_sma.price.usd;
|
||||
let price_200d_sma_x2_4 = Price::from_computed::<DollarsTimesTenths<24>>(
|
||||
let price_200d_sma_source = &price_200d_sma.price.cents;
|
||||
let price_200d_sma_x2_4 = Price::from_cents_source::<CentsTimesTenths<24>>(
|
||||
"price_200d_sma_x2_4",
|
||||
version,
|
||||
price_200d_sma_source,
|
||||
);
|
||||
let price_200d_sma_x0_8 = Price::from_computed::<DollarsTimesTenths<8>>(
|
||||
let price_200d_sma_x0_8 = Price::from_cents_source::<CentsTimesTenths<8>>(
|
||||
"price_200d_sma_x0_8",
|
||||
version,
|
||||
price_200d_sma_source,
|
||||
);
|
||||
|
||||
let price_350d_sma_source = &price_350d_sma.price.usd;
|
||||
let price_350d_sma_x2 = Price::from_computed::<DollarsTimesTenths<20>>(
|
||||
let price_350d_sma_source = &price_350d_sma.price.cents;
|
||||
let price_350d_sma_x2 = Price::from_cents_source::<CentsTimesTenths<20>>(
|
||||
"price_350d_sma_x2",
|
||||
version,
|
||||
price_350d_sma_source,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::Dollars;
|
||||
use brk_types::Cents;
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeightPriceWithRatioExtended, LazyFromHeightLast, Price};
|
||||
@@ -41,7 +41,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_200w_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_4y_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
|
||||
pub price_200d_sma_x2_4: Price<LazyFromHeightLast<Dollars, Dollars>>,
|
||||
pub price_200d_sma_x0_8: Price<LazyFromHeightLast<Dollars, Dollars>>,
|
||||
pub price_350d_sma_x2: Price<LazyFromHeightLast<Dollars, Dollars>>,
|
||||
pub price_200d_sma_x2_4: Price<LazyFromHeightLast<Cents, Cents>>,
|
||||
pub price_200d_sma_x0_8: Price<LazyFromHeightLast<Cents, Cents>>,
|
||||
pub price_350d_sma_x2: Price<LazyFromHeightLast<Cents, Cents>>,
|
||||
}
|
||||
|
||||
@@ -16,58 +16,58 @@ impl Vecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let price = &prices.price.usd.height;
|
||||
let price = &prices.price.cents.height;
|
||||
|
||||
self.price_1w_min.usd.height.compute_rolling_min_from_starts(
|
||||
self.price_1w_min.cents.height.compute_rolling_min_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_1w_max.usd.height.compute_rolling_max_from_starts(
|
||||
self.price_1w_max.cents.height.compute_rolling_max_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_2w_min.usd.height.compute_rolling_min_from_starts(
|
||||
self.price_2w_min.cents.height.compute_rolling_min_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_2w_max.usd.height.compute_rolling_max_from_starts(
|
||||
self.price_2w_max.cents.height.compute_rolling_max_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_1m_min.usd.height.compute_rolling_min_from_starts(
|
||||
self.price_1m_min.cents.height.compute_rolling_min_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_1m_max.usd.height.compute_rolling_max_from_starts(
|
||||
self.price_1m_max.cents.height.compute_rolling_max_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_1y_min.usd.height.compute_rolling_min_from_starts(
|
||||
self.price_1y_min.cents.height.compute_rolling_min_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1y_ago,
|
||||
price,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_1y_max.usd.height.compute_rolling_max_from_starts(
|
||||
self.price_1y_max.cents.height.compute_rolling_max_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1y_ago,
|
||||
price,
|
||||
@@ -88,7 +88,8 @@ impl Vecs {
|
||||
}
|
||||
});
|
||||
prev_price = Some(current);
|
||||
let tr = (*current - *prev).abs();
|
||||
let (c, p) = (f64::from(current), f64::from(prev));
|
||||
let tr = (c - p).abs();
|
||||
(h, StoredF32::from(tr))
|
||||
},
|
||||
exit,
|
||||
@@ -105,11 +106,11 @@ impl Vecs {
|
||||
self.price_2w_choppiness_index.height.compute_transform4(
|
||||
starting_indexes.height,
|
||||
&self.price_true_range_2w_sum.height,
|
||||
&self.price_2w_max.usd.height,
|
||||
&self.price_2w_min.usd.height,
|
||||
&self.price_2w_max.cents.height,
|
||||
&self.price_2w_min.cents.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
|(h, tr_sum, max, min, window_start, ..)| {
|
||||
let range = *max - *min;
|
||||
let range = f64::from(max) - f64::from(min);
|
||||
let n = (h.to_usize() - window_start.to_usize() + 1) as f32;
|
||||
let ci = if range > 0.0 && n > 1.0 {
|
||||
StoredF32::from(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeightLast, Price};
|
||||
@@ -7,14 +7,14 @@ use crate::internal::{ComputedFromHeightLast, Price};
|
||||
/// Price range and choppiness metrics
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_1w_min: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_1w_max: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_2w_min: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_2w_max: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_1m_min: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_1m_max: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_1y_min: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_1y_max: Price<ComputedFromHeightLast<Dollars, M>>,
|
||||
pub price_1w_min: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_1w_max: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_2w_min: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_2w_max: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_1m_min: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_1m_max: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_1y_min: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_1y_max: Price<ComputedFromHeightLast<Cents, M>>,
|
||||
pub price_true_range: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub price_true_range_2w_sum: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub price_2w_choppiness_index: ComputedFromHeightLast<StoredF32, M>,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::Version;
|
||||
use brk_types::{Cents, Version};
|
||||
use vecdb::{Database, ReadableCloneableVec, PAGE_SIZE};
|
||||
|
||||
use super::Vecs;
|
||||
@@ -49,10 +49,9 @@ impl Vecs {
|
||||
super::velocity::Vecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
// Market cap - lazy identity from distribution supply in USD
|
||||
let market_cap = LazyFromHeightLast::from_computed::<DollarsIdentity>(
|
||||
let market_cap = LazyFromHeightLast::from_lazy::<DollarsIdentity, Cents>(
|
||||
"market_cap",
|
||||
version,
|
||||
supply_metrics.total.usd.height.read_only_boxed_clone(),
|
||||
&supply_metrics.total.usd,
|
||||
);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{Formattable, Pco};
|
||||
use vecdb::{CheckedSub, Formattable, Pco};
|
||||
|
||||
use super::{CentsSats, Dollars, Sats};
|
||||
|
||||
@@ -258,6 +258,12 @@ impl Div<usize> for Cents {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Cents {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Cents {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut buf = itoa::Buffer::new();
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{Formattable, Pco};
|
||||
use vecdb::{CheckedSub, Formattable, Pco};
|
||||
|
||||
use super::Dollars;
|
||||
|
||||
@@ -90,6 +90,13 @@ impl From<CentsSigned> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for CentsSigned {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for CentsSigned {
|
||||
#[inline]
|
||||
fn from(value: i64) -> Self {
|
||||
@@ -238,6 +245,12 @@ impl Mul<usize> for CentsSigned {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for CentsSigned {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CentsSigned {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut buf = itoa::Buffer::new();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user