mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -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::<Bps32ToFloat, Bps32ToPercent>(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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub weight: ComputedHeightDerivedFull<Weight, M>,
|
||||
pub fullness: ComputedFromHeightDistribution<StoredF32, M>,
|
||||
pub fullness: PercentFromHeightDistribution<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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<Self> {
|
||||
Ok(Self {
|
||||
cointime_adj_inflation_rate: PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
cointime_adj_inflation_rate: PercentFromHeight::forced_import_bps32(
|
||||
db,
|
||||
"cointime_adj_inflation_rate",
|
||||
version,
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub all: ComputedFromHeightDistribution<StoredF32, M>,
|
||||
pub all: PercentFromHeightDistribution<BasisPoints16, M>,
|
||||
#[traversable(flatten)]
|
||||
pub by_addresstype: ByAddressType<ComputedFromHeightDistribution<StoredF32, M>>,
|
||||
pub by_addresstype: ByAddressType<PercentFromHeightDistribution<BasisPoints16, M>>,
|
||||
}
|
||||
|
||||
impl GrowthRateVecs {
|
||||
@@ -27,22 +27,21 @@ impl GrowthRateVecs {
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let all = ComputedFromHeightDistribution::forced_import(
|
||||
let all = PercentFromHeightDistribution::forced_import_bp16(
|
||||
db,
|
||||
"growth_rate",
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
let by_addresstype: ByAddressType<ComputedFromHeightDistribution<StoredF32>> =
|
||||
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<PcoVec<Height, StoredF32>>,
|
||||
target: &mut EagerVec<PcoVec<Height, BasisPoints16>>,
|
||||
max_from: Height,
|
||||
numerator: &impl ReadableVec<Height, StoredU64>,
|
||||
denominator: &impl ReadableVec<Height, StoredU64>,
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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<Rw> {
|
||||
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<Rw> {
|
||||
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)?;
|
||||
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub invested_capital: PercentilesVecs<M>,
|
||||
|
||||
/// What percentile of cost basis is below spot (sat-weighted)
|
||||
pub spot_cost_basis_percentile: ComputedFromHeight<StoredF32, M>,
|
||||
pub spot_cost_basis_percentile: PercentFromHeight<BasisPoints16, M>,
|
||||
|
||||
/// What percentile of invested capital is below spot (USD-weighted)
|
||||
pub spot_invested_capital_percentile: ComputedFromHeight<StoredF32, M>,
|
||||
pub spot_invested_capital_percentile: PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
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(())
|
||||
|
||||
@@ -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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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::<Identity<StoredF32>>(
|
||||
let mvrv = LazyFromHeight::from_lazy::<Identity<StoredF32>, 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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
PercentFromHeight::forced_import_bps16(
|
||||
cfg.db,
|
||||
&cfg.name("net_pnl_change_1m_rel_to_market_cap"),
|
||||
cfg.version + v3,
|
||||
|
||||
@@ -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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
realized_cap_rel_to_own_market_cap: PercentFromHeight::forced_import_bp16(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap_rel_to_own_market_cap"),
|
||||
cfg.version,
|
||||
|
||||
@@ -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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
PercentFromHeight::forced_import_bp16(
|
||||
cfg.db, &cfg.name("invested_capital_in_loss_rel_to_realized_cap"), cfg.version, cfg.indexes,
|
||||
)?,
|
||||
})
|
||||
|
||||
@@ -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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
PercentFromHeight::forced_import_bps16(
|
||||
cfg.db,
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
|
||||
@@ -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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
PercentFromHeight::forced_import_bps16(
|
||||
cfg.db,
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_gross_pnl"),
|
||||
cfg.version + v2,
|
||||
|
||||
@@ -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<Self> {
|
||||
Ok(Self {
|
||||
supply_rel_to_circulating_supply:
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
PercentFromHeight::forced_import_bp16(
|
||||
cfg.db,
|
||||
&cfg.name("supply_in_loss_rel_to_circulating_supply"),
|
||||
cfg.version + brk_types::Version::ONE,
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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<B, M: StorageMode = Rw>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub bps: ComputedFromHeight<B, M>,
|
||||
pub float: LazyFromHeight<StoredF32, B>,
|
||||
}
|
||||
|
||||
impl<B> Float32FromHeight<B>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import<F: UnaryTransform<B, StoredF32>>(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let bps = ComputedFromHeight::forced_import(db, name, version, indexes)?;
|
||||
|
||||
let float = LazyFromHeight::from_computed::<F>(
|
||||
&format!("{name}_float"),
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
&bps,
|
||||
);
|
||||
|
||||
Ok(Self { bps, float })
|
||||
}
|
||||
|
||||
pub(crate) fn compute_binary<S1T, S2T, F>(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
source1: &impl ReadableVec<Height, S1T>,
|
||||
source2: &impl ReadableVec<Height, S2T>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
S1T: VecValue,
|
||||
S2T: VecValue,
|
||||
F: BinaryTransform<S1T, S2T, B>,
|
||||
{
|
||||
self.bps.compute_binary::<S1T, S2T, F>(max_from, source1, source2, exit)
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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<B, StoredF32>,
|
||||
PercentTransform: UnaryTransform<B, StoredF32>,
|
||||
{
|
||||
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::<RatioTransform>(
|
||||
&format!("{name}_ratio"),
|
||||
@@ -54,7 +59,7 @@ where
|
||||
);
|
||||
|
||||
let percent = LazyFromHeight::from_computed::<PercentTransform>(
|
||||
&format!("{name}_percent"),
|
||||
name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
&bps,
|
||||
@@ -63,6 +68,45 @@ where
|
||||
Ok(Self { bps, ratio, percent })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PercentFromHeight<BasisPoints16> {
|
||||
pub(crate) fn forced_import_bp16(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
|
||||
}
|
||||
}
|
||||
|
||||
impl PercentFromHeight<BasisPointsSigned16> {
|
||||
pub(crate) fn forced_import_bps16(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Self::forced_import::<Bps16ToFloat, Bps16ToPercent>(db, name, version, indexes)
|
||||
}
|
||||
}
|
||||
|
||||
impl PercentFromHeight<BasisPointsSigned32> {
|
||||
pub(crate) fn forced_import_bps32(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Self::forced_import::<Bps32ToFloat, Bps32ToPercent>(db, name, version, indexes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> PercentFromHeight<B>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn compute_binary<S1T, S2T, F>(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
|
||||
@@ -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<B, M: StorageMode = Rw>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub bps: ComputedFromHeightDistribution<B, M>,
|
||||
pub ratio: LazyFromHeight<StoredF32, B>,
|
||||
pub percent: LazyFromHeight<StoredF32, B>,
|
||||
}
|
||||
|
||||
impl<B> PercentFromHeightDistribution<B>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import<RatioTransform, PercentTransform>(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self>
|
||||
where
|
||||
RatioTransform: UnaryTransform<B, StoredF32>,
|
||||
PercentTransform: UnaryTransform<B, StoredF32>,
|
||||
{
|
||||
let bps = ComputedFromHeightDistribution::forced_import(db, &format!("{name}_bps"), version, indexes)?;
|
||||
|
||||
let ratio = LazyFromHeight::from_height_source::<RatioTransform>(
|
||||
&format!("{name}_ratio"),
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
let percent = LazyFromHeight::from_height_source::<PercentTransform>(
|
||||
name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
Ok(Self { bps, ratio, percent })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PercentFromHeightDistribution<BasisPoints16> {
|
||||
pub(crate) fn forced_import_bp16(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> PercentFromHeightDistribution<B>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
exit: &Exit,
|
||||
compute_height: impl FnOnce(&mut EagerVec<PcoVec<Height, B>>) -> Result<()>,
|
||||
) -> Result<()>
|
||||
where
|
||||
B: Copy + Ord + From<f64> + Default,
|
||||
f64: From<B>,
|
||||
{
|
||||
self.bps.compute(max_from, windows, exit, compute_height)
|
||||
}
|
||||
}
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub ratio_sma_1w: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_sma_1m: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_pct99: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_pct98: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_pct95: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_pct5: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_pct2: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_pct1: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_sma_1w: ComputedFromHeightRatio<M>,
|
||||
pub ratio_sma_1m: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct99: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct98: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct95: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct5: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct2: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct1: ComputedFromHeightRatio<M>,
|
||||
pub ratio_pct99_price: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub ratio_pct98_price: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub ratio_pct95_price: Price<ComputedFromHeight<Cents, M>>,
|
||||
@@ -47,9 +47,9 @@ impl ComputedFromHeightRatioExtension {
|
||||
) -> Result<Self> {
|
||||
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<Height, StoredF32>,
|
||||
) -> 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<PcoVec<Height, StoredF32>>; 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<PcoVec<Height, BasisPoints32>>; 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<Height, Cents>,
|
||||
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::<Cents, StoredF32, PriceTimesRatioCents>(
|
||||
.compute_binary::<Cents, BasisPoints32, PriceTimesRatioBp32Cents>(
|
||||
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<Item = &mut EagerVec<PcoVec<Height, StoredF32>>> {
|
||||
) -> impl Iterator<Item = &mut EagerVec<PcoVec<Height, BasisPoints32>>> {
|
||||
[
|
||||
&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()
|
||||
}
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub ratio: ComputedFromHeight<StoredF32, M>,
|
||||
pub bps: ComputedFromHeight<BasisPoints32, M>,
|
||||
pub ratio: LazyFromHeight<StoredF32, BasisPoints32>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO;
|
||||
@@ -28,12 +29,28 @@ impl ComputedFromHeightRatio {
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
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<Self> {
|
||||
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::<Bp32ToFloat>(
|
||||
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<Height, Cents>,
|
||||
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,
|
||||
|
||||
@@ -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<BasisPoints16> {
|
||||
pub(crate) fn forced_import_bp16(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> PercentRollingEmas1w1m<B>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn compute_from_24h(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
|
||||
@@ -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<BasisPoints16> {
|
||||
pub(crate) fn forced_import_bp16(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Self::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, name, version, indexes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPoints16, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp16ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPoints16, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp16ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPoints32, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp32ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPoints32, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp32ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints32) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPointsSigned16, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bps16ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPointsSigned16, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bps16ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPointsSigned32, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bps32ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{BasisPointsSigned32, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bps32ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
38
crates/brk_computer/src/internal/transform/bps_to_float.rs
Normal file
38
crates/brk_computer/src/internal/transform/bps_to_float.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use brk_types::{BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp16ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bp32ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps16ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps32ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
29
crates/brk_computer/src/internal/transform/bps_to_percent.rs
Normal file
29
crates/brk_computer/src/internal/transform/bps_to_percent.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use brk_types::{BasisPoints16, BasisPointsSigned16, BasisPointsSigned32, StoredF32};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp16ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps16ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps32ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
}
|
||||
}
|
||||
48
crates/brk_computer/src/internal/transform/cents_convert.rs
Normal file
48
crates/brk_computer/src/internal/transform/cents_convert.rs
Normal file
@@ -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<Cents, Dollars> 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<Cents, Dollars> 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<CentsSigned, Dollars> for CentsSignedToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: CentsSigned) -> Dollars {
|
||||
cents.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// CentsUnsigned -> Sats (sats per dollar: 1 BTC / price)
|
||||
pub struct CentsUnsignedToSats;
|
||||
|
||||
impl UnaryTransform<Cents, Sats> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::Cents;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Cents -> Cents/2 (for supply_halved_cents)
|
||||
pub struct HalveCents;
|
||||
|
||||
impl UnaryTransform<Cents, Cents> for HalveCents {
|
||||
#[inline(always)]
|
||||
fn apply(cents: Cents) -> Cents {
|
||||
cents / 2u64
|
||||
}
|
||||
}
|
||||
@@ -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<CentsSigned, Dollars> for CentsSignedToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: CentsSigned) -> Dollars {
|
||||
cents.into()
|
||||
}
|
||||
}
|
||||
@@ -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<Cents, Dollars> for CentsUnsignedToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: Cents) -> Dollars {
|
||||
cents.into()
|
||||
}
|
||||
}
|
||||
@@ -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<Cents, Sats> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::Dollars;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Dollars -> Dollars/2 (for supply_halved_usd)
|
||||
pub struct HalveDollars;
|
||||
|
||||
impl UnaryTransform<Dollars, Dollars> for HalveDollars {
|
||||
#[inline(always)]
|
||||
fn apply(dollars: Dollars) -> Dollars {
|
||||
dollars.halved()
|
||||
}
|
||||
}
|
||||
43
crates/brk_computer/src/internal/transform/halve.rs
Normal file
43
crates/brk_computer/src/internal/transform/halve.rs
Normal file
@@ -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<Sats, Sats> 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<Sats, Bitcoin> 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<Cents, Cents> for HalveCents {
|
||||
#[inline(always)]
|
||||
fn apply(cents: Cents) -> Cents {
|
||||
cents / 2u64
|
||||
}
|
||||
}
|
||||
|
||||
/// Dollars -> Dollars/2 (for supply_halved_usd)
|
||||
pub struct HalveDollars;
|
||||
|
||||
impl UnaryTransform<Dollars, Dollars> for HalveDollars {
|
||||
#[inline(always)]
|
||||
fn apply(dollars: Dollars) -> Dollars {
|
||||
dollars.halved()
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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<Cents, Dollars> for NegCentsUnsignedToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: Cents) -> Dollars {
|
||||
-Dollars::from(cents)
|
||||
}
|
||||
}
|
||||
@@ -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<OHLCCents, OHLCDollars> for OhlcCentsToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: OHLCCents) -> OHLCDollars {
|
||||
OHLCDollars::from(cents)
|
||||
}
|
||||
}
|
||||
|
||||
/// OHLCCents -> OHLCSats with high/low swapped (inverse price relationship).
|
||||
pub struct OhlcCentsToSats;
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
use brk_types::{OHLCCents, OHLCDollars};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct OhlcCentsToDollars;
|
||||
|
||||
impl UnaryTransform<OHLCCents, OHLCDollars> for OhlcCentsToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: OHLCCents) -> OHLCDollars {
|
||||
OHLCDollars::from(cents)
|
||||
}
|
||||
}
|
||||
@@ -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<Cents, Cents, StoredF32> for PercentageDiffCents {
|
||||
#[inline(always)]
|
||||
fn apply(close: Cents, base: Cents) -> StoredF32 {
|
||||
let base_f64 = f64::from(base);
|
||||
if base_f64 == 0.0 {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from((f64::from(close) / base_f64 - 1.0) * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,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<Dollars, Dollars, StoredF32> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Cents, StoredF32, Cents> for PriceTimesRatioCents {
|
||||
Cents::from(f64::from(price) * f64::from(ratio))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PriceTimesRatioBp32Cents;
|
||||
|
||||
impl BinaryTransform<Cents, BasisPoints32, Cents> for PriceTimesRatioBp32Cents {
|
||||
#[inline(always)]
|
||||
fn apply(price: Cents, ratio: BasisPoints32) -> Cents {
|
||||
Cents::from(f64::from(price) * f64::from(ratio))
|
||||
}
|
||||
}
|
||||
|
||||
197
crates/brk_computer/src/internal/transform/ratio.rs
Normal file
197
crates/brk_computer/src/internal/transform/ratio.rs
Normal file
@@ -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<StoredU64, StoredU64, BasisPoints16> 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<Sats, Sats, BasisPoints16> 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<Cents, Cents, BasisPoints16> 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<StoredU32, StoredU32, BasisPoints16> 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<Dollars, Dollars, BasisPoints16> 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<Dollars, Dollars, BasisPointsSigned16> 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<Dollars, Dollars, BasisPointsSigned16> 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<CentsSigned, Cents, BasisPointsSigned16> 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<CentsSigned, Dollars, BasisPointsSigned16> 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<Dollars, Dollars, BasisPoints32> 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<StoredF32, StoredF32, BasisPointsSigned32> 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<Dollars, Dollars, BasisPointsSigned32> 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<Cents, Cents, BasisPointsSigned32> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Dollars, Dollars, StoredF32> for Ratio32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 {
|
||||
StoredF32::from(numerator / denominator)
|
||||
}
|
||||
}
|
||||
@@ -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<StoredU64, StoredU64, BasisPoints16> 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<Sats, Sats, BasisPoints16> 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<Cents, Cents, BasisPoints16> 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<StoredU32, StoredU32, BasisPoints16> 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<Dollars, Dollars, BasisPoints16> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Dollars, Dollars, BasisPointsSigned16> 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<Dollars, Dollars, BasisPointsSigned16> 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<CentsSigned, Cents, BasisPointsSigned16> 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<CentsSigned, Dollars, BasisPointsSigned16> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Dollars, Dollars, BasisPointsSigned32> 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<Cents, Cents, BasisPointsSigned32> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<StoredU64, StoredU64, StoredF32> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
32
crates/brk_computer/src/internal/transform/return_const.rs
Normal file
32
crates/brk_computer/src/internal/transform/return_const.rs
Normal file
@@ -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<const V: u16>;
|
||||
|
||||
impl<S, const V: u16> UnaryTransform<S, StoredF32> for ReturnF32Tenths<V> {
|
||||
#[inline(always)]
|
||||
fn apply(_: S) -> StoredF32 {
|
||||
StoredF32::from(V as f32 / 10.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a constant u16 value, ignoring the input.
|
||||
pub struct ReturnU16<const V: u16>;
|
||||
|
||||
impl<S, const V: u16> UnaryTransform<S, StoredU16> for ReturnU16<V> {
|
||||
#[inline(always)]
|
||||
fn apply(_: S) -> StoredU16 {
|
||||
StoredU16::new(V)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a constant i8 value, ignoring the input.
|
||||
pub struct ReturnI8<const V: i8>;
|
||||
|
||||
impl<S, const V: i8> UnaryTransform<S, StoredI8> for ReturnI8<V> {
|
||||
#[inline(always)]
|
||||
fn apply(_: S) -> StoredI8 {
|
||||
StoredI8::new(V)
|
||||
}
|
||||
}
|
||||
@@ -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<const V: u16>;
|
||||
|
||||
impl<S, const V: u16> UnaryTransform<S, StoredF32> for ReturnF32Tenths<V> {
|
||||
#[inline(always)]
|
||||
fn apply(_: S) -> StoredF32 {
|
||||
StoredF32::from(V as f32 / 10.0)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::StoredI8;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Returns a constant i8 value, ignoring the input.
|
||||
pub struct ReturnI8<const V: i8>;
|
||||
|
||||
impl<S, const V: i8> UnaryTransform<S, StoredI8> for ReturnI8<V> {
|
||||
#[inline(always)]
|
||||
fn apply(_: S) -> StoredI8 {
|
||||
StoredI8::new(V)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::StoredU16;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Returns a constant u16 value, ignoring the input.
|
||||
pub struct ReturnU16<const V: u16>;
|
||||
|
||||
impl<S, const V: u16> UnaryTransform<S, StoredU16> for ReturnU16<V> {
|
||||
#[inline(always)]
|
||||
fn apply(_: S) -> StoredU16 {
|
||||
StoredU16::new(V)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use brk_types::Sats;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
/// Sats -> Sats/2 (for supply_halved)
|
||||
pub struct HalveSats;
|
||||
|
||||
impl UnaryTransform<Sats, Sats> for HalveSats {
|
||||
#[inline(always)]
|
||||
fn apply(sats: Sats) -> Sats {
|
||||
sats / 2
|
||||
}
|
||||
}
|
||||
@@ -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<Sats, Bitcoin> for HalveSatsToBitcoin {
|
||||
#[inline(always)]
|
||||
fn apply(sats: Sats) -> Bitcoin {
|
||||
Bitcoin::from(sats / 2)
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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::<Bps16ToFloat, Bps16ToPercent>(db, "price_drawdown", v, indexes)?;
|
||||
PercentFromHeight::forced_import_bps16(db, "price_drawdown", v, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
price_ath,
|
||||
|
||||
@@ -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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
PercentFromHeight::forced_import_bps32(
|
||||
db,
|
||||
&format!("dca_return_{name}"),
|
||||
version,
|
||||
|
||||
@@ -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::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
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::<Dollars, Dollars, Ratio32>(
|
||||
self.nvt.bps.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
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::<Dollars, Dollars, Ratio32>(
|
||||
self.pi_cycle.bps.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
starting_indexes.height,
|
||||
&moving_average.price_sma_111d.price.usd.height,
|
||||
&moving_average.price_sma_350d_x2.usd.height,
|
||||
|
||||
@@ -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<Self> {
|
||||
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::<Bp16ToFloat, Bp16ToPercent>(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,
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
@@ -10,12 +10,12 @@ pub struct RsiChain<M: StorageMode = Rw> {
|
||||
pub losses: ComputedFromHeight<StoredF32, M>,
|
||||
pub average_gain: ComputedFromHeight<StoredF32, M>,
|
||||
pub average_loss: ComputedFromHeight<StoredF32, M>,
|
||||
pub rsi: ComputedFromHeight<StoredF32, M>,
|
||||
pub rsi_min: ComputedFromHeight<StoredF32, M>,
|
||||
pub rsi_max: ComputedFromHeight<StoredF32, M>,
|
||||
pub stoch_rsi: ComputedFromHeight<StoredF32, M>,
|
||||
pub stoch_rsi_k: ComputedFromHeight<StoredF32, M>,
|
||||
pub stoch_rsi_d: ComputedFromHeight<StoredF32, M>,
|
||||
pub rsi: PercentFromHeight<BasisPoints16, M>,
|
||||
pub rsi_min: PercentFromHeight<BasisPoints16, M>,
|
||||
pub rsi_max: PercentFromHeight<BasisPoints16, M>,
|
||||
pub stoch_rsi: PercentFromHeight<BasisPoints16, M>,
|
||||
pub stoch_rsi_k: PercentFromHeight<BasisPoints16, M>,
|
||||
pub stoch_rsi_d: PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -29,15 +29,15 @@ pub struct MacdChain<M: StorageMode = Rw> {
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub puell_multiple: ComputedFromHeight<StoredF32, M>,
|
||||
pub nvt: ComputedFromHeight<StoredF32, M>,
|
||||
pub puell_multiple: ComputedFromHeightRatio<M>,
|
||||
pub nvt: ComputedFromHeightRatio<M>,
|
||||
|
||||
pub rsi: Windows<RsiChain<M>>,
|
||||
|
||||
pub stoch_k: ComputedFromHeight<StoredF32, M>,
|
||||
pub stoch_d: ComputedFromHeight<StoredF32, M>,
|
||||
pub stoch_k: PercentFromHeight<BasisPoints16, M>,
|
||||
pub stoch_d: PercentFromHeight<BasisPoints16, M>,
|
||||
|
||||
pub pi_cycle: ComputedFromHeight<StoredF32, M>,
|
||||
pub pi_cycle: ComputedFromHeightRatio<M>,
|
||||
|
||||
pub macd: Windows<MacdChain<M>>,
|
||||
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
|
||||
@@ -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<Self> {
|
||||
@@ -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,
|
||||
)?,
|
||||
})
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub price_max_1y: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_true_range: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_true_range_sum_2w: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_choppiness_index_2w: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_choppiness_index_2w: PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
PercentFromHeight::forced_import_bps32(
|
||||
db,
|
||||
&format!("price_cagr_{name}"),
|
||||
version,
|
||||
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
|
||||
@@ -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<PcoVec<Height, StoredF32>>,
|
||||
starting_indexes_height: Height,
|
||||
ret: &impl ReadableVec<Height, StoredF32>,
|
||||
sd: &impl ReadableVec<Height, StoredF32>,
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -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::<StoredF32, StoredF32, RatioDiffF32Bps32>(
|
||||
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::<StoredF32, StoredF32, RatioDiffF32Bps32>(
|
||||
starting_indexes.height,
|
||||
&self.hash_value_phs.height,
|
||||
&self.hash_value_phs_min.height,
|
||||
|
||||
@@ -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::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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,
|
||||
|
||||
@@ -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<M: StorageMode = Rw> {
|
||||
pub hash_price_ths_min: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_price_phs: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_price_phs_min: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_price_rebound: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_price_rebound: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
pub hash_value_ths: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_value_ths_min: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_value_phs: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_value_phs_min: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_value_rebound: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_value_rebound: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
}
|
||||
|
||||
@@ -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::<Bp16ToFloat, Bp16ToPercent>(
|
||||
fee_dominance: PercentFromHeight::forced_import_bp16(
|
||||
db,
|
||||
"fee_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
fee_dominance_rolling: PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
fee_dominance_rolling: PercentRollingWindows::forced_import_bp16(
|
||||
db,
|
||||
"fee_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
subsidy_dominance: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
subsidy_dominance: PercentFromHeight::forced_import_bp16(
|
||||
db,
|
||||
"subsidy_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
subsidy_dominance_rolling: PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
subsidy_dominance_rolling: PercentRollingWindows::forced_import_bp16(
|
||||
db,
|
||||
"subsidy_dominance",
|
||||
version,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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::<Bp16ToFloat, Bp16ToPercent>(db, &suffix("dominance"), version, indexes)?;
|
||||
PercentFromHeight::forced_import_bp16(db, &suffix("dominance"), version, indexes)?;
|
||||
let dominance_rolling =
|
||||
PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, &suffix("dominance"), version, indexes)?;
|
||||
PercentRollingWindows::forced_import_bp16(db, &suffix("dominance"), version, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
dominance,
|
||||
|
||||
@@ -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<Self> {
|
||||
Ok(Self {
|
||||
taproot: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
taproot: PercentFromHeight::forced_import_bp16(
|
||||
db,
|
||||
"taproot_adoption",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
segwit: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
segwit: PercentFromHeight::forced_import_bp16(
|
||||
db,
|
||||
"segwit_adoption",
|
||||
version,
|
||||
|
||||
@@ -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::<Bps32ToFloat, Bps32ToPercent>(&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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
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::<Bps32ToFloat, Bps32ToPercent>(
|
||||
let realized_cap_growth_rate = PercentFromHeight::forced_import_bps32(
|
||||
&db,
|
||||
"realized_cap_growth_rate",
|
||||
version + Version::ONE,
|
||||
|
||||
@@ -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<I: VecIndex> {
|
||||
f64: From<C> + From<A>;
|
||||
}
|
||||
|
||||
impl<I> ComputeDrawdown<I> for EagerVec<PcoVec<I, StoredF32>>
|
||||
where
|
||||
I: VecIndex,
|
||||
{
|
||||
fn compute_drawdown<C, A>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
current: &impl ReadableVec<I, C>,
|
||||
ath: &impl ReadableVec<I, A>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
C: VecValue,
|
||||
A: VecValue,
|
||||
f64: From<C> + From<A>,
|
||||
{
|
||||
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<I> ComputeDrawdown<I> for EagerVec<PcoVec<I, BasisPointsSigned16>>
|
||||
where
|
||||
I: VecIndex,
|
||||
|
||||
Reference in New Issue
Block a user