diff --git a/crates/brk_computer/src/blocks/difficulty/import.rs b/crates/brk_computer/src/blocks/difficulty/import.rs index cbfa9fa42..56bdde520 100644 --- a/crates/brk_computer/src/blocks/difficulty/import.rs +++ b/crates/brk_computer/src/blocks/difficulty/import.rs @@ -6,7 +6,7 @@ use vecdb::{Database, ReadableCloneableVec}; use super::Vecs; use crate::{ indexes, - internal::{Bps32ToFloat, Bps32ToPercent, ComputedFromHeight, ComputedHeightDerived, PercentFromHeight}, + internal::{ComputedFromHeight, ComputedHeightDerived, PercentFromHeight}, }; impl Vecs { @@ -26,7 +26,7 @@ impl Vecs { indexes, ), as_hash: ComputedFromHeight::forced_import(db, "difficulty_as_hash", version, indexes)?, - adjustment: PercentFromHeight::forced_import::(db, "difficulty_adjustment", version, indexes)?, + adjustment: PercentFromHeight::forced_import_bps32(db, "difficulty_adjustment", version, indexes)?, epoch: ComputedFromHeight::forced_import(db, "difficulty_epoch", version, indexes)?, blocks_before_next_adjustment: ComputedFromHeight::forced_import( db, diff --git a/crates/brk_computer/src/blocks/size/compute.rs b/crates/brk_computer/src/blocks/size/compute.rs index 39f74ebf9..7dc1c8b72 100644 --- a/crates/brk_computer/src/blocks/size/compute.rs +++ b/crates/brk_computer/src/blocks/size/compute.rs @@ -16,7 +16,7 @@ impl Vecs { ) -> Result<()> { let window_starts = count_vecs.window_starts(); - // vbytes = ceil(weight / 4), stored at height level + // vbytes = floor(weight / 4), stored at height level self.vbytes.compute( starting_indexes.height, &window_starts, diff --git a/crates/brk_computer/src/blocks/weight/compute.rs b/crates/brk_computer/src/blocks/weight/compute.rs index 064b1ac32..b7bc6b7c2 100644 --- a/crates/brk_computer/src/blocks/weight/compute.rs +++ b/crates/brk_computer/src/blocks/weight/compute.rs @@ -1,6 +1,6 @@ use brk_error::Result; use brk_indexer::Indexer; -use brk_types::StoredF32; +use brk_types::BasisPoints16; use vecdb::Exit; use super::Vecs; @@ -31,7 +31,7 @@ impl Vecs { vec.compute_transform( starting_indexes.height, &indexer.vecs.blocks.weight, - |(h, weight, ..)| (h, StoredF32::from(weight.fullness())), + |(h, weight, ..)| (h, BasisPoints16::from(weight.fullness())), exit, )?; Ok(()) diff --git a/crates/brk_computer/src/blocks/weight/import.rs b/crates/brk_computer/src/blocks/weight/import.rs index b43cf2a54..895bf9f46 100644 --- a/crates/brk_computer/src/blocks/weight/import.rs +++ b/crates/brk_computer/src/blocks/weight/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedFromHeightDistribution, ComputedHeightDerivedFull}, + internal::{ComputedHeightDerivedFull, PercentFromHeightDistribution}, }; impl Vecs { @@ -22,7 +22,7 @@ impl Vecs { )?; let fullness = - ComputedFromHeightDistribution::forced_import(db, "block_fullness", version, indexes)?; + PercentFromHeightDistribution::forced_import_bp16(db, "block_fullness", version, indexes)?; Ok(Self { weight, fullness }) } diff --git a/crates/brk_computer/src/blocks/weight/vecs.rs b/crates/brk_computer/src/blocks/weight/vecs.rs index 08328c229..2bb8b09a8 100644 --- a/crates/brk_computer/src/blocks/weight/vecs.rs +++ b/crates/brk_computer/src/blocks/weight/vecs.rs @@ -1,11 +1,11 @@ use brk_traversable::Traversable; -use brk_types::{StoredF32, Weight}; +use brk_types::{BasisPoints16, Weight}; use vecdb::{Rw, StorageMode}; -use crate::internal::{ComputedFromHeightDistribution, ComputedHeightDerivedFull}; +use crate::internal::{ComputedHeightDerivedFull, PercentFromHeightDistribution}; #[derive(Traversable)] pub struct Vecs { pub weight: ComputedHeightDerivedFull, - pub fullness: ComputedFromHeightDistribution, + pub fullness: PercentFromHeightDistribution, } diff --git a/crates/brk_computer/src/cointime/activity/compute.rs b/crates/brk_computer/src/cointime/activity/compute.rs index c3aa5d16d..746a7685f 100644 --- a/crates/brk_computer/src/cointime/activity/compute.rs +++ b/crates/brk_computer/src/cointime/activity/compute.rs @@ -44,11 +44,10 @@ impl Vecs { self.coinblocks_stored .compute(starting_indexes.height, &window_starts, exit, |vec| { - vec.compute_transform2( + vec.compute_subtract( starting_indexes.height, &self.coinblocks_created.height, &coinblocks_destroyed.height, - |(i, created, destroyed, ..)| (i, created.checked_sub(destroyed).unwrap()), exit, )?; Ok(()) diff --git a/crates/brk_computer/src/cointime/adjusted/compute.rs b/crates/brk_computer/src/cointime/adjusted/compute.rs index 284f855ba..7fbfb1b15 100644 --- a/crates/brk_computer/src/cointime/adjusted/compute.rs +++ b/crates/brk_computer/src/cointime/adjusted/compute.rs @@ -1,5 +1,5 @@ use brk_error::Result; -use brk_types::{BasisPointsSigned32, StoredF64}; +use brk_types::BasisPointsSigned32; use vecdb::Exit; use super::super::activity; @@ -16,29 +16,27 @@ impl Vecs { ) -> Result<()> { self.cointime_adj_inflation_rate.bps.height.compute_transform2( starting_indexes.height, - &activity.activity_to_vaultedness_ratio.height, + &activity.liveliness.height, &supply.inflation_rate.bps.height, - |(h, ratio, inflation, ..)| (h, BasisPointsSigned32::from((*ratio) * f64::from(inflation))), + |(h, liveliness, inflation, ..)| (h, BasisPointsSigned32::from(f64::from(liveliness) * f64::from(inflation))), exit, )?; self.cointime_adj_tx_velocity_btc .height - .compute_transform2( + .compute_multiply( starting_indexes.height, &activity.activity_to_vaultedness_ratio.height, &supply.velocity.btc.height, - |(h, ratio, vel, ..)| (h, StoredF64::from(*ratio * *vel)), exit, )?; self.cointime_adj_tx_velocity_usd .height - .compute_transform2( + .compute_multiply( starting_indexes.height, &activity.activity_to_vaultedness_ratio.height, &supply.velocity.usd.height, - |(h, ratio, vel, ..)| (h, StoredF64::from(*ratio * *vel)), exit, )?; diff --git a/crates/brk_computer/src/cointime/adjusted/import.rs b/crates/brk_computer/src/cointime/adjusted/import.rs index f524eeaed..232d6e21d 100644 --- a/crates/brk_computer/src/cointime/adjusted/import.rs +++ b/crates/brk_computer/src/cointime/adjusted/import.rs @@ -5,13 +5,13 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{Bps32ToFloat, Bps32ToPercent, ComputedFromHeight, PercentFromHeight}, + internal::{ComputedFromHeight, PercentFromHeight}, }; impl Vecs { pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { Ok(Self { - cointime_adj_inflation_rate: PercentFromHeight::forced_import::( + cointime_adj_inflation_rate: PercentFromHeight::forced_import_bps32( db, "cointime_adj_inflation_rate", version, diff --git a/crates/brk_computer/src/cointime/cap/compute.rs b/crates/brk_computer/src/cointime/cap/compute.rs index d428fc303..572e7fc50 100644 --- a/crates/brk_computer/src/cointime/cap/compute.rs +++ b/crates/brk_computer/src/cointime/cap/compute.rs @@ -48,23 +48,17 @@ impl Vecs { exit, )?; - self.vaulted_cap.cents.height.compute_transform2( + self.vaulted_cap.cents.height.compute_multiply( starting_indexes.height, realized_cap_cents, &activity.vaultedness.height, - |(i, cap, vaultedness, ..)| { - (i, Cents::from(f64::from(cap) / f64::from(vaultedness))) - }, exit, )?; - self.active_cap.cents.height.compute_transform2( + self.active_cap.cents.height.compute_multiply( starting_indexes.height, realized_cap_cents, &activity.liveliness.height, - |(i, cap, liveliness, ..)| { - (i, Cents::from(f64::from(cap) * f64::from(liveliness))) - }, exit, )?; diff --git a/crates/brk_computer/src/cointime/pricing/compute.rs b/crates/brk_computer/src/cointime/pricing/compute.rs index 4a92efcf1..ec886af37 100644 --- a/crates/brk_computer/src/cointime/pricing/compute.rs +++ b/crates/brk_computer/src/cointime/pricing/compute.rs @@ -54,13 +54,10 @@ impl Vecs { &self.vaulted_price.cents.height, )?; - self.active_price.cents.height.compute_transform2( + self.active_price.cents.height.compute_multiply( starting_indexes.height, realized_price, &activity.liveliness.height, - |(i, price, liveliness, ..)| { - (i, Cents::from(f64::from(price) * f64::from(liveliness))) - }, exit, )?; diff --git a/crates/brk_computer/src/distribution/address/growth_rate.rs b/crates/brk_computer/src/distribution/address/growth_rate.rs index bf57891fb..1cd96de59 100644 --- a/crates/brk_computer/src/distribution/address/growth_rate.rs +++ b/crates/brk_computer/src/distribution/address/growth_rate.rs @@ -3,12 +3,12 @@ use brk_cohort::ByAddressType; use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Height, StoredF32, StoredU64, Version}; +use brk_types::{BasisPoints16, Height, StoredU64, Version}; use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode}; use crate::{ indexes, - internal::{ComputedFromHeightDistribution, WindowStarts}, + internal::{PercentFromHeightDistribution, WindowStarts}, }; use super::{AddrCountsVecs, NewAddrCountVecs}; @@ -16,9 +16,9 @@ use super::{AddrCountsVecs, NewAddrCountVecs}; /// Growth rate: new_addr_count / addr_count (global + per-type) #[derive(Traversable)] pub struct GrowthRateVecs { - pub all: ComputedFromHeightDistribution, + pub all: PercentFromHeightDistribution, #[traversable(flatten)] - pub by_addresstype: ByAddressType>, + pub by_addresstype: ByAddressType>, } impl GrowthRateVecs { @@ -27,22 +27,21 @@ impl GrowthRateVecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let all = ComputedFromHeightDistribution::forced_import( + let all = PercentFromHeightDistribution::forced_import_bp16( db, "growth_rate", version, indexes, )?; - let by_addresstype: ByAddressType> = - ByAddressType::new_with_name(|name| { - ComputedFromHeightDistribution::forced_import( - db, - &format!("{name}_growth_rate"), - version, - indexes, - ) - })?; + let by_addresstype = ByAddressType::new_with_name(|name| { + PercentFromHeightDistribution::forced_import_bp16( + db, + &format!("{name}_growth_rate"), + version, + indexes, + ) + })?; Ok(Self { all, by_addresstype }) } @@ -91,7 +90,7 @@ impl GrowthRateVecs { } fn compute_ratio( - target: &mut EagerVec>, + target: &mut EagerVec>, max_from: Height, numerator: &impl ReadableVec, denominator: &impl ReadableVec, @@ -105,7 +104,7 @@ fn compute_ratio( let n = *num as f64; let d = *den as f64; let ratio = if d == 0.0 { 0.0 } else { n / d }; - (h, StoredF32::from(ratio)) + (h, BasisPoints16::from(ratio)) }, exit, )?; diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index 403f9c363..194c29ec0 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -7,11 +7,11 @@ use brk_cohort::{ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{ - Cents, CentsCompact, CostBasisDistribution, Date, Dollars, Height, Sats, - StoredF32, Version, + BasisPoints16, Cents, CentsCompact, CostBasisDistribution, Date, Dollars, Height, Sats, + Version, }; use rayon::prelude::*; -use vecdb::{AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, VecIndex, WritableVec}; +use vecdb::{AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, WritableVec}; use crate::{ ComputeIndexes, blocks, @@ -859,13 +859,15 @@ impl UTXOCohorts { target .extended .spot_cost_basis_percentile + .bps .height - .truncate_push(height, StoredF32::NAN)?; + .truncate_push(height, BasisPoints16::ZERO)?; target .extended .spot_invested_capital_percentile + .bps .height - .truncate_push(height, StoredF32::NAN)?; + .truncate_push(height, BasisPoints16::ZERO)?; continue; } @@ -969,12 +971,14 @@ impl UTXOCohorts { target .extended .spot_cost_basis_percentile + .bps .height .truncate_push(height, rank)?; let rank = compute_spot_percentile_rank(&usd_result, spot); target .extended .spot_invested_capital_percentile + .bps .height .truncate_push(height, rank)?; diff --git a/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs b/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs index 6661712fa..c3803fac5 100644 --- a/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs @@ -1,12 +1,13 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Cents, Height, StoredF32, Version}; +use brk_types::{BasisPoints16, Cents, Height, Version}; use vecdb::{AnyStoredVec, Rw, StorageMode, WritableVec}; use crate::{ distribution::state::CohortState, internal::{ - ComputedFromHeight, PERCENTILES_LEN, PercentilesVecs, compute_spot_percentile_rank, + PERCENTILES_LEN, PercentFromHeight, PercentilesVecs, + compute_spot_percentile_rank, }, }; @@ -22,10 +23,10 @@ pub struct CostBasisExtended { pub invested_capital: PercentilesVecs, /// What percentile of cost basis is below spot (sat-weighted) - pub spot_cost_basis_percentile: ComputedFromHeight, + pub spot_cost_basis_percentile: PercentFromHeight, /// What percentile of invested capital is below spot (USD-weighted) - pub spot_invested_capital_percentile: ComputedFromHeight, + pub spot_invested_capital_percentile: PercentFromHeight, } impl CostBasisExtended { @@ -43,13 +44,13 @@ impl CostBasisExtended { cfg.version, cfg.indexes, )?, - spot_cost_basis_percentile: ComputedFromHeight::forced_import( + spot_cost_basis_percentile: PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("spot_cost_basis_percentile"), cfg.version, cfg.indexes, )?, - spot_invested_capital_percentile: ComputedFromHeight::forced_import( + spot_invested_capital_percentile: PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("spot_invested_capital_percentile"), cfg.version, @@ -74,6 +75,7 @@ impl CostBasisExtended { self.percentiles.truncate_push(height, &sat_prices)?; let rank = compute_spot_percentile_rank(&sat_prices, spot); self.spot_cost_basis_percentile + .bps .height .truncate_push(height, rank)?; @@ -85,6 +87,7 @@ impl CostBasisExtended { self.invested_capital.truncate_push(height, &usd_prices)?; let rank = compute_spot_percentile_rank(&usd_prices, spot); self.spot_invested_capital_percentile + .bps .height .truncate_push(height, rank)?; @@ -105,8 +108,8 @@ impl CostBasisExtended { .iter_mut() .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); + vecs.push(&mut self.spot_cost_basis_percentile.bps.height); + vecs.push(&mut self.spot_invested_capital_percentile.bps.height); vecs } @@ -116,9 +119,11 @@ impl CostBasisExtended { self.invested_capital .validate_computed_version_or_reset(base_version)?; self.spot_cost_basis_percentile + .bps .height .validate_computed_version_or_reset(base_version)?; self.spot_invested_capital_percentile + .bps .height .validate_computed_version_or_reset(base_version)?; Ok(()) diff --git a/crates/brk_computer/src/distribution/metrics/realized/base.rs b/crates/brk_computer/src/distribution/metrics/realized/base.rs index 623fdcf0e..3ca2e47c8 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/base.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/base.rs @@ -1,7 +1,7 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{ - BasisPoints16, BasisPointsSigned16, + BasisPoints16, BasisPoints32, BasisPointsSigned16, Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats, Dollars, Height, Sats, StoredF32, StoredF64, Version, }; use vecdb::{ @@ -13,7 +13,6 @@ use crate::{ ComputeIndexes, blocks, distribution::state::RealizedState, internal::{ - Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, CentsPlus, CentsUnsignedToDollars, ComputedFromHeightCumulative, ComputedFromHeight, ComputedFromHeightRatio, FiatFromHeight, NegCentsUnsignedToDollars, PercentFromHeight, PercentRollingEmas1w1m, PercentRollingWindows, ValueFromHeightCumulative, LazyFromHeight, @@ -196,7 +195,7 @@ impl RealizedBase { )?; let realized_profit_rel_to_realized_cap = - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("realized_profit_rel_to_realized_cap"), cfg.version + v1, @@ -204,7 +203,7 @@ impl RealizedBase { )?; let realized_loss_rel_to_realized_cap = - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("realized_loss_rel_to_realized_cap"), cfg.version + v1, @@ -212,7 +211,7 @@ impl RealizedBase { )?; let net_realized_pnl_rel_to_realized_cap = - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("net_realized_pnl_rel_to_realized_cap"), cfg.version + v1, @@ -316,10 +315,9 @@ impl RealizedBase { cfg.indexes, )?; - let mvrv = LazyFromHeight::from_computed::>( + let mvrv = LazyFromHeight::from_lazy::, BasisPoints32>( &cfg.name("mvrv"), cfg.version, - realized_price_ratio.ratio.height.read_only_boxed_clone(), &realized_price_ratio.ratio, ); @@ -336,7 +334,7 @@ impl RealizedBase { let sopr = RollingWindows::forced_import( cfg.db, &cfg.name("sopr"), cfg.version + v1, cfg.indexes, )?; - let sell_side_risk_ratio = PercentRollingWindows::forced_import::( + let sell_side_risk_ratio = PercentRollingWindows::forced_import_bp16( cfg.db, &cfg.name("sell_side_risk_ratio"), cfg.version + v1, cfg.indexes, )?; @@ -344,12 +342,12 @@ impl RealizedBase { let sopr_24h_ema = RollingEmas1w1m::forced_import( cfg.db, &cfg.name("sopr_24h"), cfg.version + v1, cfg.indexes, )?; - let sell_side_risk_ratio_24h_ema = PercentRollingEmas1w1m::forced_import::( + let sell_side_risk_ratio_24h_ema = PercentRollingEmas1w1m::forced_import_bp16( cfg.db, &cfg.name("sell_side_risk_ratio_24h"), cfg.version + v1, cfg.indexes, )?; let peak_regret_rel_to_realized_cap = - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("realized_peak_regret_rel_to_realized_cap"), cfg.version + v1, @@ -407,14 +405,14 @@ impl RealizedBase { cfg.indexes, )?, net_pnl_change_1m_rel_to_realized_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("net_pnl_change_1m_rel_to_realized_cap"), cfg.version + v3, cfg.indexes, )?, net_pnl_change_1m_rel_to_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("net_pnl_change_1m_rel_to_market_cap"), cfg.version + v3, diff --git a/crates/brk_computer/src/distribution/metrics/realized/extended.rs b/crates/brk_computer/src/distribution/metrics/realized/extended.rs index 27459af65..45d48fe47 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/extended.rs @@ -6,7 +6,7 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use crate::{ ComputeIndexes, blocks, internal::{ - Bp16ToFloat, Bp16ToPercent, ComputedFromHeightRatioExtension, PercentFromHeight, + ComputedFromHeightRatioExtension, PercentFromHeight, RatioCents64, RatioDollarsBp16, RollingWindows, }, }; @@ -37,7 +37,7 @@ impl RealizedExtended { let v1 = Version::ONE; Ok(RealizedExtended { - realized_cap_rel_to_own_market_cap: PercentFromHeight::forced_import::( + realized_cap_rel_to_own_market_cap: PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("realized_cap_rel_to_own_market_cap"), cfg.version, diff --git a/crates/brk_computer/src/distribution/metrics/relative/base.rs b/crates/brk_computer/src/distribution/metrics/relative/base.rs index 388c21a5e..c9bda2c1f 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/base.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/base.rs @@ -4,7 +4,7 @@ use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height, Sats, Store use vecdb::{Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode}; use crate::internal::{ - Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, LazyFromHeight, + Bps16ToFloat, LazyFromHeight, NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16, RatioSatsBp16, }; @@ -37,7 +37,7 @@ impl RelativeBase { let v2 = Version::new(2); let net_unrealized_pnl_rel_to_market_cap = - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, cfg.indexes, )?; @@ -50,33 +50,33 @@ impl RelativeBase { Ok(Self { supply_in_profit_rel_to_own_supply: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("supply_in_profit_rel_to_own_supply"), cfg.version + v1, cfg.indexes, )?, supply_in_loss_rel_to_own_supply: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("supply_in_loss_rel_to_own_supply"), cfg.version + v1, cfg.indexes, )?, unrealized_profit_rel_to_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("unrealized_profit_rel_to_market_cap"), cfg.version + v2, cfg.indexes, )?, unrealized_loss_rel_to_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes, )?, neg_unrealized_loss_rel_to_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("neg_unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes, )?, net_unrealized_pnl_rel_to_market_cap, nupl, invested_capital_in_profit_rel_to_realized_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("invested_capital_in_profit_rel_to_realized_cap"), cfg.version, cfg.indexes, )?, invested_capital_in_loss_rel_to_realized_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("invested_capital_in_loss_rel_to_realized_cap"), cfg.version, cfg.indexes, )?, }) diff --git a/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs b/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs index 09561c03f..b4b04e201 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs @@ -4,7 +4,6 @@ use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height}; use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use crate::internal::{ - Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16, }; @@ -31,28 +30,28 @@ impl RelativeExtendedOwnMarketCap { Ok(Self { unrealized_profit_rel_to_own_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("unrealized_profit_rel_to_own_market_cap"), cfg.version + v2, cfg.indexes, )?, unrealized_loss_rel_to_own_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("unrealized_loss_rel_to_own_market_cap"), cfg.version + v2, cfg.indexes, )?, neg_unrealized_loss_rel_to_own_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("neg_unrealized_loss_rel_to_own_market_cap"), cfg.version + v2, cfg.indexes, )?, net_unrealized_pnl_rel_to_own_market_cap: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("net_unrealized_pnl_rel_to_own_market_cap"), cfg.version + v2, diff --git a/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs b/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs index 704e6f959..c245d6630 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs @@ -4,7 +4,6 @@ use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height}; use vecdb::{Exit, Rw, StorageMode}; use crate::internal::{ - Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16, }; @@ -32,28 +31,28 @@ impl RelativeExtendedOwnPnl { Ok(Self { unrealized_profit_rel_to_own_gross_pnl: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("unrealized_profit_rel_to_own_gross_pnl"), cfg.version + v1, cfg.indexes, )?, unrealized_loss_rel_to_own_gross_pnl: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("unrealized_loss_rel_to_own_gross_pnl"), cfg.version + v1, cfg.indexes, )?, neg_unrealized_loss_rel_to_own_gross_pnl: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("neg_unrealized_loss_rel_to_own_gross_pnl"), cfg.version + v1, cfg.indexes, )?, net_unrealized_pnl_rel_to_own_gross_pnl: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps16( cfg.db, &cfg.name("net_unrealized_pnl_rel_to_own_gross_pnl"), cfg.version + v2, diff --git a/crates/brk_computer/src/distribution/metrics/relative/to_all.rs b/crates/brk_computer/src/distribution/metrics/relative/to_all.rs index 1d50a6ecb..f62173cc4 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/to_all.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/to_all.rs @@ -3,7 +3,7 @@ use brk_traversable::Traversable; use brk_types::{BasisPoints16, Height, Sats}; use vecdb::{Exit, ReadableVec, Rw, StorageMode}; -use crate::internal::{Bp16ToFloat, Bp16ToPercent, PercentFromHeight, RatioSatsBp16}; +use crate::internal::{PercentFromHeight, RatioSatsBp16}; use crate::distribution::metrics::{ImportConfig, UnrealizedBase}; @@ -24,21 +24,21 @@ impl RelativeToAll { ) -> Result { Ok(Self { supply_rel_to_circulating_supply: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("supply_rel_to_circulating_supply"), cfg.version + brk_types::Version::ONE, cfg.indexes, )?, supply_in_profit_rel_to_circulating_supply: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("supply_in_profit_rel_to_circulating_supply"), cfg.version + brk_types::Version::ONE, cfg.indexes, )?, supply_in_loss_rel_to_circulating_supply: - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bp16( cfg.db, &cfg.name("supply_in_loss_rel_to_circulating_supply"), cfg.version + brk_types::Version::ONE, diff --git a/crates/brk_computer/src/internal/compute.rs b/crates/brk_computer/src/internal/compute.rs index 8fbe324ad..0b1b3fe49 100644 --- a/crates/brk_computer/src/internal/compute.rs +++ b/crates/brk_computer/src/internal/compute.rs @@ -165,33 +165,14 @@ where if values.is_empty() { // Handle edge case where all items were skipped - if let Some(ref mut max_vec) = max { - max_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut pct90_vec) = pct90 { - pct90_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut pct75_vec) = pct75 { - pct75_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut median_vec) = median { - median_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut pct25_vec) = pct25 { - pct25_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut pct10_vec) = pct10 { - pct10_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut min_vec) = min { - min_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut average_vec) = average { - average_vec.truncate_push_at(idx, T::from(0_usize))?; - } - if let Some(ref mut sum_vec) = sum { - sum_vec.truncate_push_at(idx, T::from(0_usize))?; + macro_rules! push_zero { + ($($vec:ident),*) => { + $(if let Some(ref mut v) = $vec { + v.truncate_push_at(idx, T::from(0_usize))?; + })* + }; } + push_zero!(max, pct90, pct75, median, pct25, pct10, min, average, sum); if let Some(ref mut cumulative_vec) = cumulative { let t = cumulative_val.unwrap(); cumulative_vec.truncate_push_at(idx, t)?; diff --git a/crates/brk_computer/src/internal/from_height/float32.rs b/crates/brk_computer/src/internal/from_height/float32.rs deleted file mode 100644 index 8ed205764..000000000 --- a/crates/brk_computer/src/internal/from_height/float32.rs +++ /dev/null @@ -1,61 +0,0 @@ -use brk_error::Result; -use brk_traversable::Traversable; -use brk_types::{Height, StoredF32, Version}; -use schemars::JsonSchema; -use vecdb::{BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, UnaryTransform, VecValue}; - -use crate::indexes; - -use super::{ComputedFromHeight, LazyFromHeight}; -use crate::internal::NumericValue; - -/// Basis-point storage with lazy ratio float view (÷10000). -/// -/// Stores integer basis points on disk (Pco-compressed), -/// exposes a lazy StoredF32 ratio (e.g., 25000 bps → 2.5). -#[derive(Traversable)] -pub struct Float32FromHeight -where - B: NumericValue + JsonSchema, -{ - pub bps: ComputedFromHeight, - pub float: LazyFromHeight, -} - -impl Float32FromHeight -where - B: NumericValue + JsonSchema, -{ - pub(crate) fn forced_import>( - db: &Database, - name: &str, - version: Version, - indexes: &indexes::Vecs, - ) -> Result { - let bps = ComputedFromHeight::forced_import(db, name, version, indexes)?; - - let float = LazyFromHeight::from_computed::( - &format!("{name}_float"), - version, - bps.height.read_only_boxed_clone(), - &bps, - ); - - Ok(Self { bps, float }) - } - - pub(crate) fn compute_binary( - &mut self, - max_from: Height, - source1: &impl ReadableVec, - source2: &impl ReadableVec, - exit: &Exit, - ) -> Result<()> - where - S1T: VecValue, - S2T: VecValue, - F: BinaryTransform, - { - self.bps.compute_binary::(max_from, source1, source2, exit) - } -} diff --git a/crates/brk_computer/src/internal/from_height/mod.rs b/crates/brk_computer/src/internal/from_height/mod.rs index 55e4efd5e..0340355a4 100644 --- a/crates/brk_computer/src/internal/from_height/mod.rs +++ b/crates/brk_computer/src/internal/from_height/mod.rs @@ -6,10 +6,10 @@ mod cumulative; mod cumulative_sum; mod distribution; mod fiat; -mod float32; mod full; mod lazy_base; mod percent; +mod percent_distribution; mod percentiles; mod price; mod ratio; @@ -24,10 +24,10 @@ pub use cumulative::*; pub use cumulative_sum::*; pub use distribution::*; pub use fiat::*; -pub use float32::*; pub use full::*; pub use lazy_base::*; pub use percent::*; +pub use percent_distribution::*; pub use percentiles::*; pub use price::*; pub use ratio::*; diff --git a/crates/brk_computer/src/internal/from_height/percent.rs b/crates/brk_computer/src/internal/from_height/percent.rs index 33828c851..df89ccdbe 100644 --- a/crates/brk_computer/src/internal/from_height/percent.rs +++ b/crates/brk_computer/src/internal/from_height/percent.rs @@ -1,12 +1,17 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Height, StoredF32, Version}; +use brk_types::{ + BasisPoints16, BasisPointsSigned16, BasisPointsSigned32, Height, StoredF32, Version, +}; use schemars::JsonSchema; use vecdb::{BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, UnaryTransform, VecValue}; use crate::{ indexes, - internal::NumericValue, + internal::{ + Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, Bps32ToFloat, Bps32ToPercent, + NumericValue, + }, traits::ComputeDrawdown, }; @@ -44,7 +49,7 @@ where RatioTransform: UnaryTransform, PercentTransform: UnaryTransform, { - let bps = ComputedFromHeight::forced_import(db, name, version, indexes)?; + let bps = ComputedFromHeight::forced_import(db, &format!("{name}_bps"), version, indexes)?; let ratio = LazyFromHeight::from_computed::( &format!("{name}_ratio"), @@ -54,7 +59,7 @@ where ); let percent = LazyFromHeight::from_computed::( - &format!("{name}_percent"), + name, version, bps.height.read_only_boxed_clone(), &bps, @@ -63,6 +68,45 @@ where Ok(Self { bps, ratio, percent }) } +} + +impl PercentFromHeight { + pub(crate) fn forced_import_bp16( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import::(db, name, version, indexes) + } +} + +impl PercentFromHeight { + pub(crate) fn forced_import_bps16( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import::(db, name, version, indexes) + } +} + +impl PercentFromHeight { + pub(crate) fn forced_import_bps32( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import::(db, name, version, indexes) + } +} + +impl PercentFromHeight +where + B: NumericValue + JsonSchema, +{ pub(crate) fn compute_binary( &mut self, max_from: Height, diff --git a/crates/brk_computer/src/internal/from_height/percent_distribution.rs b/crates/brk_computer/src/internal/from_height/percent_distribution.rs new file mode 100644 index 000000000..82b18c2a4 --- /dev/null +++ b/crates/brk_computer/src/internal/from_height/percent_distribution.rs @@ -0,0 +1,85 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{BasisPoints16, Height, StoredF32, Version}; +use schemars::JsonSchema; +use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode, UnaryTransform}; + +use crate::{indexes, internal::{Bp16ToFloat, Bp16ToPercent, NumericValue, WindowStarts}}; + +use super::{ComputedFromHeightDistribution, LazyFromHeight}; + +/// Like PercentFromHeight but with rolling distribution stats on the bps data. +#[derive(Traversable)] +pub struct PercentFromHeightDistribution +where + B: NumericValue + JsonSchema, +{ + pub bps: ComputedFromHeightDistribution, + pub ratio: LazyFromHeight, + pub percent: LazyFromHeight, +} + +impl PercentFromHeightDistribution +where + B: NumericValue + JsonSchema, +{ + pub(crate) fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result + where + RatioTransform: UnaryTransform, + PercentTransform: UnaryTransform, + { + let bps = ComputedFromHeightDistribution::forced_import(db, &format!("{name}_bps"), version, indexes)?; + + let ratio = LazyFromHeight::from_height_source::( + &format!("{name}_ratio"), + version, + bps.height.read_only_boxed_clone(), + indexes, + ); + + let percent = LazyFromHeight::from_height_source::( + name, + version, + bps.height.read_only_boxed_clone(), + indexes, + ); + + Ok(Self { bps, ratio, percent }) + } + +} + +impl PercentFromHeightDistribution { + pub(crate) fn forced_import_bp16( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import::(db, name, version, indexes) + } +} + +impl PercentFromHeightDistribution +where + B: NumericValue + JsonSchema, +{ + pub(crate) fn compute( + &mut self, + max_from: Height, + windows: &WindowStarts<'_>, + exit: &Exit, + compute_height: impl FnOnce(&mut EagerVec>) -> Result<()>, + ) -> Result<()> + where + B: Copy + Ord + From + Default, + f64: From, + { + self.bps.compute(max_from, windows, exit, compute_height) + } +} diff --git a/crates/brk_computer/src/internal/from_height/percentiles.rs b/crates/brk_computer/src/internal/from_height/percentiles.rs index 581e57410..e89015f42 100644 --- a/crates/brk_computer/src/internal/from_height/percentiles.rs +++ b/crates/brk_computer/src/internal/from_height/percentiles.rs @@ -1,6 +1,6 @@ use brk_error::Result; use brk_traversable::{Traversable, TreeNode}; -use brk_types::{Cents, Height, StoredF32, Version}; +use brk_types::{BasisPoints16, Cents, Height, Version}; use vecdb::{AnyExportableVec, Database, ReadOnlyClone, Ro, Rw, StorageMode, WritableVec}; use crate::indexes; @@ -16,9 +16,9 @@ pub const PERCENTILES_LEN: usize = PERCENTILES.len(); pub(crate) fn compute_spot_percentile_rank( percentile_prices: &[Cents; PERCENTILES_LEN], spot: Cents, -) -> StoredF32 { +) -> BasisPoints16 { if spot == Cents::ZERO && percentile_prices[0] == Cents::ZERO { - return StoredF32::NAN; + return BasisPoints16::ZERO; } let spot_f64 = f64::from(spot); @@ -27,10 +27,10 @@ pub(crate) fn compute_spot_percentile_rank( let p5 = f64::from(percentile_prices[0]); if spot_f64 <= p5 { if p5 == 0.0 { - return StoredF32::from(0.0); + return BasisPoints16::ZERO; } - // Linear extrapolation: rank = 5 * (spot / p5) - return StoredF32::from((5.0 * spot_f64 / p5).max(0.0)); + // Linear extrapolation: rank = 5% * (spot / p5) + return BasisPoints16::from((0.05 * spot_f64 / p5).max(0.0)); } // Above highest percentile (p95) - extrapolate towards 100 @@ -38,11 +38,11 @@ pub(crate) fn compute_spot_percentile_rank( let p90 = f64::from(percentile_prices[PERCENTILES_LEN - 2]); if spot_f64 >= p95 { if p95 == p90 { - return StoredF32::from(100.0); + return BasisPoints16::ONE; } // Linear extrapolation using p90-p95 slope - let slope = 5.0 / (p95 - p90); - return StoredF32::from((95.0 + (spot_f64 - p95) * slope).min(100.0)); + let slope = 0.05 / (p95 - p90); + return BasisPoints16::from((0.95 + (spot_f64 - p95) * slope).min(1.0)); } // Find the band containing spot and interpolate @@ -51,20 +51,20 @@ pub(crate) fn compute_spot_percentile_rank( let upper = f64::from(percentile_prices[i + 1]); if spot_f64 >= lower && spot_f64 <= upper { - let lower_pct = f64::from(PERCENTILES[i]); - let upper_pct = f64::from(PERCENTILES[i + 1]); + let lower_pct = f64::from(PERCENTILES[i]) / 100.0; + let upper_pct = f64::from(PERCENTILES[i + 1]) / 100.0; if upper == lower { - return StoredF32::from(lower_pct); + return BasisPoints16::from(lower_pct); } // Linear interpolation let ratio = (spot_f64 - lower) / (upper - lower); - return StoredF32::from(lower_pct + ratio * (upper_pct - lower_pct)); + return BasisPoints16::from(lower_pct + ratio * (upper_pct - lower_pct)); } } - StoredF32::NAN + BasisPoints16::ZERO } pub struct PercentilesVecs { diff --git a/crates/brk_computer/src/internal/from_height/ratio/extension.rs b/crates/brk_computer/src/internal/from_height/ratio/extension.rs index 7ccbdd86f..875835c94 100644 --- a/crates/brk_computer/src/internal/from_height/ratio/extension.rs +++ b/crates/brk_computer/src/internal/from_height/ratio/extension.rs @@ -1,6 +1,6 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Cents, Height, StoredF32, Version}; +use brk_types::{BasisPoints32, Cents, Height, StoredF32, Version}; use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, WritableVec}; use crate::{ @@ -8,18 +8,18 @@ use crate::{ internal::{ComputedFromHeightStdDevExtended, Price, TDigest}, }; -use super::super::ComputedFromHeight; +use super::{ComputedFromHeightRatio, super::ComputedFromHeight}; #[derive(Traversable)] pub struct ComputedFromHeightRatioExtension { - pub ratio_sma_1w: ComputedFromHeight, - pub ratio_sma_1m: ComputedFromHeight, - pub ratio_pct99: ComputedFromHeight, - pub ratio_pct98: ComputedFromHeight, - pub ratio_pct95: ComputedFromHeight, - pub ratio_pct5: ComputedFromHeight, - pub ratio_pct2: ComputedFromHeight, - pub ratio_pct1: ComputedFromHeight, + pub ratio_sma_1w: ComputedFromHeightRatio, + pub ratio_sma_1m: ComputedFromHeightRatio, + pub ratio_pct99: ComputedFromHeightRatio, + pub ratio_pct98: ComputedFromHeightRatio, + pub ratio_pct95: ComputedFromHeightRatio, + pub ratio_pct5: ComputedFromHeightRatio, + pub ratio_pct2: ComputedFromHeightRatio, + pub ratio_pct1: ComputedFromHeightRatio, pub ratio_pct99_price: Price>, pub ratio_pct98_price: Price>, pub ratio_pct95_price: Price>, @@ -47,9 +47,9 @@ impl ComputedFromHeightRatioExtension { ) -> Result { let v = version + VERSION; - macro_rules! import { + macro_rules! import_ratio { ($suffix:expr) => { - ComputedFromHeight::forced_import( + ComputedFromHeightRatio::forced_import_raw( db, &format!("{name}_{}", $suffix), v, @@ -78,18 +78,18 @@ impl ComputedFromHeightRatioExtension { } Ok(Self { - ratio_sma_1w: import!("ratio_sma_1w"), - ratio_sma_1m: import!("ratio_sma_1m"), + ratio_sma_1w: import_ratio!("ratio_sma_1w"), + ratio_sma_1m: import_ratio!("ratio_sma_1m"), ratio_sd: import_sd!("ratio", "", usize::MAX), ratio_sd_1y: import_sd!("ratio", "1y", 365), ratio_sd_2y: import_sd!("ratio", "2y", 2 * 365), ratio_sd_4y: import_sd!("ratio", "4y", 4 * 365), - ratio_pct99: import!("ratio_pct99"), - ratio_pct98: import!("ratio_pct98"), - ratio_pct95: import!("ratio_pct95"), - ratio_pct5: import!("ratio_pct5"), - ratio_pct2: import!("ratio_pct2"), - ratio_pct1: import!("ratio_pct1"), + ratio_pct99: import_ratio!("ratio_pct99"), + ratio_pct98: import_ratio!("ratio_pct98"), + ratio_pct95: import_ratio!("ratio_pct95"), + ratio_pct5: import_ratio!("ratio_pct5"), + ratio_pct2: import_ratio!("ratio_pct2"), + ratio_pct1: import_ratio!("ratio_pct1"), ratio_pct99_price: import_price!("ratio_pct99"), ratio_pct98_price: import_price!("ratio_pct98"), ratio_pct95_price: import_price!("ratio_pct95"), @@ -109,14 +109,14 @@ impl ComputedFromHeightRatioExtension { ratio_source: &impl ReadableVec, ) -> Result<()> { // SMA using lookback vecs - self.ratio_sma_1w.height.compute_rolling_average( + self.ratio_sma_1w.bps.height.compute_rolling_average( starting_indexes.height, &blocks.count.height_1w_ago, ratio_source, exit, )?; - self.ratio_sma_1m.height.compute_rolling_average( + self.ratio_sma_1m.bps.height.compute_rolling_average( starting_indexes.height, &blocks.count.height_1m_ago, ratio_source, @@ -124,14 +124,14 @@ impl ComputedFromHeightRatioExtension { )?; let ratio_version = ratio_source.version(); - self.mut_ratio_vecs() + self.mut_pct_vecs() .try_for_each(|v| -> Result<()> { v.validate_computed_version_or_reset(ratio_version)?; Ok(()) })?; let starting_height = self - .mut_ratio_vecs() + .mut_pct_vecs() .map(|v| Height::from(v.len())) .min() .unwrap() @@ -154,13 +154,13 @@ impl ComputedFromHeightRatioExtension { // Process new blocks [start, ratio_len) let new_ratios = ratio_source.collect_range_at(start, ratio_len); - let mut pct_vecs: [&mut EagerVec>; 6] = [ - &mut self.ratio_pct1.height, - &mut self.ratio_pct2.height, - &mut self.ratio_pct5.height, - &mut self.ratio_pct95.height, - &mut self.ratio_pct98.height, - &mut self.ratio_pct99.height, + let mut pct_vecs: [&mut EagerVec>; 6] = [ + &mut self.ratio_pct1.bps.height, + &mut self.ratio_pct2.bps.height, + &mut self.ratio_pct5.bps.height, + &mut self.ratio_pct95.bps.height, + &mut self.ratio_pct98.bps.height, + &mut self.ratio_pct99.bps.height, ]; const PCTS: [f64; 6] = [0.01, 0.02, 0.05, 0.95, 0.98, 0.99]; let mut out = [0.0f64; 6]; @@ -170,14 +170,14 @@ impl ComputedFromHeightRatioExtension { self.tdigest.quantiles(&PCTS, &mut out); let idx = start + offset; for (vec, &val) in pct_vecs.iter_mut().zip(out.iter()) { - vec.truncate_push_at(idx, StoredF32::from(val as f32))?; + vec.truncate_push_at(idx, BasisPoints32::from(val))?; } } } { let _lock = exit.lock(); - self.mut_ratio_vecs() + self.mut_pct_vecs() .try_for_each(|v| v.flush())?; } @@ -201,13 +201,13 @@ impl ComputedFromHeightRatioExtension { metric_price: &impl ReadableVec, exit: &Exit, ) -> Result<()> { - use crate::internal::PriceTimesRatioCents; + use crate::internal::PriceTimesRatioBp32Cents; macro_rules! compute_band { ($usd_field:ident, $band_source:expr) => { self.$usd_field .cents - .compute_binary::( + .compute_binary::( starting_indexes.height, metric_price, $band_source, @@ -216,12 +216,12 @@ impl ComputedFromHeightRatioExtension { }; } - 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); + compute_band!(ratio_pct99_price, &self.ratio_pct99.bps.height); + compute_band!(ratio_pct98_price, &self.ratio_pct98.bps.height); + compute_band!(ratio_pct95_price, &self.ratio_pct95.bps.height); + compute_band!(ratio_pct5_price, &self.ratio_pct5.bps.height); + compute_band!(ratio_pct2_price, &self.ratio_pct2.bps.height); + compute_band!(ratio_pct1_price, &self.ratio_pct1.bps.height); // Stddev cents bands self.ratio_sd @@ -236,16 +236,16 @@ impl ComputedFromHeightRatioExtension { Ok(()) } - fn mut_ratio_vecs( + fn mut_pct_vecs( &mut self, - ) -> impl Iterator>> { + ) -> impl Iterator>> { [ - &mut self.ratio_pct1.height, - &mut self.ratio_pct2.height, - &mut self.ratio_pct5.height, - &mut self.ratio_pct95.height, - &mut self.ratio_pct98.height, - &mut self.ratio_pct99.height, + &mut self.ratio_pct1.bps.height, + &mut self.ratio_pct2.bps.height, + &mut self.ratio_pct5.bps.height, + &mut self.ratio_pct95.bps.height, + &mut self.ratio_pct98.bps.height, + &mut self.ratio_pct99.bps.height, ] .into_iter() } diff --git a/crates/brk_computer/src/internal/from_height/ratio/mod.rs b/crates/brk_computer/src/internal/from_height/ratio/mod.rs index 0f81a61dc..b9276fc3e 100644 --- a/crates/brk_computer/src/internal/from_height/ratio/mod.rs +++ b/crates/brk_computer/src/internal/from_height/ratio/mod.rs @@ -8,16 +8,17 @@ pub use price_extended::*; use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Cents, Height, StoredF32, Version}; -use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode}; +use brk_types::{BasisPoints32, Cents, Height, StoredF32, Version}; +use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode}; -use crate::{ComputeIndexes, indexes}; +use crate::{ComputeIndexes, indexes, internal::Bp32ToFloat}; -use super::ComputedFromHeight; +use super::{ComputedFromHeight, LazyFromHeight}; #[derive(Traversable)] pub struct ComputedFromHeightRatio { - pub ratio: ComputedFromHeight, + pub bps: ComputedFromHeight, + pub ratio: LazyFromHeight, } const VERSION: Version = Version::TWO; @@ -28,12 +29,28 @@ impl ComputedFromHeightRatio { name: &str, version: Version, indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import_raw(db, &format!("{name}_ratio"), version, indexes) + } + + pub(crate) fn forced_import_raw( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, ) -> Result { let v = version + VERSION; - Ok(Self { - ratio: ComputedFromHeight::forced_import(db, &format!("{name}_ratio"), v, indexes)?, - }) + let bps = ComputedFromHeight::forced_import(db, &format!("{name}_bps"), v, indexes)?; + + let ratio = LazyFromHeight::from_computed::( + name, + v, + bps.height.read_only_boxed_clone(), + &bps, + ); + + Ok(Self { bps, ratio }) } /// Compute ratio = close_price / metric_price at height level (both in cents) @@ -44,15 +61,15 @@ impl ComputedFromHeightRatio { metric_price: &impl ReadableVec, exit: &Exit, ) -> Result<()> { - self.ratio.height.compute_transform2( + self.bps.height.compute_transform2( starting_indexes.height, close_price, metric_price, |(i, close, price, ..)| { if price == Cents::ZERO { - (i, StoredF32::from(1.0)) + (i, BasisPoints32::from(1.0)) } else { - (i, StoredF32::from(f64::from(close) / f64::from(price))) + (i, BasisPoints32::from(f64::from(close) / f64::from(price))) } }, exit, diff --git a/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs b/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs index a5687b2c2..40fca736b 100644 --- a/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs +++ b/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs @@ -1,13 +1,13 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Height, StoredF32, Version}; +use brk_types::{BasisPoints16, Height, StoredF32, Version}; use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, UnaryTransform}; use crate::{ indexes, - internal::{Emas1w1m, NumericValue, PercentFromHeight}, + internal::{Bp16ToFloat, Bp16ToPercent, Emas1w1m, NumericValue, PercentFromHeight}, }; const VERSION: Version = Version::ZERO; @@ -45,6 +45,23 @@ where })?)) } +} + +impl PercentRollingEmas1w1m { + pub(crate) fn forced_import_bp16( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import::(db, name, version, indexes) + } +} + +impl PercentRollingEmas1w1m +where + B: NumericValue + JsonSchema, +{ pub(crate) fn compute_from_24h( &mut self, max_from: Height, diff --git a/crates/brk_computer/src/internal/rolling/percent_windows.rs b/crates/brk_computer/src/internal/rolling/percent_windows.rs index 3950f1b44..cdc8dadf1 100644 --- a/crates/brk_computer/src/internal/rolling/percent_windows.rs +++ b/crates/brk_computer/src/internal/rolling/percent_windows.rs @@ -1,13 +1,13 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{StoredF32, Version}; +use brk_types::{BasisPoints16, StoredF32, Version}; use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use vecdb::{Database, Rw, StorageMode, UnaryTransform}; use crate::{ indexes, - internal::{NumericValue, PercentFromHeight, Windows}, + internal::{Bp16ToFloat, Bp16ToPercent, NumericValue, PercentFromHeight, Windows}, }; const VERSION: Version = Version::ZERO; @@ -45,3 +45,14 @@ where })?)) } } + +impl PercentRollingWindows { + pub(crate) fn forced_import_bp16( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + Self::forced_import::(db, name, version, indexes) + } +} diff --git a/crates/brk_computer/src/internal/transform/bp16_to_float.rs b/crates/brk_computer/src/internal/transform/bp16_to_float.rs deleted file mode 100644 index 20c8357ad..000000000 --- a/crates/brk_computer/src/internal/transform/bp16_to_float.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPoints16, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bp16ToFloat; - -impl UnaryTransform for Bp16ToFloat { - #[inline(always)] - fn apply(bp: BasisPoints16) -> StoredF32 { - StoredF32::from(bp.to_f32()) - } -} diff --git a/crates/brk_computer/src/internal/transform/bp16_to_percent.rs b/crates/brk_computer/src/internal/transform/bp16_to_percent.rs deleted file mode 100644 index 4fc3644af..000000000 --- a/crates/brk_computer/src/internal/transform/bp16_to_percent.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPoints16, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bp16ToPercent; - -impl UnaryTransform for Bp16ToPercent { - #[inline(always)] - fn apply(bp: BasisPoints16) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/bp32_to_float.rs b/crates/brk_computer/src/internal/transform/bp32_to_float.rs deleted file mode 100644 index 9226be12e..000000000 --- a/crates/brk_computer/src/internal/transform/bp32_to_float.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPoints32, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bp32ToFloat; - -impl UnaryTransform for Bp32ToFloat { - #[inline(always)] - fn apply(bp: BasisPoints32) -> StoredF32 { - StoredF32::from(bp.to_f32()) - } -} diff --git a/crates/brk_computer/src/internal/transform/bp32_to_percent.rs b/crates/brk_computer/src/internal/transform/bp32_to_percent.rs deleted file mode 100644 index d8d02e06f..000000000 --- a/crates/brk_computer/src/internal/transform/bp32_to_percent.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPoints32, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bp32ToPercent; - -impl UnaryTransform for Bp32ToPercent { - #[inline(always)] - fn apply(bp: BasisPoints32) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/bps16_to_float.rs b/crates/brk_computer/src/internal/transform/bps16_to_float.rs deleted file mode 100644 index 7a3882cdc..000000000 --- a/crates/brk_computer/src/internal/transform/bps16_to_float.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPointsSigned16, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bps16ToFloat; - -impl UnaryTransform for Bps16ToFloat { - #[inline(always)] - fn apply(bp: BasisPointsSigned16) -> StoredF32 { - StoredF32::from(bp.to_f32()) - } -} diff --git a/crates/brk_computer/src/internal/transform/bps16_to_percent.rs b/crates/brk_computer/src/internal/transform/bps16_to_percent.rs deleted file mode 100644 index 800e7ab23..000000000 --- a/crates/brk_computer/src/internal/transform/bps16_to_percent.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPointsSigned16, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bps16ToPercent; - -impl UnaryTransform for Bps16ToPercent { - #[inline(always)] - fn apply(bp: BasisPointsSigned16) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/bps32_to_float.rs b/crates/brk_computer/src/internal/transform/bps32_to_float.rs deleted file mode 100644 index a43f1fc07..000000000 --- a/crates/brk_computer/src/internal/transform/bps32_to_float.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPointsSigned32, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bps32ToFloat; - -impl UnaryTransform for Bps32ToFloat { - #[inline(always)] - fn apply(bp: BasisPointsSigned32) -> StoredF32 { - StoredF32::from(bp.to_f32()) - } -} diff --git a/crates/brk_computer/src/internal/transform/bps32_to_percent.rs b/crates/brk_computer/src/internal/transform/bps32_to_percent.rs deleted file mode 100644 index 63ed256c9..000000000 --- a/crates/brk_computer/src/internal/transform/bps32_to_percent.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{BasisPointsSigned32, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bps32ToPercent; - -impl UnaryTransform for Bps32ToPercent { - #[inline(always)] - fn apply(bp: BasisPointsSigned32) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/bps_to_float.rs b/crates/brk_computer/src/internal/transform/bps_to_float.rs new file mode 100644 index 000000000..8122186fd --- /dev/null +++ b/crates/brk_computer/src/internal/transform/bps_to_float.rs @@ -0,0 +1,38 @@ +use brk_types::{BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32}; +use vecdb::UnaryTransform; + +pub struct Bp16ToFloat; + +impl UnaryTransform for Bp16ToFloat { + #[inline(always)] + fn apply(bp: BasisPoints16) -> StoredF32 { + StoredF32::from(bp.to_f32()) + } +} + +pub struct Bp32ToFloat; + +impl UnaryTransform for Bp32ToFloat { + #[inline(always)] + fn apply(bp: BasisPoints32) -> StoredF32 { + StoredF32::from(bp.to_f32()) + } +} + +pub struct Bps16ToFloat; + +impl UnaryTransform for Bps16ToFloat { + #[inline(always)] + fn apply(bp: BasisPointsSigned16) -> StoredF32 { + StoredF32::from(bp.to_f32()) + } +} + +pub struct Bps32ToFloat; + +impl UnaryTransform for Bps32ToFloat { + #[inline(always)] + fn apply(bp: BasisPointsSigned32) -> StoredF32 { + StoredF32::from(bp.to_f32()) + } +} diff --git a/crates/brk_computer/src/internal/transform/bps_to_percent.rs b/crates/brk_computer/src/internal/transform/bps_to_percent.rs new file mode 100644 index 000000000..229cc2356 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/bps_to_percent.rs @@ -0,0 +1,29 @@ +use brk_types::{BasisPoints16, BasisPointsSigned16, BasisPointsSigned32, StoredF32}; +use vecdb::UnaryTransform; + +pub struct Bp16ToPercent; + +impl UnaryTransform for Bp16ToPercent { + #[inline(always)] + fn apply(bp: BasisPoints16) -> StoredF32 { + StoredF32::from(bp.inner() as f32 / 100.0) + } +} + +pub struct Bps16ToPercent; + +impl UnaryTransform for Bps16ToPercent { + #[inline(always)] + fn apply(bp: BasisPointsSigned16) -> StoredF32 { + StoredF32::from(bp.inner() as f32 / 100.0) + } +} + +pub struct Bps32ToPercent; + +impl UnaryTransform for Bps32ToPercent { + #[inline(always)] + fn apply(bp: BasisPointsSigned32) -> StoredF32 { + StoredF32::from(bp.inner() as f32 / 100.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/cents_convert.rs b/crates/brk_computer/src/internal/transform/cents_convert.rs new file mode 100644 index 000000000..ed1402113 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/cents_convert.rs @@ -0,0 +1,48 @@ +use brk_types::{Cents, CentsSigned, Dollars, Sats}; +use vecdb::UnaryTransform; + +/// CentsUnsigned -> Dollars (convert cents to dollars for display) +pub struct CentsUnsignedToDollars; + +impl UnaryTransform for CentsUnsignedToDollars { + #[inline(always)] + fn apply(cents: Cents) -> Dollars { + cents.into() + } +} + +/// Cents -> -Dollars (negate after converting to dollars) +/// Avoids lazy-from-lazy by combining both transforms. +pub struct NegCentsUnsignedToDollars; + +impl UnaryTransform for NegCentsUnsignedToDollars { + #[inline(always)] + fn apply(cents: Cents) -> Dollars { + -Dollars::from(cents) + } +} + +/// CentsSigned -> Dollars (convert signed cents to dollars for display) +pub struct CentsSignedToDollars; + +impl UnaryTransform for CentsSignedToDollars { + #[inline(always)] + fn apply(cents: CentsSigned) -> Dollars { + cents.into() + } +} + +/// CentsUnsigned -> Sats (sats per dollar: 1 BTC / price) +pub struct CentsUnsignedToSats; + +impl UnaryTransform for CentsUnsignedToSats { + #[inline(always)] + fn apply(cents: Cents) -> Sats { + let dollars = Dollars::from(cents); + if dollars == Dollars::ZERO { + Sats::ZERO + } else { + Sats::ONE_BTC / dollars + } + } +} diff --git a/crates/brk_computer/src/internal/transform/cents_halve.rs b/crates/brk_computer/src/internal/transform/cents_halve.rs deleted file mode 100644 index f5a204428..000000000 --- a/crates/brk_computer/src/internal/transform/cents_halve.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::Cents; -use vecdb::UnaryTransform; - -/// Cents -> Cents/2 (for supply_halved_cents) -pub struct HalveCents; - -impl UnaryTransform for HalveCents { - #[inline(always)] - fn apply(cents: Cents) -> Cents { - cents / 2u64 - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_signed_to_dollars.rs b/crates/brk_computer/src/internal/transform/cents_signed_to_dollars.rs deleted file mode 100644 index 151ca91d7..000000000 --- a/crates/brk_computer/src/internal/transform/cents_signed_to_dollars.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::{CentsSigned, Dollars}; -use vecdb::UnaryTransform; - -/// CentsSigned -> Dollars (convert signed cents to dollars for display) -pub struct CentsSignedToDollars; - -impl UnaryTransform for CentsSignedToDollars { - #[inline(always)] - fn apply(cents: CentsSigned) -> Dollars { - cents.into() - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_to_dollars.rs b/crates/brk_computer/src/internal/transform/cents_to_dollars.rs deleted file mode 100644 index b62cf003a..000000000 --- a/crates/brk_computer/src/internal/transform/cents_to_dollars.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::{Cents, Dollars}; -use vecdb::UnaryTransform; - -/// CentsUnsigned -> Dollars (convert cents to dollars for display) -pub struct CentsUnsignedToDollars; - -impl UnaryTransform for CentsUnsignedToDollars { - #[inline(always)] - fn apply(cents: Cents) -> Dollars { - cents.into() - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_to_sats.rs b/crates/brk_computer/src/internal/transform/cents_to_sats.rs deleted file mode 100644 index e407a7c64..000000000 --- a/crates/brk_computer/src/internal/transform/cents_to_sats.rs +++ /dev/null @@ -1,17 +0,0 @@ -use brk_types::{Cents, Dollars, Sats}; -use vecdb::UnaryTransform; - -/// CentsUnsigned -> Sats (sats per dollar: 1 BTC / price) -pub struct CentsUnsignedToSats; - -impl UnaryTransform for CentsUnsignedToSats { - #[inline(always)] - fn apply(cents: Cents) -> Sats { - let dollars = Dollars::from(cents); - if dollars == Dollars::ZERO { - Sats::ZERO - } else { - Sats::ONE_BTC / dollars - } - } -} diff --git a/crates/brk_computer/src/internal/transform/dollar_halve.rs b/crates/brk_computer/src/internal/transform/dollar_halve.rs deleted file mode 100644 index 43a4027eb..000000000 --- a/crates/brk_computer/src/internal/transform/dollar_halve.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::Dollars; -use vecdb::UnaryTransform; - -/// Dollars -> Dollars/2 (for supply_halved_usd) -pub struct HalveDollars; - -impl UnaryTransform for HalveDollars { - #[inline(always)] - fn apply(dollars: Dollars) -> Dollars { - dollars.halved() - } -} diff --git a/crates/brk_computer/src/internal/transform/halve.rs b/crates/brk_computer/src/internal/transform/halve.rs new file mode 100644 index 000000000..157c780d2 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/halve.rs @@ -0,0 +1,43 @@ +use brk_types::{Bitcoin, Cents, Dollars, Sats}; +use vecdb::UnaryTransform; + +/// Sats -> Sats/2 (for supply_halved) +pub struct HalveSats; + +impl UnaryTransform for HalveSats { + #[inline(always)] + fn apply(sats: Sats) -> Sats { + sats / 2 + } +} + +/// Sats -> Bitcoin/2 (halve then convert to bitcoin) +/// Avoids lazy-from-lazy by combining both transforms +pub struct HalveSatsToBitcoin; + +impl UnaryTransform for HalveSatsToBitcoin { + #[inline(always)] + fn apply(sats: Sats) -> Bitcoin { + Bitcoin::from(sats / 2) + } +} + +/// Cents -> Cents/2 (for supply_halved_cents) +pub struct HalveCents; + +impl UnaryTransform for HalveCents { + #[inline(always)] + fn apply(cents: Cents) -> Cents { + cents / 2u64 + } +} + +/// Dollars -> Dollars/2 (for supply_halved_usd) +pub struct HalveDollars; + +impl UnaryTransform for HalveDollars { + #[inline(always)] + fn apply(dollars: Dollars) -> Dollars { + dollars.halved() + } +} diff --git a/crates/brk_computer/src/internal/transform/mod.rs b/crates/brk_computer/src/internal/transform/mod.rs index c8bddf1b9..c287a410b 100644 --- a/crates/brk_computer/src/internal/transform/mod.rs +++ b/crates/brk_computer/src/internal/transform/mod.rs @@ -1,86 +1,43 @@ -mod bp16_to_float; -mod bp16_to_percent; -mod bp32_to_float; -mod bp32_to_percent; -mod bps16_to_float; -mod bps16_to_percent; -mod bps32_to_float; -mod bps32_to_percent; mod block_count_target; -mod cents_halve; -mod identity; +mod bps_to_float; +mod bps_to_percent; +mod cents_convert; mod cents_plus; -mod cents_signed_to_dollars; mod cents_subtract_to_cents_signed; mod cents_times_tenths; -mod cents_to_dollars; -mod cents_to_sats; -mod dollar_halve; +mod days_to_years; mod dollars_to_sats_fract; -mod neg_cents_to_dollars; -mod ohlc_cents_to_dollars; -mod ohlc_cents_to_sats; -mod percentage_diff_close_cents; -mod percentage_diff_close_dollars; -mod price_times_ratio_cents; -mod ratio32; -mod ratio_cents64; +mod halve; +mod identity; +mod ohlc; mod per_sec; -mod ratio_bp16; -mod ratio_bps16; -mod ratio_bps32; -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 price_times_ratio_cents; +mod ratio; +mod ratio_cents64; +mod return_const; mod sat_mask; mod sat_to_bitcoin; -mod days_to_years; +mod sats_to_cents; mod volatility; -pub use bp16_to_float::*; -pub use bp16_to_percent::*; -pub use bp32_to_float::*; -pub use bp32_to_percent::*; -pub use bps16_to_float::*; -pub use bps16_to_percent::*; -pub use bps32_to_float::*; -pub use bps32_to_percent::*; pub use block_count_target::*; -pub use cents_halve::*; -pub use identity::*; +pub use bps_to_float::*; +pub use bps_to_percent::*; +pub use cents_convert::*; pub use cents_plus::*; -pub use cents_signed_to_dollars::*; pub use cents_subtract_to_cents_signed::*; 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 dollar_halve::*; +pub use days_to_years::*; pub use dollars_to_sats_fract::*; -pub use percentage_diff_close_cents::*; -pub use percentage_diff_close_dollars::*; -pub use price_times_ratio_cents::*; -pub use ratio32::*; -pub use ratio_cents64::*; +pub use halve::*; +pub use identity::*; +pub use ohlc::*; pub use per_sec::*; -pub use ratio_bp16::*; -pub use ratio_bps16::*; -pub use ratio_bps32::*; -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 price_times_ratio_cents::*; +pub use ratio::*; +pub use ratio_cents64::*; +pub use return_const::*; pub use sat_mask::*; pub use sat_to_bitcoin::*; -pub use days_to_years::*; +pub use sats_to_cents::*; pub use volatility::*; diff --git a/crates/brk_computer/src/internal/transform/neg_cents_to_dollars.rs b/crates/brk_computer/src/internal/transform/neg_cents_to_dollars.rs deleted file mode 100644 index 5ef3b6d95..000000000 --- a/crates/brk_computer/src/internal/transform/neg_cents_to_dollars.rs +++ /dev/null @@ -1,13 +0,0 @@ -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 for NegCentsUnsignedToDollars { - #[inline(always)] - fn apply(cents: Cents) -> Dollars { - -Dollars::from(cents) - } -} diff --git a/crates/brk_computer/src/internal/transform/ohlc_cents_to_sats.rs b/crates/brk_computer/src/internal/transform/ohlc.rs similarity index 68% rename from crates/brk_computer/src/internal/transform/ohlc_cents_to_sats.rs rename to crates/brk_computer/src/internal/transform/ohlc.rs index 4df785c6b..8e471c150 100644 --- a/crates/brk_computer/src/internal/transform/ohlc_cents_to_sats.rs +++ b/crates/brk_computer/src/internal/transform/ohlc.rs @@ -1,8 +1,17 @@ -use brk_types::{Close, High, Low, OHLCCents, OHLCSats, Open}; +use brk_types::{Close, High, Low, OHLCCents, OHLCDollars, OHLCSats, Open}; use vecdb::UnaryTransform; use super::CentsUnsignedToSats; +pub struct OhlcCentsToDollars; + +impl UnaryTransform for OhlcCentsToDollars { + #[inline(always)] + fn apply(cents: OHLCCents) -> OHLCDollars { + OHLCDollars::from(cents) + } +} + /// OHLCCents -> OHLCSats with high/low swapped (inverse price relationship). pub struct OhlcCentsToSats; diff --git a/crates/brk_computer/src/internal/transform/ohlc_cents_to_dollars.rs b/crates/brk_computer/src/internal/transform/ohlc_cents_to_dollars.rs deleted file mode 100644 index 4e72e62b1..000000000 --- a/crates/brk_computer/src/internal/transform/ohlc_cents_to_dollars.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::{OHLCCents, OHLCDollars}; -use vecdb::UnaryTransform; - -pub struct OhlcCentsToDollars; - -impl UnaryTransform for OhlcCentsToDollars { - #[inline(always)] - fn apply(cents: OHLCCents) -> OHLCDollars { - OHLCDollars::from(cents) - } -} diff --git a/crates/brk_computer/src/internal/transform/percentage_diff_close_cents.rs b/crates/brk_computer/src/internal/transform/percentage_diff_close_cents.rs deleted file mode 100644 index 5e038eb99..000000000 --- a/crates/brk_computer/src/internal/transform/percentage_diff_close_cents.rs +++ /dev/null @@ -1,17 +0,0 @@ -use brk_types::{Cents, StoredF32}; -use vecdb::BinaryTransform; - -/// (Cents, Cents) -> StoredF32 percentage difference ((a/b - 1) * 100) -pub struct PercentageDiffCents; - -impl BinaryTransform 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) - } - } -} diff --git a/crates/brk_computer/src/internal/transform/percentage_diff_close_dollars.rs b/crates/brk_computer/src/internal/transform/percentage_diff_close_dollars.rs deleted file mode 100644 index 0d4ac860a..000000000 --- a/crates/brk_computer/src/internal/transform/percentage_diff_close_dollars.rs +++ /dev/null @@ -1,16 +0,0 @@ -use brk_types::{Dollars, StoredF32}; -use vecdb::BinaryTransform; - -/// (Dollars, Dollars) -> StoredF32 percentage difference ((a/b - 1) × 100) -pub struct PercentageDiffDollars; - -impl BinaryTransform for PercentageDiffDollars { - #[inline(always)] - fn apply(close: Dollars, base: Dollars) -> StoredF32 { - if base == Dollars::ZERO { - StoredF32::default() - } else { - StoredF32::from((*close / *base - 1.0) * 100.0) - } - } -} diff --git a/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs b/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs index 52d6c0d2c..9523f0709 100644 --- a/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs +++ b/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs @@ -1,4 +1,4 @@ -use brk_types::{Cents, StoredF32}; +use brk_types::{BasisPoints32, Cents, StoredF32}; use vecdb::BinaryTransform; pub struct PriceTimesRatioCents; @@ -9,3 +9,12 @@ impl BinaryTransform for PriceTimesRatioCents { Cents::from(f64::from(price) * f64::from(ratio)) } } + +pub struct PriceTimesRatioBp32Cents; + +impl BinaryTransform for PriceTimesRatioBp32Cents { + #[inline(always)] + fn apply(price: Cents, ratio: BasisPoints32) -> Cents { + Cents::from(f64::from(price) * f64::from(ratio)) + } +} diff --git a/crates/brk_computer/src/internal/transform/ratio.rs b/crates/brk_computer/src/internal/transform/ratio.rs new file mode 100644 index 000000000..06062c3a1 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/ratio.rs @@ -0,0 +1,197 @@ +use brk_types::{ + BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, Cents, CentsSigned, + Dollars, Sats, StoredF32, StoredU32, StoredU64, +}; +use vecdb::BinaryTransform; + +// === BasisPoints16 (unsigned) ratios === + +/// (StoredU64, StoredU64) -> BasisPoints16 ratio (a/b × 10000) +pub struct RatioU64Bp16; + +impl BinaryTransform for RatioU64Bp16 { + #[inline(always)] + fn apply(numerator: StoredU64, denominator: StoredU64) -> BasisPoints16 { + if *denominator > 0 { + BasisPoints16::from(*numerator as f64 / *denominator as f64) + } else { + BasisPoints16::ZERO + } + } +} + +/// (Sats, Sats) -> BasisPoints16 ratio (a/b × 10000) +pub struct RatioSatsBp16; + +impl BinaryTransform for RatioSatsBp16 { + #[inline(always)] + fn apply(numerator: Sats, denominator: Sats) -> BasisPoints16 { + if *denominator > 0 { + BasisPoints16::from(*numerator as f64 / *denominator as f64) + } else { + BasisPoints16::ZERO + } + } +} + +/// (Cents, Cents) -> BasisPoints16 ratio (a/b × 10000) +pub struct RatioCentsBp16; + +impl BinaryTransform for RatioCentsBp16 { + #[inline(always)] + fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 { + if denominator == Cents::ZERO { + BasisPoints16::ZERO + } else { + BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64) + } + } +} + +/// (StoredU32, StoredU32) -> BasisPoints16 ratio (a/b × 10000) +pub struct RatioU32Bp16; + +impl BinaryTransform for RatioU32Bp16 { + #[inline(always)] + fn apply(numerator: StoredU32, denominator: StoredU32) -> BasisPoints16 { + if *denominator > 0 { + BasisPoints16::from(*numerator as f64 / *denominator as f64) + } else { + BasisPoints16::ZERO + } + } +} + +/// (Dollars, Dollars) -> BasisPoints16 ratio (a/b × 10000) +pub struct RatioDollarsBp16; + +impl BinaryTransform for RatioDollarsBp16 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints16 { + let ratio = *(numerator / denominator); + if ratio.is_finite() { + BasisPoints16::from(ratio) + } else { + BasisPoints16::ZERO + } + } +} + +// === BasisPointsSigned16 (signed) ratios === + +/// (Dollars, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000) +pub struct RatioDollarsBps16; + +impl BinaryTransform for RatioDollarsBps16 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 { + let ratio = *(numerator / denominator); + if ratio.is_finite() { + BasisPointsSigned16::from(ratio) + } else { + BasisPointsSigned16::ZERO + } + } +} + +/// (Dollars, Dollars) -> BasisPointsSigned16 negated ratio (-(a/b) × 10000) +pub struct NegRatioDollarsBps16; + +impl BinaryTransform for NegRatioDollarsBps16 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 { + let ratio = *(numerator / denominator); + if ratio.is_finite() { + BasisPointsSigned16::from(-ratio) + } else { + BasisPointsSigned16::ZERO + } + } +} + +/// (CentsSigned, Cents) -> BasisPointsSigned16 ratio (a/b × 10000) +pub struct RatioCentsSignedCentsBps16; + +impl BinaryTransform for RatioCentsSignedCentsBps16 { + #[inline(always)] + fn apply(numerator: CentsSigned, denominator: Cents) -> BasisPointsSigned16 { + if denominator == Cents::ZERO { + BasisPointsSigned16::ZERO + } else { + BasisPointsSigned16::from(numerator.inner() as f64 / denominator.inner() as f64) + } + } +} + +/// (CentsSigned, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000) +pub struct RatioCentsSignedDollarsBps16; + +impl BinaryTransform for RatioCentsSignedDollarsBps16 { + #[inline(always)] + fn apply(numerator: CentsSigned, denominator: Dollars) -> BasisPointsSigned16 { + let d: f64 = denominator.into(); + if d > 0.0 { + BasisPointsSigned16::from(numerator.inner() as f64 / 100.0 / d) + } else { + BasisPointsSigned16::ZERO + } + } +} + +// === BasisPoints32 (unsigned) ratios === + +/// (Dollars, Dollars) -> BasisPoints32 ratio (a / b × 10000) +pub struct RatioDollarsBp32; + +impl BinaryTransform for RatioDollarsBp32 { + #[inline(always)] + fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints32 { + BasisPoints32::from(f64::from(numerator) / f64::from(denominator)) + } +} + +// === BasisPointsSigned32 (signed) ratio diffs === + +/// (StoredF32, StoredF32) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) +pub struct RatioDiffF32Bps32; + +impl BinaryTransform for RatioDiffF32Bps32 { + #[inline(always)] + fn apply(value: StoredF32, base: StoredF32) -> BasisPointsSigned32 { + if base.is_nan() || *base == 0.0 { + BasisPointsSigned32::ZERO + } else { + BasisPointsSigned32::from((*value / *base - 1.0) as f64) + } + } +} + +/// (Dollars, Dollars) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) +pub struct RatioDiffDollarsBps32; + +impl BinaryTransform for RatioDiffDollarsBps32 { + #[inline(always)] + fn apply(close: Dollars, base: Dollars) -> BasisPointsSigned32 { + let base_f64: f64 = base.into(); + if base_f64 == 0.0 { + BasisPointsSigned32::ZERO + } else { + BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0) + } + } +} + +/// (Cents, Cents) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) +pub struct RatioDiffCentsBps32; + +impl BinaryTransform for RatioDiffCentsBps32 { + #[inline(always)] + fn apply(close: Cents, base: Cents) -> BasisPointsSigned32 { + let base_f64 = f64::from(base); + if base_f64 == 0.0 { + BasisPointsSigned32::ZERO + } else { + BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0) + } + } +} diff --git a/crates/brk_computer/src/internal/transform/ratio32.rs b/crates/brk_computer/src/internal/transform/ratio32.rs deleted file mode 100644 index dfb44dd7f..000000000 --- a/crates/brk_computer/src/internal/transform/ratio32.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::{Dollars, StoredF32}; -use vecdb::BinaryTransform; - -/// (Dollars, Dollars) -> StoredF32 ratio -/// Used for computing percentage ratios like profit/total, loss/total, etc. -pub struct Ratio32; - -impl BinaryTransform for Ratio32 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 { - StoredF32::from(numerator / denominator) - } -} diff --git a/crates/brk_computer/src/internal/transform/ratio_bp16.rs b/crates/brk_computer/src/internal/transform/ratio_bp16.rs deleted file mode 100644 index 8bd87162f..000000000 --- a/crates/brk_computer/src/internal/transform/ratio_bp16.rs +++ /dev/null @@ -1,73 +0,0 @@ -use brk_types::{BasisPoints16, Cents, Dollars, Sats, StoredU32, StoredU64}; -use vecdb::BinaryTransform; - -/// (StoredU64, StoredU64) -> BasisPoints16 ratio (a/b × 10000) -pub struct RatioU64Bp16; - -impl BinaryTransform for RatioU64Bp16 { - #[inline(always)] - fn apply(numerator: StoredU64, denominator: StoredU64) -> BasisPoints16 { - if *denominator > 0 { - BasisPoints16::from(*numerator as f64 / *denominator as f64) - } else { - BasisPoints16::ZERO - } - } -} - -/// (Sats, Sats) -> BasisPoints16 ratio (a/b × 10000) -pub struct RatioSatsBp16; - -impl BinaryTransform for RatioSatsBp16 { - #[inline(always)] - fn apply(numerator: Sats, denominator: Sats) -> BasisPoints16 { - if *denominator > 0 { - BasisPoints16::from(*numerator as f64 / *denominator as f64) - } else { - BasisPoints16::ZERO - } - } -} - -/// (Cents, Cents) -> BasisPoints16 ratio (a/b × 10000) -pub struct RatioCentsBp16; - -impl BinaryTransform for RatioCentsBp16 { - #[inline(always)] - fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 { - if denominator == Cents::ZERO { - BasisPoints16::ZERO - } else { - BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64) - } - } -} - -/// (StoredU32, StoredU32) -> BasisPoints16 ratio (a/b × 10000) -pub struct RatioU32Bp16; - -impl BinaryTransform for RatioU32Bp16 { - #[inline(always)] - fn apply(numerator: StoredU32, denominator: StoredU32) -> BasisPoints16 { - if *denominator > 0 { - BasisPoints16::from(*numerator as f64 / *denominator as f64) - } else { - BasisPoints16::ZERO - } - } -} - -/// (Dollars, Dollars) -> BasisPoints16 ratio (a/b × 10000) -pub struct RatioDollarsBp16; - -impl BinaryTransform for RatioDollarsBp16 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints16 { - let ratio = *(numerator / denominator); - if ratio.is_finite() { - BasisPoints16::from(ratio) - } else { - BasisPoints16::ZERO - } - } -} diff --git a/crates/brk_computer/src/internal/transform/ratio_bps16.rs b/crates/brk_computer/src/internal/transform/ratio_bps16.rs deleted file mode 100644 index cb1715c5e..000000000 --- a/crates/brk_computer/src/internal/transform/ratio_bps16.rs +++ /dev/null @@ -1,62 +0,0 @@ -use brk_types::{BasisPointsSigned16, Cents, CentsSigned, Dollars}; -use vecdb::BinaryTransform; - -/// (Dollars, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000) -pub struct RatioDollarsBps16; - -impl BinaryTransform for RatioDollarsBps16 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 { - let ratio = *(numerator / denominator); - if ratio.is_finite() { - BasisPointsSigned16::from(ratio) - } else { - BasisPointsSigned16::ZERO - } - } -} - -/// (Dollars, Dollars) -> BasisPointsSigned16 negated ratio (-(a/b) × 10000) -pub struct NegRatioDollarsBps16; - -impl BinaryTransform for NegRatioDollarsBps16 { - #[inline(always)] - fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned16 { - let ratio = *(numerator / denominator); - if ratio.is_finite() { - BasisPointsSigned16::from(-ratio) - } else { - BasisPointsSigned16::ZERO - } - } -} - -/// (CentsSigned, Cents) -> BasisPointsSigned16 ratio (a/b × 10000) -pub struct RatioCentsSignedCentsBps16; - -impl BinaryTransform for RatioCentsSignedCentsBps16 { - #[inline(always)] - fn apply(numerator: CentsSigned, denominator: Cents) -> BasisPointsSigned16 { - if denominator == Cents::ZERO { - BasisPointsSigned16::ZERO - } else { - BasisPointsSigned16::from(numerator.inner() as f64 / denominator.inner() as f64) - } - } -} - -/// (CentsSigned, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000) -pub struct RatioCentsSignedDollarsBps16; - -impl BinaryTransform for RatioCentsSignedDollarsBps16 { - #[inline(always)] - fn apply(numerator: CentsSigned, denominator: Dollars) -> BasisPointsSigned16 { - let d: f64 = denominator.into(); - if d > 0.0 { - // Convert cents to dollars first, then compute ratio - BasisPointsSigned16::from(numerator.inner() as f64 / 100.0 / d) - } else { - BasisPointsSigned16::ZERO - } - } -} diff --git a/crates/brk_computer/src/internal/transform/ratio_bps32.rs b/crates/brk_computer/src/internal/transform/ratio_bps32.rs deleted file mode 100644 index 660fafab8..000000000 --- a/crates/brk_computer/src/internal/transform/ratio_bps32.rs +++ /dev/null @@ -1,32 +0,0 @@ -use brk_types::{BasisPointsSigned32, Cents, Dollars}; -use vecdb::BinaryTransform; - -/// (Dollars, Dollars) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) -pub struct RatioDiffDollarsBps32; - -impl BinaryTransform for RatioDiffDollarsBps32 { - #[inline(always)] - fn apply(close: Dollars, base: Dollars) -> BasisPointsSigned32 { - let base_f64: f64 = base.into(); - if base_f64 == 0.0 { - BasisPointsSigned32::ZERO - } else { - BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0) - } - } -} - -/// (Cents, Cents) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) -pub struct RatioDiffCentsBps32; - -impl BinaryTransform for RatioDiffCentsBps32 { - #[inline(always)] - fn apply(close: Cents, base: Cents) -> BasisPointsSigned32 { - let base_f64 = f64::from(base); - if base_f64 == 0.0 { - BasisPointsSigned32::ZERO - } else { - BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0) - } - } -} diff --git a/crates/brk_computer/src/internal/transform/ratio_u64_f32.rs b/crates/brk_computer/src/internal/transform/ratio_u64_f32.rs deleted file mode 100644 index cc8aaa262..000000000 --- a/crates/brk_computer/src/internal/transform/ratio_u64_f32.rs +++ /dev/null @@ -1,17 +0,0 @@ -use brk_types::{StoredF32, StoredU64}; -use vecdb::BinaryTransform; - -/// (StoredU64, StoredU64) -> StoredF32 ratio (a/b) -/// Used for adoption ratio calculations (script_count / total_outputs) -pub struct RatioU64F32; - -impl BinaryTransform for RatioU64F32 { - #[inline(always)] - fn apply(numerator: StoredU64, denominator: StoredU64) -> StoredF32 { - if *denominator > 0 { - StoredF32::from(*numerator as f64 / *denominator as f64) - } else { - StoredF32::from(0.0) - } - } -} diff --git a/crates/brk_computer/src/internal/transform/return_const.rs b/crates/brk_computer/src/internal/transform/return_const.rs new file mode 100644 index 000000000..8e738d88c --- /dev/null +++ b/crates/brk_computer/src/internal/transform/return_const.rs @@ -0,0 +1,32 @@ +use brk_types::{StoredF32, StoredI8, StoredU16}; +use vecdb::UnaryTransform; + +/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input. +pub struct ReturnF32Tenths; + +impl UnaryTransform for ReturnF32Tenths { + #[inline(always)] + fn apply(_: S) -> StoredF32 { + StoredF32::from(V as f32 / 10.0) + } +} + +/// Returns a constant u16 value, ignoring the input. +pub struct ReturnU16; + +impl UnaryTransform for ReturnU16 { + #[inline(always)] + fn apply(_: S) -> StoredU16 { + StoredU16::new(V) + } +} + +/// Returns a constant i8 value, ignoring the input. +pub struct ReturnI8; + +impl UnaryTransform for ReturnI8 { + #[inline(always)] + fn apply(_: S) -> StoredI8 { + StoredI8::new(V) + } +} diff --git a/crates/brk_computer/src/internal/transform/return_f32_tenths.rs b/crates/brk_computer/src/internal/transform/return_f32_tenths.rs deleted file mode 100644 index 521b2c432..000000000 --- a/crates/brk_computer/src/internal/transform/return_f32_tenths.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::StoredF32; -use vecdb::UnaryTransform; - -/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input. -pub struct ReturnF32Tenths; - -impl UnaryTransform for ReturnF32Tenths { - #[inline(always)] - fn apply(_: S) -> StoredF32 { - StoredF32::from(V as f32 / 10.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/return_i8.rs b/crates/brk_computer/src/internal/transform/return_i8.rs deleted file mode 100644 index caddb7b21..000000000 --- a/crates/brk_computer/src/internal/transform/return_i8.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::StoredI8; -use vecdb::UnaryTransform; - -/// Returns a constant i8 value, ignoring the input. -pub struct ReturnI8; - -impl UnaryTransform for ReturnI8 { - #[inline(always)] - fn apply(_: S) -> StoredI8 { - StoredI8::new(V) - } -} diff --git a/crates/brk_computer/src/internal/transform/return_u16.rs b/crates/brk_computer/src/internal/transform/return_u16.rs deleted file mode 100644 index d9fa8d642..000000000 --- a/crates/brk_computer/src/internal/transform/return_u16.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::StoredU16; -use vecdb::UnaryTransform; - -/// Returns a constant u16 value, ignoring the input. -pub struct ReturnU16; - -impl UnaryTransform for ReturnU16 { - #[inline(always)] - fn apply(_: S) -> StoredU16 { - StoredU16::new(V) - } -} diff --git a/crates/brk_computer/src/internal/transform/sat_halve.rs b/crates/brk_computer/src/internal/transform/sat_halve.rs deleted file mode 100644 index 4c57dfdb6..000000000 --- a/crates/brk_computer/src/internal/transform/sat_halve.rs +++ /dev/null @@ -1,12 +0,0 @@ -use brk_types::Sats; -use vecdb::UnaryTransform; - -/// Sats -> Sats/2 (for supply_halved) -pub struct HalveSats; - -impl UnaryTransform for HalveSats { - #[inline(always)] - fn apply(sats: Sats) -> Sats { - sats / 2 - } -} diff --git a/crates/brk_computer/src/internal/transform/sat_halve_to_bitcoin.rs b/crates/brk_computer/src/internal/transform/sat_halve_to_bitcoin.rs deleted file mode 100644 index 0438a6741..000000000 --- a/crates/brk_computer/src/internal/transform/sat_halve_to_bitcoin.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::{Bitcoin, Sats}; -use vecdb::UnaryTransform; - -/// Sats -> Bitcoin/2 (halve then convert to bitcoin) -/// Avoids lazy-from-lazy by combining both transforms -pub struct HalveSatsToBitcoin; - -impl UnaryTransform for HalveSatsToBitcoin { - #[inline(always)] - fn apply(sats: Sats) -> Bitcoin { - Bitcoin::from(sats / 2) - } -} diff --git a/crates/brk_computer/src/market/ath/compute.rs b/crates/brk_computer/src/market/ath/compute.rs index 50863f770..7c40f0d17 100644 --- a/crates/brk_computer/src/market/ath/compute.rs +++ b/crates/brk_computer/src/market/ath/compute.rs @@ -3,7 +3,7 @@ use brk_types::{StoredF32, Timestamp}; use vecdb::{Exit, ReadableVec, VecIndex}; use super::Vecs; -use crate::{blocks, ComputeIndexes, prices, traits::ComputeDrawdown}; +use crate::{blocks, ComputeIndexes, prices}; impl Vecs { pub(crate) fn compute( diff --git a/crates/brk_computer/src/market/ath/import.rs b/crates/brk_computer/src/market/ath/import.rs index 25326d8d6..78cbe9297 100644 --- a/crates/brk_computer/src/market/ath/import.rs +++ b/crates/brk_computer/src/market/ath/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{Bps16ToFloat, Bps16ToPercent, ComputedFromHeight, DaysToYears, LazyHeightDerived, PercentFromHeight, Price}, + internal::{ComputedFromHeight, DaysToYears, LazyHeightDerived, PercentFromHeight, Price}, }; const VERSION: Version = Version::ONE; @@ -40,7 +40,7 @@ impl Vecs { ); let price_drawdown = - PercentFromHeight::forced_import::(db, "price_drawdown", v, indexes)?; + PercentFromHeight::forced_import_bps16(db, "price_drawdown", v, indexes)?; Ok(Self { price_ath, diff --git a/crates/brk_computer/src/market/dca/import.rs b/crates/brk_computer/src/market/dca/import.rs index 8e148758a..082017bef 100644 --- a/crates/brk_computer/src/market/dca/import.rs +++ b/crates/brk_computer/src/market/dca/import.rs @@ -5,7 +5,7 @@ use vecdb::{Database, ImportableVec}; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, Vecs}; use crate::{ indexes, - internal::{Bps32ToFloat, Bps32ToPercent, PercentFromHeight, Price, ValueFromHeight}, + internal::{PercentFromHeight, Price, ValueFromHeight}, }; impl Vecs { @@ -23,7 +23,7 @@ impl Vecs { })?; let period_return = ByDcaPeriod::try_new(|name, _days| { - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps32( db, &format!("dca_return_{name}"), version, @@ -32,7 +32,7 @@ impl Vecs { })?; let period_cagr = ByDcaCagr::try_new(|name, _days| { - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps32( db, &format!("dca_cagr_{name}"), version, @@ -45,7 +45,7 @@ impl Vecs { })?; let period_lump_sum_return = ByDcaPeriod::try_new(|name, _days| { - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps32( db, &format!("lump_sum_return_{name}"), version, @@ -62,7 +62,7 @@ impl Vecs { })?; let class_return = ByDcaClass::try_new(|name, _year, _day1| { - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps32( db, &format!("dca_return_{name}"), version, diff --git a/crates/brk_computer/src/market/indicators/compute.rs b/crates/brk_computer/src/market/indicators/compute.rs index 3d1772681..c2adc4a13 100644 --- a/crates/brk_computer/src/market/indicators/compute.rs +++ b/crates/brk_computer/src/market/indicators/compute.rs @@ -1,11 +1,11 @@ use brk_error::Result; -use brk_types::{Dollars, StoredF32}; +use brk_types::{BasisPoints16, Dollars}; use vecdb::Exit; use super::{super::range, Vecs}; use crate::{ ComputeIndexes, blocks, distribution, - internal::{Ratio32, Windows}, + internal::{RatioDollarsBp32, Windows}, mining, prices, transactions, }; @@ -34,17 +34,17 @@ impl Vecs { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - self.puell_multiple.height.compute_divide( + self.puell_multiple.bps.compute_binary::( starting_indexes.height, &rewards.subsidy.base.usd.height, &rewards.subsidy_sma_1y.usd.height, exit, )?; - // Stochastic Oscillator: K = (close - low_2w) / (high_2w - low_2w) * 100 + // Stochastic Oscillator: K = (close - low_2w) / (high_2w - low_2w), stored as ratio (0–1) { let price = &prices.price.usd.height; - self.stoch_k.height.compute_transform3( + self.stoch_k.bps.height.compute_transform3( starting_indexes.height, price, &range.price_min_2w.usd.height, @@ -52,19 +52,19 @@ impl Vecs { |(h, close, low, high, ..)| { let range = *high - *low; let stoch = if range == 0.0 { - StoredF32::NAN + BasisPoints16::ZERO } else { - StoredF32::from(((*close - *low) / range * 100.0) as f32) + BasisPoints16::from(((*close - *low) / range) as f64) }; (h, stoch) }, exit, )?; - self.stoch_d.height.compute_rolling_average( + self.stoch_d.bps.height.compute_rolling_average( starting_indexes.height, &blocks.count.height_3d_ago, - &self.stoch_k.height, + &self.stoch_k.bps.height, exit, )?; } @@ -75,10 +75,10 @@ impl Vecs { { let m = tf_multiplier(tf); let returns_source = match tf { - "24h" => &returns.price_return._24h.height, - "1w" => &returns.price_return._1w.height, - "1m" => &returns.price_return._1m.height, - "1y" => &returns.price_return._1y.height, + "24h" => &returns.price_return._24h.ratio.height, + "1w" => &returns.price_return._1w.ratio.height, + "1m" => &returns.price_return._1m.ratio.height, + "1y" => &returns.price_return._1y.ratio.height, _ => unreachable!(), }; super::rsi::compute( @@ -118,7 +118,7 @@ impl Vecs { )?; // NVT: market_cap / tx_volume_24h - self.nvt.compute_binary::( + self.nvt.bps.compute_binary::( starting_indexes.height, &distribution.utxo_cohorts.all.metrics.supply.total.usd.height, &transactions.volume.sent_sum.rolling._24h.usd.height, @@ -126,7 +126,7 @@ impl Vecs { )?; // Pi Cycle: sma_111d / sma_350d_x2 - self.pi_cycle.compute_binary::( + self.pi_cycle.bps.compute_binary::( starting_indexes.height, &moving_average.price_sma_111d.price.usd.height, &moving_average.price_sma_350d_x2.usd.height, diff --git a/crates/brk_computer/src/market/indicators/import.rs b/crates/brk_computer/src/market/indicators/import.rs index 98225c869..2d12b07dd 100644 --- a/crates/brk_computer/src/market/indicators/import.rs +++ b/crates/brk_computer/src/market/indicators/import.rs @@ -5,7 +5,10 @@ use vecdb::Database; use super::{MacdChain, RsiChain, Vecs}; use crate::{ indexes, - internal::{Bp16ToFloat, Bp16ToPercent, ComputedFromHeight, PercentFromHeight, Windows}, + internal::{ + ComputedFromHeight, ComputedFromHeightRatio, + PercentFromHeight, Windows, + }, }; const VERSION: Version = Version::ONE; @@ -28,10 +31,21 @@ impl RsiChain { }; } + macro_rules! percent_import { + ($name:expr) => { + PercentFromHeight::forced_import_bp16( + db, + &format!("rsi_{}_{}", $name, tf), + version, + indexes, + )? + }; + } + let average_gain = import!("average_gain"); let average_loss = import!("average_loss"); - let rsi = ComputedFromHeight::forced_import( + let rsi = PercentFromHeight::forced_import_bp16( db, &format!("rsi_{tf}"), version, @@ -44,11 +58,11 @@ impl RsiChain { average_gain, average_loss, rsi, - rsi_min: import!("min"), - rsi_max: import!("max"), - stoch_rsi: import!("stoch"), - stoch_rsi_k: import!("stoch_k"), - stoch_rsi_d: import!("stoch_d"), + rsi_min: percent_import!("min"), + rsi_max: percent_import!("max"), + stoch_rsi: percent_import!("stoch"), + stoch_rsi_k: percent_import!("stoch_k"), + stoch_rsi_d: percent_import!("stoch_d"), }) } } @@ -108,19 +122,19 @@ impl Vecs { ) -> Result { let v = version + VERSION; - let nvt = ComputedFromHeight::forced_import(db, "nvt", v, indexes)?; + let nvt = ComputedFromHeightRatio::forced_import_raw(db, "nvt", v, indexes)?; let rsi = Windows::try_from_fn(|tf| RsiChain::forced_import(db, tf, v, indexes))?; let macd = Windows::try_from_fn(|tf| MacdChain::forced_import(db, tf, v, indexes))?; - let stoch_k = ComputedFromHeight::forced_import(db, "stoch_k", v, indexes)?; - let stoch_d = ComputedFromHeight::forced_import(db, "stoch_d", v, indexes)?; - let gini = PercentFromHeight::forced_import::(db, "gini", v, indexes)?; + let stoch_k = PercentFromHeight::forced_import_bp16(db, "stoch_k", v, indexes)?; + let stoch_d = PercentFromHeight::forced_import_bp16(db, "stoch_d", v, indexes)?; + let gini = PercentFromHeight::forced_import_bp16(db, "gini", v, indexes)?; - let pi_cycle = ComputedFromHeight::forced_import(db, "pi_cycle", v, indexes)?; + let pi_cycle = ComputedFromHeightRatio::forced_import_raw(db, "pi_cycle", v, indexes)?; Ok(Self { - puell_multiple: ComputedFromHeight::forced_import(db, "puell_multiple", v, indexes)?, + puell_multiple: ComputedFromHeightRatio::forced_import_raw(db, "puell_multiple", v, indexes)?, nvt, rsi, stoch_k, diff --git a/crates/brk_computer/src/market/indicators/rsi.rs b/crates/brk_computer/src/market/indicators/rsi.rs index 81663f867..41602f9c8 100644 --- a/crates/brk_computer/src/market/indicators/rsi.rs +++ b/crates/brk_computer/src/market/indicators/rsi.rs @@ -1,5 +1,5 @@ use brk_error::Result; -use brk_types::{Height, StoredF32}; +use brk_types::{BasisPoints16, Height, StoredF32}; use vecdb::{Exit, ReadableVec}; use super::RsiChain; @@ -49,46 +49,46 @@ pub(super) fn compute( exit, )?; - // RSI = 100 * avg_gain / (avg_gain + avg_loss) - chain.rsi.height.compute_transform2( + // RSI = avg_gain / (avg_gain + avg_loss), stored as ratio (0–1) + chain.rsi.bps.height.compute_transform2( starting_indexes.height, &chain.average_gain.height, &chain.average_loss.height, |(h, g, l, ..)| { let sum = *g + *l; - let rsi = if sum == 0.0 { 50.0 } else { 100.0 * *g / sum }; - (h, StoredF32::from(rsi)) + let rsi = if sum == 0.0 { 0.5 } else { *g / sum }; + (h, BasisPoints16::from(rsi as f64)) }, exit, )?; // Rolling min/max of RSI over rma_days window - chain.rsi_min.height.compute_rolling_min_from_starts( + chain.rsi_min.bps.height.compute_rolling_min_from_starts( starting_indexes.height, ws_rma, - &chain.rsi.height, + &chain.rsi.bps.height, exit, )?; - chain.rsi_max.height.compute_rolling_max_from_starts( + chain.rsi_max.bps.height.compute_rolling_max_from_starts( starting_indexes.height, ws_rma, - &chain.rsi.height, + &chain.rsi.bps.height, exit, )?; - // StochRSI = (rsi - rsi_min) / (rsi_max - rsi_min) * 100 - chain.stoch_rsi.height.compute_transform3( + // StochRSI = (rsi - rsi_min) / (rsi_max - rsi_min), stored as ratio (0–1) + chain.stoch_rsi.bps.height.compute_transform3( starting_indexes.height, - &chain.rsi.height, - &chain.rsi_min.height, - &chain.rsi_max.height, + &chain.rsi.bps.height, + &chain.rsi_min.bps.height, + &chain.rsi_max.bps.height, |(h, r, mn, mx, ..)| { - let range = *mx - *mn; + let range = f64::from(*mx) - f64::from(*mn); let stoch = if range == 0.0 { - StoredF32::NAN + BasisPoints16::ZERO } else { - StoredF32::from((*r - *mn) / range * 100.0) + BasisPoints16::from((f64::from(*r) - f64::from(*mn)) / range) }; (h, stoch) }, @@ -96,18 +96,18 @@ pub(super) fn compute( )?; // StochRSI K = SMA of StochRSI - chain.stoch_rsi_k.height.compute_rolling_average( + chain.stoch_rsi_k.bps.height.compute_rolling_average( starting_indexes.height, ws_sma, - &chain.stoch_rsi.height, + &chain.stoch_rsi.bps.height, exit, )?; // StochRSI D = SMA of K - chain.stoch_rsi_d.height.compute_rolling_average( + chain.stoch_rsi_d.bps.height.compute_rolling_average( starting_indexes.height, ws_sma, - &chain.stoch_rsi_k.height, + &chain.stoch_rsi_k.bps.height, exit, )?; diff --git a/crates/brk_computer/src/market/indicators/vecs.rs b/crates/brk_computer/src/market/indicators/vecs.rs index 0666b3afe..e56f44287 100644 --- a/crates/brk_computer/src/market/indicators/vecs.rs +++ b/crates/brk_computer/src/market/indicators/vecs.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::{BasisPoints16, StoredF32}; use vecdb::{Rw, StorageMode}; -use crate::internal::{ComputedFromHeight, PercentFromHeight, Windows}; +use crate::internal::{ComputedFromHeight, ComputedFromHeightRatio, PercentFromHeight, Windows}; #[derive(Traversable)] pub struct RsiChain { @@ -10,12 +10,12 @@ pub struct RsiChain { pub losses: ComputedFromHeight, pub average_gain: ComputedFromHeight, pub average_loss: ComputedFromHeight, - pub rsi: ComputedFromHeight, - pub rsi_min: ComputedFromHeight, - pub rsi_max: ComputedFromHeight, - pub stoch_rsi: ComputedFromHeight, - pub stoch_rsi_k: ComputedFromHeight, - pub stoch_rsi_d: ComputedFromHeight, + pub rsi: PercentFromHeight, + pub rsi_min: PercentFromHeight, + pub rsi_max: PercentFromHeight, + pub stoch_rsi: PercentFromHeight, + pub stoch_rsi_k: PercentFromHeight, + pub stoch_rsi_d: PercentFromHeight, } #[derive(Traversable)] @@ -29,15 +29,15 @@ pub struct MacdChain { #[derive(Traversable)] pub struct Vecs { - pub puell_multiple: ComputedFromHeight, - pub nvt: ComputedFromHeight, + pub puell_multiple: ComputedFromHeightRatio, + pub nvt: ComputedFromHeightRatio, pub rsi: Windows>, - pub stoch_k: ComputedFromHeight, - pub stoch_d: ComputedFromHeight, + pub stoch_k: PercentFromHeight, + pub stoch_d: PercentFromHeight, - pub pi_cycle: ComputedFromHeight, + pub pi_cycle: ComputedFromHeightRatio, pub macd: Windows>, diff --git a/crates/brk_computer/src/market/range/compute.rs b/crates/brk_computer/src/market/range/compute.rs index 3f35083e5..5c1230ea7 100644 --- a/crates/brk_computer/src/market/range/compute.rs +++ b/crates/brk_computer/src/market/range/compute.rs @@ -1,5 +1,5 @@ use brk_error::Result; -use brk_types::StoredF32; +use brk_types::{BasisPoints16, StoredF32}; use vecdb::{Exit, ReadableVec, VecIndex}; use super::Vecs; @@ -54,7 +54,7 @@ impl Vecs { exit, )?; - self.price_choppiness_index_2w.height.compute_transform4( + self.price_choppiness_index_2w.bps.height.compute_transform4( starting_indexes.height, &self.price_true_range_sum_2w.height, &self.price_max_2w.cents.height, @@ -64,11 +64,11 @@ impl Vecs { 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( - 100.0 * (*tr_sum / range as f32).log10() / n.log10(), + BasisPoints16::from( + (*tr_sum / range as f32).log10() as f64 / n.log10() as f64, ) } else { - StoredF32::NAN + BasisPoints16::ZERO }; (h, ci) }, diff --git a/crates/brk_computer/src/market/range/import.rs b/crates/brk_computer/src/market/range/import.rs index 2cf0564ba..f3ec8d77e 100644 --- a/crates/brk_computer/src/market/range/import.rs +++ b/crates/brk_computer/src/market/range/import.rs @@ -3,7 +3,7 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{indexes, internal::{ComputedFromHeight, Price}}; +use crate::{indexes, internal::{ComputedFromHeight, PercentFromHeight, Price}}; impl Vecs { pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { @@ -24,7 +24,7 @@ impl Vecs { price_true_range_sum_2w: ComputedFromHeight::forced_import( db, "price_true_range_sum_2w", version + v1, indexes, )?, - price_choppiness_index_2w: ComputedFromHeight::forced_import( + price_choppiness_index_2w: PercentFromHeight::forced_import_bp16( db, "price_choppiness_index_2w", version + v1, indexes, )?, }) diff --git a/crates/brk_computer/src/market/range/vecs.rs b/crates/brk_computer/src/market/range/vecs.rs index aa5907a32..cf4c73cfd 100644 --- a/crates/brk_computer/src/market/range/vecs.rs +++ b/crates/brk_computer/src/market/range/vecs.rs @@ -1,8 +1,8 @@ use brk_traversable::Traversable; -use brk_types::{Cents, StoredF32}; +use brk_types::{BasisPoints16, Cents, StoredF32}; use vecdb::{Rw, StorageMode}; -use crate::internal::{ComputedFromHeight, Price}; +use crate::internal::{ComputedFromHeight, PercentFromHeight, Price}; /// Price range and choppiness metrics #[derive(Traversable)] @@ -17,5 +17,5 @@ pub struct Vecs { pub price_max_1y: Price>, pub price_true_range: ComputedFromHeight, pub price_true_range_sum_2w: ComputedFromHeight, - pub price_choppiness_index_2w: ComputedFromHeight, + pub price_choppiness_index_2w: PercentFromHeight, } diff --git a/crates/brk_computer/src/market/returns/compute.rs b/crates/brk_computer/src/market/returns/compute.rs index 94ee28504..4a122981d 100644 --- a/crates/brk_computer/src/market/returns/compute.rs +++ b/crates/brk_computer/src/market/returns/compute.rs @@ -44,22 +44,22 @@ impl Vecs { )?; } - let _24h_price_return_height = &self.price_return._24h.bps.height; + let _24h_price_return_ratio = &self.price_return._24h.ratio.height; self.price_return_24h_sd_1w - .compute_all(blocks, starting_indexes, exit, _24h_price_return_height)?; + .compute_all(blocks, starting_indexes, exit, _24h_price_return_ratio)?; self.price_return_24h_sd_1m - .compute_all(blocks, starting_indexes, exit, _24h_price_return_height)?; + .compute_all(blocks, starting_indexes, exit, _24h_price_return_ratio)?; self.price_return_24h_sd_1y - .compute_all(blocks, starting_indexes, exit, _24h_price_return_height)?; + .compute_all(blocks, starting_indexes, exit, _24h_price_return_ratio)?; // Downside returns: min(return, 0) self.price_downside_24h.compute_transform( starting_indexes.height, - _24h_price_return_height, + _24h_price_return_ratio, |(i, ret, ..)| { - let v = f64::from(ret).min(0.0); - (i, StoredF32::from(v as f32)) + let v = f32::from(ret).min(0.0); + (i, StoredF32::from(v)) }, exit, )?; diff --git a/crates/brk_computer/src/market/returns/import.rs b/crates/brk_computer/src/market/returns/import.rs index 8ba4cee71..14c3c574e 100644 --- a/crates/brk_computer/src/market/returns/import.rs +++ b/crates/brk_computer/src/market/returns/import.rs @@ -6,7 +6,7 @@ use super::super::lookback::ByLookbackPeriod; use super::Vecs; use crate::{ indexes, - internal::{Bps32ToFloat, Bps32ToPercent, ComputedFromHeightStdDev, PercentFromHeight}, + internal::{ComputedFromHeightStdDev, PercentFromHeight}, market::dca::ByDcaCagr, }; @@ -19,7 +19,7 @@ impl Vecs { let v1 = Version::ONE; let price_return = ByLookbackPeriod::try_new(|name, _days| { - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps32( db, &format!("price_return_{name}"), version, @@ -29,7 +29,7 @@ impl Vecs { // CAGR (computed, 2y+ only) let price_cagr = ByDcaCagr::try_new(|name, _days| { - PercentFromHeight::forced_import::( + PercentFromHeight::forced_import_bps32( db, &format!("price_cagr_{name}"), version, diff --git a/crates/brk_computer/src/market/returns/vecs.rs b/crates/brk_computer/src/market/returns/vecs.rs index 412ed31fc..85bbe73d1 100644 --- a/crates/brk_computer/src/market/returns/vecs.rs +++ b/crates/brk_computer/src/market/returns/vecs.rs @@ -3,7 +3,7 @@ use brk_types::{BasisPointsSigned32, Height, StoredF32}; use vecdb::{EagerVec, PcoVec, Rw, StorageMode}; use crate::{ - internal::{ComputedFromHeight, ComputedFromHeightStdDev, PercentFromHeight}, + internal::{ComputedFromHeightStdDev, PercentFromHeight}, market::{dca::ByDcaCagr, lookback::ByLookbackPeriod}, }; diff --git a/crates/brk_computer/src/market/volatility/compute.rs b/crates/brk_computer/src/market/volatility/compute.rs index de08e6cb3..4ab2d0ad6 100644 --- a/crates/brk_computer/src/market/volatility/compute.rs +++ b/crates/brk_computer/src/market/volatility/compute.rs @@ -14,17 +14,17 @@ impl Vecs { ) -> Result<()> { // Sharpe ratios: returns / volatility for (out, ret, vol) in [ - (&mut self.price_sharpe_1w, &returns.price_return._1w.height, &self.price_volatility_1w.height), - (&mut self.price_sharpe_1m, &returns.price_return._1m.height, &self.price_volatility_1m.height), - (&mut self.price_sharpe_1y, &returns.price_return._1y.height, &self.price_volatility_1y.height), + (&mut self.price_sharpe_1w, &returns.price_return._1w.ratio.height, &self.price_volatility_1w.height), + (&mut self.price_sharpe_1m, &returns.price_return._1m.ratio.height, &self.price_volatility_1m.height), + (&mut self.price_sharpe_1y, &returns.price_return._1y.ratio.height, &self.price_volatility_1y.height), ] { compute_ratio(&mut out.height, starting_indexes_height, ret, vol, exit)?; } - // Sortino ratios: returns / downside volatility - compute_ratio(&mut self.price_sortino_1w.height, starting_indexes_height, &returns.price_return._1w.height, &returns.price_downside_24h_sd_1w.sd.height, exit)?; - compute_ratio(&mut self.price_sortino_1m.height, starting_indexes_height, &returns.price_return._1m.height, &returns.price_downside_24h_sd_1m.sd.height, exit)?; - compute_ratio(&mut self.price_sortino_1y.height, starting_indexes_height, &returns.price_return._1y.height, &returns.price_downside_24h_sd_1y.sd.height, exit)?; + // Sortino ratios: returns / downside volatility (sd * sqrt(days)) + compute_sortino(&mut self.price_sortino_1w.height, starting_indexes_height, &returns.price_return._1w.ratio.height, &returns.price_downside_24h_sd_1w.sd.height, 7.0_f32.sqrt(), exit)?; + compute_sortino(&mut self.price_sortino_1m.height, starting_indexes_height, &returns.price_return._1m.ratio.height, &returns.price_downside_24h_sd_1m.sd.height, 30.0_f32.sqrt(), exit)?; + compute_sortino(&mut self.price_sortino_1y.height, starting_indexes_height, &returns.price_return._1y.ratio.height, &returns.price_downside_24h_sd_1y.sd.height, 365.0_f32.sqrt(), exit)?; Ok(()) } @@ -49,3 +49,25 @@ fn compute_ratio( )?; Ok(()) } + +fn compute_sortino( + out: &mut EagerVec>, + starting_indexes_height: Height, + ret: &impl ReadableVec, + sd: &impl ReadableVec, + sqrt_days: f32, + exit: &Exit, +) -> Result<()> { + out.compute_transform2( + starting_indexes_height, + ret, + sd, + |(h, ret, sd, ..)| { + let downside_vol = f32::from(*sd) * sqrt_days; + let ratio = if downside_vol == 0.0 { 0.0 } else { f32::from(*ret) / downside_vol }; + (h, StoredF32::from(ratio)) + }, + exit, + )?; + Ok(()) +} diff --git a/crates/brk_computer/src/mining/hashrate/compute.rs b/crates/brk_computer/src/mining/hashrate/compute.rs index add44a014..e6171b379 100644 --- a/crates/brk_computer/src/mining/hashrate/compute.rs +++ b/crates/brk_computer/src/mining/hashrate/compute.rs @@ -5,8 +5,8 @@ use vecdb::{Exit, ReadableVec}; use super::Vecs; use crate::{ blocks::{self, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F64}, + internal::RatioDiffF32Bps32, ComputeIndexes, - traits::ComputeDrawdown, }; impl Vecs { @@ -151,8 +151,7 @@ impl Vecs { )?; self.hash_price_rebound - .height - .compute_percentage_difference( + .compute_binary::( starting_indexes.height, &self.hash_price_phs.height, &self.hash_price_phs_min.height, @@ -160,8 +159,7 @@ impl Vecs { )?; self.hash_value_rebound - .height - .compute_percentage_difference( + .compute_binary::( starting_indexes.height, &self.hash_value_phs.height, &self.hash_value_phs_min.height, diff --git a/crates/brk_computer/src/mining/hashrate/import.rs b/crates/brk_computer/src/mining/hashrate/import.rs index 1869cca77..3ac4d3074 100644 --- a/crates/brk_computer/src/mining/hashrate/import.rs +++ b/crates/brk_computer/src/mining/hashrate/import.rs @@ -5,7 +5,10 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{Bps16ToFloat, Bps16ToPercent, ComputedFromHeight, PercentFromHeight}, + internal::{ + ComputedFromHeight, + PercentFromHeight, + }, }; impl Vecs { @@ -49,7 +52,7 @@ impl Vecs { version, indexes, )?, - hash_rate_drawdown: PercentFromHeight::forced_import::( + hash_rate_drawdown: PercentFromHeight::forced_import_bps16( db, "hash_rate_drawdown", version, @@ -79,7 +82,7 @@ impl Vecs { version + v4, indexes, )?, - hash_price_rebound: ComputedFromHeight::forced_import( + hash_price_rebound: PercentFromHeight::forced_import_bps32( db, "hash_price_rebound", version + v4, @@ -109,7 +112,7 @@ impl Vecs { version + v4, indexes, )?, - hash_value_rebound: ComputedFromHeight::forced_import( + hash_value_rebound: PercentFromHeight::forced_import_bps32( db, "hash_value_rebound", version + v4, diff --git a/crates/brk_computer/src/mining/hashrate/vecs.rs b/crates/brk_computer/src/mining/hashrate/vecs.rs index 512c0d544..5480a3bf4 100644 --- a/crates/brk_computer/src/mining/hashrate/vecs.rs +++ b/crates/brk_computer/src/mining/hashrate/vecs.rs @@ -1,5 +1,5 @@ use brk_traversable::Traversable; -use brk_types::{BasisPointsSigned16, StoredF32, StoredF64}; +use brk_types::{BasisPointsSigned16, BasisPointsSigned32, StoredF32, StoredF64}; use vecdb::{Rw, StorageMode}; use crate::internal::{ComputedFromHeight, PercentFromHeight}; @@ -18,10 +18,10 @@ pub struct Vecs { pub hash_price_ths_min: ComputedFromHeight, pub hash_price_phs: ComputedFromHeight, pub hash_price_phs_min: ComputedFromHeight, - pub hash_price_rebound: ComputedFromHeight, + pub hash_price_rebound: PercentFromHeight, pub hash_value_ths: ComputedFromHeight, pub hash_value_ths_min: ComputedFromHeight, pub hash_value_phs: ComputedFromHeight, pub hash_value_phs_min: ComputedFromHeight, - pub hash_value_rebound: ComputedFromHeight, + pub hash_value_rebound: PercentFromHeight, } diff --git a/crates/brk_computer/src/mining/rewards/import.rs b/crates/brk_computer/src/mining/rewards/import.rs index f28cb24b1..1caa941c4 100644 --- a/crates/brk_computer/src/mining/rewards/import.rs +++ b/crates/brk_computer/src/mining/rewards/import.rs @@ -6,7 +6,7 @@ use super::Vecs; use crate::{ indexes, internal::{ - Bp16ToFloat, Bp16ToPercent, FiatFromHeight, PercentFromHeight, PercentRollingWindows, + FiatFromHeight, PercentFromHeight, PercentRollingWindows, ValueFromHeightFull, ValueFromHeightCumulativeSum, }, }; @@ -27,25 +27,25 @@ impl Vecs { version, indexes, )?, - fee_dominance: PercentFromHeight::forced_import::( + fee_dominance: PercentFromHeight::forced_import_bp16( db, "fee_dominance", version, indexes, )?, - fee_dominance_rolling: PercentRollingWindows::forced_import::( + fee_dominance_rolling: PercentRollingWindows::forced_import_bp16( db, "fee_dominance", version, indexes, )?, - subsidy_dominance: PercentFromHeight::forced_import::( + subsidy_dominance: PercentFromHeight::forced_import_bp16( db, "subsidy_dominance", version, indexes, )?, - subsidy_dominance_rolling: PercentRollingWindows::forced_import::( + subsidy_dominance_rolling: PercentRollingWindows::forced_import_bp16( db, "subsidy_dominance", version, diff --git a/crates/brk_computer/src/mining/rewards/vecs.rs b/crates/brk_computer/src/mining/rewards/vecs.rs index dcaa76b8f..2f6bcb6c8 100644 --- a/crates/brk_computer/src/mining/rewards/vecs.rs +++ b/crates/brk_computer/src/mining/rewards/vecs.rs @@ -3,7 +3,7 @@ use brk_types::{BasisPoints16, Cents}; use vecdb::{Rw, StorageMode}; use crate::internal::{ - FiatFromHeight, PercentFromHeight, PercentRollingWindows, RollingWindows, + FiatFromHeight, PercentFromHeight, PercentRollingWindows, ValueFromHeightFull, ValueFromHeightCumulativeSum, }; diff --git a/crates/brk_computer/src/pools/vecs.rs b/crates/brk_computer/src/pools/vecs.rs index 816a45d5a..8733f4955 100644 --- a/crates/brk_computer/src/pools/vecs.rs +++ b/crates/brk_computer/src/pools/vecs.rs @@ -7,7 +7,7 @@ use crate::{ blocks, indexes::{self, ComputeIndexes}, internal::{ - Bp16ToFloat, Bp16ToPercent, ComputedFromHeightCumulativeSum, ComputedFromHeight, MaskSats, + ComputedFromHeightCumulativeSum, ComputedFromHeight, MaskSats, PercentFromHeight, PercentRollingWindows, RatioU32Bp16, RollingWindows, ValueFromHeightCumulativeSum, }, @@ -58,9 +58,9 @@ impl Vecs { ValueFromHeightCumulativeSum::forced_import(db, &suffix("coinbase"), version, indexes)?; let dominance = - PercentFromHeight::forced_import::(db, &suffix("dominance"), version, indexes)?; + PercentFromHeight::forced_import_bp16(db, &suffix("dominance"), version, indexes)?; let dominance_rolling = - PercentRollingWindows::forced_import::(db, &suffix("dominance"), version, indexes)?; + PercentRollingWindows::forced_import_bp16(db, &suffix("dominance"), version, indexes)?; Ok(Self { dominance, diff --git a/crates/brk_computer/src/scripts/adoption.rs b/crates/brk_computer/src/scripts/adoption.rs index 067c9383c..4facee13f 100644 --- a/crates/brk_computer/src/scripts/adoption.rs +++ b/crates/brk_computer/src/scripts/adoption.rs @@ -5,7 +5,7 @@ use vecdb::{Database, Exit, Rw, StorageMode}; use crate::{ ComputeIndexes, indexes, - internal::{Bp16ToFloat, Bp16ToPercent, PercentFromHeight, RatioU64Bp16}, + internal::{PercentFromHeight, RatioU64Bp16}, outputs, }; @@ -24,13 +24,13 @@ impl Vecs { indexes: &indexes::Vecs, ) -> Result { Ok(Self { - taproot: PercentFromHeight::forced_import::( + taproot: PercentFromHeight::forced_import_bp16( db, "taproot_adoption", version, indexes, )?, - segwit: PercentFromHeight::forced_import::( + segwit: PercentFromHeight::forced_import_bp16( db, "segwit_adoption", version, diff --git a/crates/brk_computer/src/supply/import.rs b/crates/brk_computer/src/supply/import.rs index ca2f2bbfb..a6ae38487 100644 --- a/crates/brk_computer/src/supply/import.rs +++ b/crates/brk_computer/src/supply/import.rs @@ -9,7 +9,7 @@ use super::Vecs; use crate::{ distribution, indexes, internal::{ - Bps32ToFloat, Bps32ToPercent, ComputedFromHeight, Identity, LazyFromHeight, + ComputedFromHeight, Identity, LazyFromHeight, LazyValueFromHeight, PercentFromHeight, SatsToBitcoin, }, }; @@ -42,7 +42,7 @@ impl Vecs { // Inflation rate let inflation_rate = - PercentFromHeight::forced_import::(&db, "inflation_rate", version, indexes)?; + PercentFromHeight::forced_import_bps32(&db, "inflation_rate", version, indexes)?; // Velocity let velocity = super::velocity::Vecs::forced_import(&db, version, indexes)?; @@ -55,13 +55,13 @@ impl Vecs { ); // Growth rates - let market_cap_growth_rate = PercentFromHeight::forced_import::( + let market_cap_growth_rate = PercentFromHeight::forced_import_bps32( &db, "market_cap_growth_rate", version + Version::ONE, indexes, )?; - let realized_cap_growth_rate = PercentFromHeight::forced_import::( + let realized_cap_growth_rate = PercentFromHeight::forced_import_bps32( &db, "realized_cap_growth_rate", version + Version::ONE, diff --git a/crates/brk_computer/src/traits/mod.rs b/crates/brk_computer/src/traits/mod.rs index 467b366e9..6e390c53d 100644 --- a/crates/brk_computer/src/traits/mod.rs +++ b/crates/brk_computer/src/traits/mod.rs @@ -1,5 +1,5 @@ use brk_error::Result; -use brk_types::{BasisPointsSigned16, StoredF32}; +use brk_types::BasisPointsSigned16; use vecdb::{ AnyStoredVec, AnyVec, EagerVec, Exit, PcoVec, PcoVecValue, ReadableVec, VecIndex, VecValue, WritableVec, @@ -209,41 +209,6 @@ pub trait ComputeDrawdown { f64: From + From; } -impl ComputeDrawdown for EagerVec> -where - I: VecIndex, -{ - fn compute_drawdown( - &mut self, - max_from: I, - current: &impl ReadableVec, - ath: &impl ReadableVec, - exit: &Exit, - ) -> Result<()> - where - C: VecValue, - A: VecValue, - f64: From + From, - { - self.compute_transform2( - max_from, - current, - ath, - |(i, current, ath, _)| { - let ath_f64 = f64::from(ath); - let drawdown = if ath_f64 == 0.0 { - StoredF32::default() - } else { - StoredF32::from((f64::from(current) - ath_f64) / ath_f64 * 100.0) - }; - (i, drawdown) - }, - exit, - )?; - Ok(()) - } -} - impl ComputeDrawdown for EagerVec> where I: VecIndex, diff --git a/crates/brk_types/src/basis_points_16.rs b/crates/brk_types/src/basis_points_16.rs index 097e44c42..819cf8984 100644 --- a/crates/brk_types/src/basis_points_16.rs +++ b/crates/brk_types/src/basis_points_16.rs @@ -71,7 +71,17 @@ impl From for u16 { } } -/// Convert from float: multiply by 10000 and round. +/// Convert from f32: multiply by 10000 and round. +/// Input is in ratio form (e.g., 0.4523 for 45.23%). +impl From for BasisPoints16 { + #[inline] + fn from(value: f32) -> Self { + debug_assert!(value >= 0.0 && value <= u16::MAX as f32 / 10000.0, "f32 out of BasisPoints16 range: {value}"); + Self((value * 10000.0).round() as u16) + } +} + +/// Convert from f64: multiply by 10000 and round. /// Input is in ratio form (e.g., 0.4523 for 45.23%). impl From for BasisPoints16 { #[inline] diff --git a/crates/brk_types/src/cents.rs b/crates/brk_types/src/cents.rs index f16ab2496..4e3527d89 100644 --- a/crates/brk_types/src/cents.rs +++ b/crates/brk_types/src/cents.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco}; -use super::{CentsSats, Dollars, Sats}; +use super::{CentsSats, Dollars, Sats, StoredF64}; /// Unsigned cents (u64) - for values that should never be negative. /// Used for invested capital, realized cap, etc. @@ -226,6 +226,14 @@ impl Mul for Cents { } } +impl Mul for Cents { + type Output = Self; + #[inline] + fn mul(self, rhs: StoredF64) -> Self::Output { + Self::from(f64::from(self) * f64::from(rhs)) + } +} + impl Mul for Cents { type Output = CentsSats; #[inline] diff --git a/crates/brk_types/src/weight.rs b/crates/brk_types/src/weight.rs index 53b6cb5cf..d44bda0fe 100644 --- a/crates/brk_types/src/weight.rs +++ b/crates/brk_types/src/weight.rs @@ -45,10 +45,10 @@ impl Weight { bitcoin::Weight::from(*self).to_vbytes_floor() } - /// Returns block fullness as a percentage (0-100+) relative to MAX_BLOCK. + /// Returns block fullness as a ratio (0–1+) relative to MAX_BLOCK. #[inline] pub fn fullness(&self) -> f32 { - (self.0 as f64 / Self::MAX_BLOCK.0 as f64 * 100.0) as f32 + (self.0 as f64 / Self::MAX_BLOCK.0 as f64) as f32 } }