mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-25 15:19:58 -07:00
global: snapshot
This commit is contained in:
@@ -162,8 +162,8 @@ impl Vecs {
|
||||
// Compute rolling window block counts (both block_count's own rolling + separate block_count_sum)
|
||||
let ws = WindowStarts {
|
||||
_24h: &self.height_24h_ago,
|
||||
_7d: &self.height_1w_ago,
|
||||
_30d: &self.height_1m_ago,
|
||||
_1w: &self.height_1w_ago,
|
||||
_1m: &self.height_1m_ago,
|
||||
_1y: &self.height_1y_ago,
|
||||
};
|
||||
self.block_count.sum.compute_rolling_sum(
|
||||
|
||||
@@ -59,12 +59,12 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
/// Get the standard 4 rolling window start heights (24h, 7d, 30d, 1y).
|
||||
/// Get the standard 4 rolling window start heights (24h, 1w, 1m, 1y).
|
||||
pub fn window_starts(&self) -> WindowStarts<'_> {
|
||||
WindowStarts {
|
||||
_24h: &self.height_24h_ago,
|
||||
_7d: &self.height_1w_ago,
|
||||
_30d: &self.height_1m_ago,
|
||||
_1w: &self.height_1w_ago,
|
||||
_1m: &self.height_1m_ago,
|
||||
_1y: &self.height_1y_ago,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Compute difficulty adjustment percentage
|
||||
self.adjustment.height.compute_percentage_change(
|
||||
// Compute difficulty adjustment ratio: (current - previous) / previous
|
||||
self.adjustment.bps.height.compute_ratio_change(
|
||||
starting_indexes.height,
|
||||
&indexer.vecs.blocks.difficulty,
|
||||
1,
|
||||
|
||||
@@ -6,7 +6,7 @@ use vecdb::{Database, ReadableCloneableVec};
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeight, ComputedHeightDerived},
|
||||
internal::{Bps32ToFloat, Bps32ToPercent, ComputedFromHeight, ComputedHeightDerived, PercentFromHeight},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -26,7 +26,7 @@ impl Vecs {
|
||||
indexes,
|
||||
),
|
||||
as_hash: ComputedFromHeight::forced_import(db, "difficulty_as_hash", version, indexes)?,
|
||||
adjustment: ComputedFromHeight::forced_import(db, "difficulty_adjustment", version, indexes)?,
|
||||
adjustment: PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(db, "difficulty_adjustment", version, indexes)?,
|
||||
epoch: ComputedFromHeight::forced_import(db, "difficulty_epoch", version, indexes)?,
|
||||
blocks_before_next_adjustment: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{DifficultyEpoch, StoredF32, StoredF64, StoredU32};
|
||||
use brk_types::{BasisPointsSigned32, DifficultyEpoch, StoredF32, StoredF64, StoredU32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeight, ComputedHeightDerived};
|
||||
use crate::internal::{ComputedFromHeight, ComputedHeightDerived, PercentFromHeight};
|
||||
|
||||
/// Difficulty metrics: raw difficulty, derived stats, adjustment, and countdown
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub raw: ComputedHeightDerived<StoredF64>,
|
||||
pub as_hash: ComputedFromHeight<StoredF64, M>,
|
||||
pub adjustment: ComputedFromHeight<StoredF32, M>,
|
||||
pub adjustment: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
pub epoch: ComputedFromHeight<DifficultyEpoch, M>,
|
||||
pub blocks_before_next_adjustment: ComputedFromHeight<StoredU32, M>,
|
||||
pub days_before_next_adjustment: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{StoredF32, StoredF64};
|
||||
use brk_types::{BasisPointsSigned32, StoredF64};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::super::activity;
|
||||
@@ -14,15 +14,15 @@ impl Vecs {
|
||||
activity: &activity::Vecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.cointime_adj_inflation_rate.height.compute_transform2(
|
||||
self.cointime_adj_inflation_rate.bps.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&activity.activity_to_vaultedness_ratio.height,
|
||||
&supply.inflation.height,
|
||||
|(h, ratio, inflation, ..)| (h, StoredF32::from((*ratio) * f64::from(*inflation))),
|
||||
&supply.inflation_rate.bps.height,
|
||||
|(h, ratio, inflation, ..)| (h, BasisPointsSigned32::from((*ratio) * f64::from(inflation))),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cointime_adj_tx_btc_velocity
|
||||
self.cointime_adj_tx_velocity_btc
|
||||
.height
|
||||
.compute_transform2(
|
||||
starting_indexes.height,
|
||||
@@ -32,7 +32,7 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cointime_adj_tx_usd_velocity
|
||||
self.cointime_adj_tx_velocity_usd
|
||||
.height
|
||||
.compute_transform2(
|
||||
starting_indexes.height,
|
||||
|
||||
@@ -3,26 +3,29 @@ use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{indexes, internal::ComputedFromHeight};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{Bps32ToFloat, Bps32ToPercent, ComputedFromHeight, PercentFromHeight},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
|
||||
Ok(Self {
|
||||
cointime_adj_inflation_rate: ComputedFromHeight::forced_import(
|
||||
cointime_adj_inflation_rate: PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
"cointime_adj_inflation_rate",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
cointime_adj_tx_btc_velocity: ComputedFromHeight::forced_import(
|
||||
cointime_adj_tx_velocity_btc: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
"cointime_adj_tx_btc_velocity",
|
||||
"cointime_adj_tx_velocity_btc",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
cointime_adj_tx_usd_velocity: ComputedFromHeight::forced_import(
|
||||
cointime_adj_tx_velocity_usd: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
"cointime_adj_tx_usd_velocity",
|
||||
"cointime_adj_tx_velocity_usd",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, StoredF64};
|
||||
use brk_types::{BasisPointsSigned32, StoredF64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::ComputedFromHeight;
|
||||
use crate::internal::{ComputedFromHeight, PercentFromHeight};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub cointime_adj_inflation_rate: ComputedFromHeight<StoredF32, M>,
|
||||
pub cointime_adj_tx_btc_velocity: ComputedFromHeight<StoredF64, M>,
|
||||
pub cointime_adj_tx_usd_velocity: ComputedFromHeight<StoredF64, M>,
|
||||
pub cointime_adj_inflation_rate: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
pub cointime_adj_tx_velocity_btc: ComputedFromHeight<StoredF64, M>,
|
||||
pub cointime_adj_tx_velocity_usd: ComputedFromHeight<StoredF64, M>,
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
value: &value::Vecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.vocdd_365d_median.compute_rolling_median_from_starts(
|
||||
self.vocdd_median_1y.compute_rolling_median_from_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1y_ago,
|
||||
&value.vocdd.height,
|
||||
@@ -24,7 +24,7 @@ impl Vecs {
|
||||
self.hodl_bank.compute_cumulative_transformed_binary(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&self.vocdd_365d_median,
|
||||
&self.vocdd_median_1y,
|
||||
|price, median| StoredF64::from(f64::from(price) - f64::from(median)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -13,7 +13,7 @@ impl Vecs {
|
||||
) -> Result<Self> {
|
||||
let v1 = version + Version::ONE;
|
||||
Ok(Self {
|
||||
vocdd_365d_median: EagerVec::forced_import(db, "vocdd_365d_median", v1)?,
|
||||
vocdd_median_1y: EagerVec::forced_import(db, "vocdd_median_1y", v1)?,
|
||||
hodl_bank: EagerVec::forced_import(db, "hodl_bank", v1)?,
|
||||
reserve_risk: ComputedFromHeight::forced_import(db, "reserve_risk", v1, indexes)?,
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::internal::ComputedFromHeight;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub vocdd_365d_median: M::Stored<EagerVec<PcoVec<Height, StoredF64>>>,
|
||||
pub vocdd_median_1y: M::Stored<EagerVec<PcoVec<Height, StoredF64>>>,
|
||||
pub hodl_bank: M::Stored<EagerVec<PcoVec<Height, StoredF64>>>,
|
||||
pub reserve_risk: ComputedFromHeight<StoredF64, M>,
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ use vecdb::{
|
||||
|
||||
use crate::{ComputeIndexes, blocks, indexes, internal::ComputedFromHeight};
|
||||
|
||||
/// Address count with 30d change metric for a single type.
|
||||
/// Address count with 1m change metric for a single type.
|
||||
#[derive(Traversable)]
|
||||
pub struct AddrCountVecs<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub count: ComputedFromHeight<StoredU64, M>,
|
||||
pub _30d_change: ComputedFromHeight<StoredF64, M>,
|
||||
pub change_1m: ComputedFromHeight<StoredF64, M>,
|
||||
}
|
||||
|
||||
impl AddrCountVecs {
|
||||
@@ -28,9 +28,9 @@ impl AddrCountVecs {
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
count: ComputedFromHeight::forced_import(db, name, version, indexes)?,
|
||||
_30d_change: ComputedFromHeight::forced_import(
|
||||
change_1m: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&format!("{name}_30d_change"),
|
||||
&format!("{name}_change_1m"),
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
@@ -43,7 +43,7 @@ impl AddrCountVecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self._30d_change.height.compute_rolling_change(
|
||||
self.change_1m.height.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.count.height,
|
||||
@@ -85,7 +85,7 @@ impl From<(&AddressTypeToAddrCountVecs, Height)> for AddressTypeToAddressCount {
|
||||
}
|
||||
}
|
||||
|
||||
/// Address count per address type, with height + derived indexes + 30d change.
|
||||
/// Address count per address type, with height + derived indexes + 1m change.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct AddressTypeToAddrCountVecs<M: StorageMode = Rw>(ByAddressType<AddrCountVecs<M>>);
|
||||
|
||||
@@ -290,7 +290,7 @@ impl AddrCountsVecs {
|
||||
.height
|
||||
.compute_sum_of_others(starting_indexes.height, &sources, exit)?;
|
||||
|
||||
self.all._30d_change.height.compute_rolling_change(
|
||||
self.all.change_1m.height.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.all.count.height,
|
||||
|
||||
@@ -99,9 +99,9 @@ impl AddressCohorts {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// 1. Compute addr_count_30d_change using rolling window
|
||||
// 1. Compute addr_count_change_1m using rolling window
|
||||
self.par_iter_mut().try_for_each(|v| {
|
||||
v.addr_count_30d_change.height.compute_rolling_change(
|
||||
v.addr_count_change_1m.height.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&v.addr_count.height,
|
||||
|
||||
@@ -36,7 +36,7 @@ pub struct AddressCohortVecs<M: StorageMode = Rw> {
|
||||
pub metrics: BasicCohortMetrics<M>,
|
||||
|
||||
pub addr_count: ComputedFromHeight<StoredU64, M>,
|
||||
pub addr_count_30d_change: ComputedFromHeight<StoredF64, M>,
|
||||
pub addr_count_change_1m: ComputedFromHeight<StoredF64, M>,
|
||||
}
|
||||
|
||||
impl AddressCohortVecs {
|
||||
@@ -73,9 +73,9 @@ impl AddressCohortVecs {
|
||||
version + VERSION,
|
||||
indexes,
|
||||
)?,
|
||||
addr_count_30d_change: ComputedFromHeight::forced_import(
|
||||
addr_count_change_1m: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&cfg.name("addr_count_30d_change"),
|
||||
&cfg.name("addr_count_change_1m"),
|
||||
version + VERSION,
|
||||
indexes,
|
||||
)?,
|
||||
|
||||
@@ -6,7 +6,7 @@ use vecdb::{AnyStoredVec, AnyVec, EagerVec, Exit, ImportableVec, PcoVec, Rw, Sto
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
internal::{ComputedFromHeightCumulativeSum, ValueFromHeightCumulative, ValueFromHeight},
|
||||
internal::{ComputedFromHeightCumulativeSum, RollingEmas2w, ValueFromHeightCumulative},
|
||||
};
|
||||
|
||||
use super::ImportConfig;
|
||||
@@ -18,7 +18,7 @@ pub struct ActivityMetrics<M: StorageMode = Rw> {
|
||||
pub sent: ValueFromHeightCumulative<M>,
|
||||
|
||||
/// 14-day EMA of sent supply (sats, btc, usd)
|
||||
pub sent_14d_ema: ValueFromHeight<M>,
|
||||
pub sent_ema: RollingEmas2w<M>,
|
||||
|
||||
/// Satoshi-blocks destroyed (supply * blocks_old when spent)
|
||||
pub satblocks_destroyed: M::Stored<EagerVec<PcoVec<Height, Sats>>>,
|
||||
@@ -44,9 +44,9 @@ impl ActivityMetrics {
|
||||
cfg.indexes,
|
||||
)?,
|
||||
|
||||
sent_14d_ema: ValueFromHeight::forced_import(
|
||||
sent_ema: RollingEmas2w::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("sent_14d_ema"),
|
||||
&cfg.name("sent"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -166,7 +166,7 @@ impl ActivityMetrics {
|
||||
let window_starts = blocks.count.window_starts();
|
||||
|
||||
// 14-day EMA of sent (sats and dollars)
|
||||
self.sent_14d_ema.compute_ema(
|
||||
self.sent_ema.compute(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent.base.sats.height,
|
||||
|
||||
@@ -26,13 +26,13 @@ impl CostBasisBase {
|
||||
Ok(Self {
|
||||
min: Price::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("min_cost_basis"),
|
||||
&cfg.name("cost_basis_min"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
max: Price::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("max_cost_basis"),
|
||||
&cfg.name("cost_basis_max"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
|
||||
@@ -12,7 +12,7 @@ use super::ImportConfig;
|
||||
#[derive(Traversable)]
|
||||
pub struct OutputsMetrics<M: StorageMode = Rw> {
|
||||
pub utxo_count: ComputedFromHeight<StoredU64, M>,
|
||||
pub utxo_count_30d_change: ComputedFromHeight<StoredF64, M>,
|
||||
pub utxo_count_change_1m: ComputedFromHeight<StoredF64, M>,
|
||||
}
|
||||
|
||||
impl OutputsMetrics {
|
||||
@@ -25,9 +25,9 @@ impl OutputsMetrics {
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
utxo_count_30d_change: ComputedFromHeight::forced_import(
|
||||
utxo_count_change_1m: ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("utxo_count_30d_change"),
|
||||
&cfg.name("utxo_count_change_1m"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -77,7 +77,7 @@ impl OutputsMetrics {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.utxo_count_30d_change.height.compute_rolling_change(
|
||||
self.utxo_count_change_1m.height.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.utxo_count.height,
|
||||
|
||||
@@ -5,7 +5,7 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
internal::{ComputedFromHeight, RatioCents64, RollingEmas7d30d, RollingWindows},
|
||||
internal::{ComputedFromHeight, RatioCents64, RollingEmas1w1m, RollingWindows},
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
@@ -23,7 +23,7 @@ pub struct RealizedAdjusted<M: StorageMode = Rw> {
|
||||
|
||||
// === Adjusted SOPR (rolling window ratios) ===
|
||||
pub adjusted_sopr: RollingWindows<StoredF64, M>,
|
||||
pub adjusted_sopr_ema: RollingEmas7d30d<StoredF64, M>,
|
||||
pub adjusted_sopr_ema: RollingEmas1w1m<StoredF64, M>,
|
||||
}
|
||||
|
||||
impl RealizedAdjusted {
|
||||
@@ -52,7 +52,7 @@ impl RealizedAdjusted {
|
||||
let adjusted_sopr = RollingWindows::forced_import(
|
||||
cfg.db, &cfg.name("adjusted_sopr"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
let adjusted_sopr_ema = RollingEmas7d30d::forced_import(
|
||||
let adjusted_sopr_ema = RollingEmas1w1m::forced_import(
|
||||
cfg.db, &cfg.name("adjusted_sopr_24h"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
BasisPoints16, BasisPointsSigned16,
|
||||
Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats, Dollars, Height, Sats, StoredF32, StoredF64, Version,
|
||||
};
|
||||
use vecdb::{
|
||||
@@ -12,10 +13,13 @@ use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
distribution::state::RealizedState,
|
||||
internal::{
|
||||
Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent,
|
||||
CentsPlus, CentsUnsignedToDollars, ComputedFromHeightCumulative, ComputedFromHeight,
|
||||
ComputedFromHeightRatio, NegCentsUnsignedToDollars, ValueFromHeightCumulative, LazyFromHeight,
|
||||
PercentageCentsF32, PercentageCentsSignedCentsF32, PercentageCentsSignedDollarsF32, Price, RatioCents64,
|
||||
RollingEmas7d30d, RollingWindows, Identity, ValueFromHeight,
|
||||
ComputedFromHeightRatio, FiatFromHeight, NegCentsUnsignedToDollars, PercentFromHeight,
|
||||
PercentRollingEmas1w1m, PercentRollingWindows, ValueFromHeightCumulative, LazyFromHeight,
|
||||
Price,
|
||||
RatioCentsBp16, RatioCentsSignedCentsBps16, RatioCentsSignedDollarsBps16, RatioCents64,
|
||||
RollingEmas1w1m, RollingEmas2w, RollingWindows, Identity,
|
||||
},
|
||||
prices,
|
||||
};
|
||||
@@ -29,12 +33,12 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
pub realized_cap_cents: ComputedFromHeight<Cents, M>,
|
||||
pub realized_cap: LazyFromHeight<Dollars, Cents>,
|
||||
pub realized_price: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub realized_price_extra: ComputedFromHeightRatio<M>,
|
||||
pub realized_cap_30d_delta: ComputedFromHeight<CentsSigned, M>,
|
||||
pub realized_price_ratio: ComputedFromHeightRatio<M>,
|
||||
pub realized_cap_change_1m: ComputedFromHeight<CentsSigned, M>,
|
||||
|
||||
// === Investor Price ===
|
||||
pub investor_price: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub investor_price_extra: ComputedFromHeightRatio<M>,
|
||||
pub investor_price_ratio: ComputedFromHeightRatio<M>,
|
||||
|
||||
// === Floor/Ceiling Price Bands ===
|
||||
pub lower_price_band: Price<ComputedFromHeight<Cents, M>>,
|
||||
@@ -49,21 +53,18 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
|
||||
// === Realized Profit/Loss ===
|
||||
pub realized_profit: ComputedFromHeightCumulative<Cents, M>,
|
||||
pub realized_profit_7d_ema: ComputedFromHeight<Cents, M>,
|
||||
pub realized_profit_ema_1w: ComputedFromHeight<Cents, M>,
|
||||
pub realized_loss: ComputedFromHeightCumulative<Cents, M>,
|
||||
pub realized_loss_7d_ema: ComputedFromHeight<Cents, M>,
|
||||
pub realized_loss_ema_1w: ComputedFromHeight<Cents, M>,
|
||||
pub neg_realized_loss: LazyFromHeight<Dollars, Cents>,
|
||||
pub net_realized_pnl: ComputedFromHeightCumulative<CentsSigned, M>,
|
||||
pub net_realized_pnl_7d_ema: ComputedFromHeight<CentsSigned, M>,
|
||||
pub realized_value: ComputedFromHeight<Cents, M>,
|
||||
pub net_realized_pnl_ema_1w: ComputedFromHeight<CentsSigned, M>,
|
||||
pub gross_pnl: FiatFromHeight<Cents, M>,
|
||||
|
||||
// === Realized vs Realized Cap Ratios ===
|
||||
pub realized_profit_rel_to_realized_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub realized_loss_rel_to_realized_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub net_realized_pnl_rel_to_realized_cap: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
// === Total Realized PnL ===
|
||||
pub total_realized_pnl: LazyFromHeight<Dollars, Cents>,
|
||||
pub realized_profit_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
pub realized_loss_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
pub net_realized_pnl_rel_to_realized_cap: PercentFromHeight<BasisPointsSigned16, M>,
|
||||
|
||||
// === Value Created/Destroyed Splits (stored) ===
|
||||
pub profit_value_created: ComputedFromHeight<Cents, M>,
|
||||
@@ -85,29 +86,29 @@ pub struct RealizedBase<M: StorageMode = Rw> {
|
||||
|
||||
// === SOPR (rolling window ratios) ===
|
||||
pub sopr: RollingWindows<StoredF64, M>,
|
||||
pub sopr_ema: RollingEmas7d30d<StoredF64, M>,
|
||||
pub sopr_24h_ema: RollingEmas1w1m<StoredF64, M>,
|
||||
|
||||
// === Sell Side Risk ===
|
||||
pub realized_value_sum: RollingWindows<Cents, M>,
|
||||
pub sell_side_risk_ratio: RollingWindows<StoredF32, M>,
|
||||
pub sell_side_risk_ratio_ema: RollingEmas7d30d<StoredF32, M>,
|
||||
pub gross_pnl_sum: RollingWindows<Cents, M>,
|
||||
pub sell_side_risk_ratio: PercentRollingWindows<BasisPoints16, M>,
|
||||
pub sell_side_risk_ratio_24h_ema: PercentRollingEmas1w1m<BasisPoints16, M>,
|
||||
|
||||
// === Net Realized PnL Deltas ===
|
||||
pub net_realized_pnl_cumulative_30d_delta: ComputedFromHeight<CentsSigned, M>,
|
||||
pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
pub net_pnl_change_1m: ComputedFromHeight<CentsSigned, M>,
|
||||
pub net_pnl_change_1m_rel_to_realized_cap:
|
||||
PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub net_pnl_change_1m_rel_to_market_cap:
|
||||
PercentFromHeight<BasisPointsSigned16, M>,
|
||||
|
||||
// === Peak Regret ===
|
||||
pub peak_regret: ComputedFromHeightCumulative<Cents, M>,
|
||||
pub peak_regret_rel_to_realized_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub peak_regret_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
|
||||
// === Sent in Profit/Loss ===
|
||||
pub sent_in_profit: ValueFromHeightCumulative<M>,
|
||||
pub sent_in_profit_14d_ema: ValueFromHeight<M>,
|
||||
pub sent_in_profit_ema: RollingEmas2w<M>,
|
||||
pub sent_in_loss: ValueFromHeightCumulative<M>,
|
||||
pub sent_in_loss_14d_ema: ValueFromHeight<M>,
|
||||
pub sent_in_loss_ema: RollingEmas2w<M>,
|
||||
}
|
||||
|
||||
impl RealizedBase {
|
||||
@@ -138,9 +139,9 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let realized_profit_7d_ema = ComputedFromHeight::forced_import(
|
||||
let realized_profit_ema_1w = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit_7d_ema"),
|
||||
&cfg.name("realized_profit_ema_1w"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
@@ -152,9 +153,9 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let realized_loss_7d_ema = ComputedFromHeight::forced_import(
|
||||
let realized_loss_ema_1w = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_loss_7d_ema"),
|
||||
&cfg.name("realized_loss_ema_1w"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
@@ -173,9 +174,9 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let net_realized_pnl_7d_ema = ComputedFromHeight::forced_import(
|
||||
let net_realized_pnl_ema_1w = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_7d_ema"),
|
||||
&cfg.name("net_realized_pnl_ema_1w"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
@@ -187,40 +188,36 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let realized_value = ComputedFromHeight::forced_import(
|
||||
let gross_pnl = FiatFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_value"),
|
||||
&cfg.name("gross_pnl"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let total_realized_pnl = LazyFromHeight::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("total_realized_pnl"),
|
||||
cfg.version + v1,
|
||||
realized_value.height.read_only_boxed_clone(),
|
||||
&realized_value,
|
||||
);
|
||||
let realized_profit_rel_to_realized_cap =
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let realized_profit_rel_to_realized_cap = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
let realized_loss_rel_to_realized_cap =
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("realized_loss_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let realized_loss_rel_to_realized_cap = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_loss_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let net_realized_pnl_rel_to_realized_cap = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
let net_realized_pnl_rel_to_realized_cap =
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let realized_price = Price::forced_import(
|
||||
cfg.db,
|
||||
@@ -236,7 +233,7 @@ impl RealizedBase {
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
let investor_price_extra = ComputedFromHeightRatio::forced_import(
|
||||
let investor_price_ratio = ComputedFromHeightRatio::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("investor_price"),
|
||||
cfg.version,
|
||||
@@ -312,7 +309,7 @@ impl RealizedBase {
|
||||
&profit_value_destroyed,
|
||||
);
|
||||
|
||||
let realized_price_extra = ComputedFromHeightRatio::forced_import(
|
||||
let realized_price_ratio = ComputedFromHeightRatio::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_price"),
|
||||
cfg.version + v1,
|
||||
@@ -322,8 +319,8 @@ impl RealizedBase {
|
||||
let mvrv = LazyFromHeight::from_computed::<Identity<StoredF32>>(
|
||||
&cfg.name("mvrv"),
|
||||
cfg.version,
|
||||
realized_price_extra.ratio.height.read_only_boxed_clone(),
|
||||
&realized_price_extra.ratio,
|
||||
realized_price_ratio.ratio.height.read_only_boxed_clone(),
|
||||
&realized_price_ratio.ratio,
|
||||
);
|
||||
|
||||
// === Rolling windows ===
|
||||
@@ -333,61 +330,61 @@ impl RealizedBase {
|
||||
let value_destroyed_sum = RollingWindows::forced_import(
|
||||
cfg.db, &cfg.name("value_destroyed"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
let realized_value_sum = RollingWindows::forced_import(
|
||||
cfg.db, &cfg.name("realized_value"), cfg.version + v1, cfg.indexes,
|
||||
let gross_pnl_sum = RollingWindows::forced_import(
|
||||
cfg.db, &cfg.name("gross_pnl_sum"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
let sopr = RollingWindows::forced_import(
|
||||
cfg.db, &cfg.name("sopr"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
let sell_side_risk_ratio = RollingWindows::forced_import(
|
||||
let sell_side_risk_ratio = PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db, &cfg.name("sell_side_risk_ratio"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
|
||||
// === EMA imports ===
|
||||
let sopr_ema = RollingEmas7d30d::forced_import(
|
||||
let sopr_24h_ema = RollingEmas1w1m::forced_import(
|
||||
cfg.db, &cfg.name("sopr_24h"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
let sell_side_risk_ratio_ema = RollingEmas7d30d::forced_import(
|
||||
let sell_side_risk_ratio_24h_ema = PercentRollingEmas1w1m::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db, &cfg.name("sell_side_risk_ratio_24h"), cfg.version + v1, cfg.indexes,
|
||||
)?;
|
||||
|
||||
let peak_regret_rel_to_realized_cap = ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("peak_regret_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
let peak_regret_rel_to_realized_cap =
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("realized_peak_regret_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
realized_cap_cents,
|
||||
realized_cap,
|
||||
realized_price,
|
||||
realized_price_extra,
|
||||
realized_cap_30d_delta: ComputedFromHeight::forced_import(
|
||||
realized_price_ratio,
|
||||
realized_cap_change_1m: ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap_30d_delta"),
|
||||
&cfg.name("realized_cap_change_1m"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
investor_price,
|
||||
investor_price_extra,
|
||||
investor_price_ratio,
|
||||
lower_price_band,
|
||||
upper_price_band,
|
||||
cap_raw,
|
||||
investor_cap_raw,
|
||||
mvrv,
|
||||
realized_profit,
|
||||
realized_profit_7d_ema,
|
||||
realized_profit_ema_1w,
|
||||
realized_loss,
|
||||
realized_loss_7d_ema,
|
||||
realized_loss_ema_1w,
|
||||
neg_realized_loss,
|
||||
net_realized_pnl,
|
||||
net_realized_pnl_7d_ema,
|
||||
realized_value,
|
||||
net_realized_pnl_ema_1w,
|
||||
gross_pnl,
|
||||
realized_profit_rel_to_realized_cap,
|
||||
realized_loss_rel_to_realized_cap,
|
||||
net_realized_pnl_rel_to_realized_cap,
|
||||
total_realized_pnl,
|
||||
profit_value_created,
|
||||
profit_value_destroyed,
|
||||
loss_value_created,
|
||||
@@ -399,27 +396,27 @@ impl RealizedBase {
|
||||
value_created_sum,
|
||||
value_destroyed_sum,
|
||||
sopr,
|
||||
sopr_ema,
|
||||
realized_value_sum,
|
||||
sopr_24h_ema,
|
||||
gross_pnl_sum,
|
||||
sell_side_risk_ratio,
|
||||
sell_side_risk_ratio_ema,
|
||||
net_realized_pnl_cumulative_30d_delta: ComputedFromHeight::forced_import(
|
||||
sell_side_risk_ratio_24h_ema,
|
||||
net_pnl_change_1m: ComputedFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta"),
|
||||
&cfg.name("net_pnl_change_1m"),
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap:
|
||||
ComputedFromHeight::forced_import(
|
||||
net_pnl_change_1m_rel_to_realized_cap:
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap"),
|
||||
&cfg.name("net_pnl_change_1m_rel_to_realized_cap"),
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
net_realized_pnl_cumulative_30d_delta_rel_to_market_cap:
|
||||
ComputedFromHeight::forced_import(
|
||||
net_pnl_change_1m_rel_to_market_cap:
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta_rel_to_market_cap"),
|
||||
&cfg.name("net_pnl_change_1m_rel_to_market_cap"),
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -431,9 +428,9 @@ impl RealizedBase {
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
sent_in_profit_14d_ema: ValueFromHeight::forced_import(
|
||||
sent_in_profit_ema: RollingEmas2w::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("sent_in_profit_14d_ema"),
|
||||
&cfg.name("sent_in_profit"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -443,9 +440,9 @@ impl RealizedBase {
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
sent_in_loss_14d_ema: ValueFromHeight::forced_import(
|
||||
sent_in_loss_ema: RollingEmas2w::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("sent_in_loss_14d_ema"),
|
||||
&cfg.name("sent_in_loss"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -710,7 +707,7 @@ impl RealizedBase {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.realized_value.height.compute_add(
|
||||
self.gross_pnl.cents.height.compute_add(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit.height,
|
||||
&self.realized_loss.height,
|
||||
@@ -750,14 +747,14 @@ impl RealizedBase {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.realized_price_extra.compute_ratio(
|
||||
self.realized_price_ratio.compute_ratio(
|
||||
starting_indexes,
|
||||
&prices.price.cents.height,
|
||||
&self.realized_price.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.investor_price_extra.compute_ratio(
|
||||
self.investor_price_ratio.compute_ratio(
|
||||
starting_indexes,
|
||||
&prices.price.cents.height,
|
||||
&self.investor_price.cents.height,
|
||||
@@ -796,7 +793,7 @@ impl RealizedBase {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.realized_cap_30d_delta.height.compute_rolling_change(
|
||||
self.realized_cap_change_1m.height.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.realized_cap_cents.height,
|
||||
@@ -827,8 +824,8 @@ impl RealizedBase {
|
||||
self.value_destroyed_sum.compute_rolling_sum(
|
||||
starting_indexes.height, &window_starts, &self.value_destroyed.height, exit,
|
||||
)?;
|
||||
self.realized_value_sum.compute_rolling_sum(
|
||||
starting_indexes.height, &window_starts, &self.realized_value.height, exit,
|
||||
self.gross_pnl_sum.compute_rolling_sum(
|
||||
starting_indexes.height, &window_starts, &self.gross_pnl.cents.height, exit,
|
||||
)?;
|
||||
|
||||
// Compute SOPR from rolling sums
|
||||
@@ -843,27 +840,27 @@ impl RealizedBase {
|
||||
|
||||
// Compute sell-side risk ratios
|
||||
for (ssrr, rv) in self.sell_side_risk_ratio.as_mut_array().into_iter()
|
||||
.zip(self.realized_value_sum.as_array())
|
||||
.zip(self.gross_pnl_sum.as_array())
|
||||
{
|
||||
ssrr.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
ssrr.compute_binary::<Cents, Cents, RatioCentsBp16>(
|
||||
starting_indexes.height, &rv.height, &self.realized_cap_cents.height, exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
// 7d EMAs
|
||||
self.realized_profit_7d_ema.height.compute_rolling_ema(
|
||||
self.realized_profit_ema_1w.height.compute_rolling_ema(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
&self.realized_profit.height,
|
||||
exit,
|
||||
)?;
|
||||
self.realized_loss_7d_ema.height.compute_rolling_ema(
|
||||
self.realized_loss_ema_1w.height.compute_rolling_ema(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
&self.realized_loss.height,
|
||||
exit,
|
||||
)?;
|
||||
self.net_realized_pnl_7d_ema
|
||||
self.net_realized_pnl_ema_1w
|
||||
.height
|
||||
.compute_rolling_ema(
|
||||
starting_indexes.height,
|
||||
@@ -873,14 +870,14 @@ impl RealizedBase {
|
||||
)?;
|
||||
|
||||
// 14-day EMA of sent in profit/loss
|
||||
self.sent_in_profit_14d_ema.compute_ema(
|
||||
self.sent_in_profit_ema.compute(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent_in_profit.base.sats.height,
|
||||
&self.sent_in_profit.base.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sent_in_loss_14d_ema.compute_ema(
|
||||
self.sent_in_loss_ema.compute(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent_in_loss.base.sats.height,
|
||||
@@ -889,7 +886,7 @@ impl RealizedBase {
|
||||
)?;
|
||||
|
||||
// SOPR EMAs (based on 24h window)
|
||||
self.sopr_ema.compute_from_24h(
|
||||
self.sopr_24h_ema.compute_from_24h(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
&blocks.count.height_1m_ago,
|
||||
@@ -898,38 +895,38 @@ impl RealizedBase {
|
||||
)?;
|
||||
|
||||
// Sell side risk EMAs (based on 24h window)
|
||||
self.sell_side_risk_ratio_ema.compute_from_24h(
|
||||
self.sell_side_risk_ratio_24h_ema.compute_from_24h(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.sell_side_risk_ratio._24h.height,
|
||||
&self.sell_side_risk_ratio._24h.bps.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Realized profit/loss/net relative to realized cap
|
||||
self.realized_profit_rel_to_realized_cap
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
.compute_binary::<Cents, Cents, RatioCentsBp16>(
|
||||
starting_indexes.height,
|
||||
&self.realized_profit.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.realized_loss_rel_to_realized_cap
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
.compute_binary::<Cents, Cents, RatioCentsBp16>(
|
||||
starting_indexes.height,
|
||||
&self.realized_loss.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.net_realized_pnl_rel_to_realized_cap
|
||||
.compute_binary::<CentsSigned, Cents, PercentageCentsSignedCentsF32>(
|
||||
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps16>(
|
||||
starting_indexes.height,
|
||||
&self.net_realized_pnl.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.peak_regret_rel_to_realized_cap
|
||||
.compute_binary::<Cents, Cents, PercentageCentsF32>(
|
||||
.compute_binary::<Cents, Cents, RatioCentsBp16>(
|
||||
starting_indexes.height,
|
||||
&self.peak_regret.height,
|
||||
&self.realized_cap_cents.height,
|
||||
@@ -937,7 +934,7 @@ impl RealizedBase {
|
||||
)?;
|
||||
|
||||
// Net realized PnL cumulative 30d delta
|
||||
self.net_realized_pnl_cumulative_30d_delta
|
||||
self.net_pnl_change_1m
|
||||
.height
|
||||
.compute_rolling_change(
|
||||
starting_indexes.height,
|
||||
@@ -946,18 +943,18 @@ impl RealizedBase {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap
|
||||
.compute_binary::<CentsSigned, Cents, PercentageCentsSignedCentsF32>(
|
||||
self.net_pnl_change_1m_rel_to_realized_cap
|
||||
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps16>(
|
||||
starting_indexes.height,
|
||||
&self.net_realized_pnl_cumulative_30d_delta.height,
|
||||
&self.net_pnl_change_1m.height,
|
||||
&self.realized_cap_cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.net_realized_pnl_cumulative_30d_delta_rel_to_market_cap
|
||||
.compute_binary::<CentsSigned, Dollars, PercentageCentsSignedDollarsF32>(
|
||||
self.net_pnl_change_1m_rel_to_market_cap
|
||||
.compute_binary::<CentsSigned, Dollars, RatioCentsSignedDollarsBps16>(
|
||||
starting_indexes.height,
|
||||
&self.net_realized_pnl_cumulative_30d_delta.height,
|
||||
&self.net_pnl_change_1m.height,
|
||||
height_to_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Dollars, Height, StoredF32, StoredF64, Version};
|
||||
use brk_types::{BasisPoints16, Cents, Dollars, Height, StoredF64, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, blocks,
|
||||
internal::{ComputedFromHeight, ComputedFromHeightRatioExtension, RatioCents64, RollingWindows},
|
||||
internal::{
|
||||
Bp16ToFloat, Bp16ToPercent, ComputedFromHeightRatioExtension, PercentFromHeight,
|
||||
RatioCents64, RatioDollarsBp16, RollingWindows,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
@@ -15,7 +18,7 @@ use super::RealizedBase;
|
||||
/// Extended realized metrics (only for extended cohorts: all, sth, lth, age_range).
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedExtended<M: StorageMode = Rw> {
|
||||
pub realized_cap_rel_to_own_market_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub realized_cap_rel_to_own_market_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
|
||||
// === Realized Profit/Loss Rolling Sums ===
|
||||
pub realized_profit_sum: RollingWindows<Cents, M>,
|
||||
@@ -34,7 +37,7 @@ impl RealizedExtended {
|
||||
let v1 = Version::ONE;
|
||||
|
||||
Ok(RealizedExtended {
|
||||
realized_cap_rel_to_own_market_cap: ComputedFromHeight::forced_import(
|
||||
realized_cap_rel_to_own_market_cap: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap_rel_to_own_market_cap"),
|
||||
cfg.version,
|
||||
@@ -84,8 +87,7 @@ impl RealizedExtended {
|
||||
|
||||
// Realized cap relative to own market cap
|
||||
self.realized_cap_rel_to_own_market_cap
|
||||
.height
|
||||
.compute_percentage(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
starting_indexes.height,
|
||||
&base.realized_cap.height,
|
||||
height_to_market_cap,
|
||||
@@ -107,7 +109,7 @@ impl RealizedExtended {
|
||||
blocks,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&base.realized_price_extra.ratio.height,
|
||||
&base.realized_price_ratio.ratio.height,
|
||||
)?;
|
||||
self.realized_price_ratio_ext.compute_cents_bands(
|
||||
starting_indexes,
|
||||
@@ -119,7 +121,7 @@ impl RealizedExtended {
|
||||
blocks,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&base.investor_price_extra.ratio.height,
|
||||
&base.investor_price_ratio.ratio.height,
|
||||
)?;
|
||||
self.investor_price_ratio_ext.compute_cents_bands(
|
||||
starting_indexes,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, StoredF32, StoredF64, Version};
|
||||
use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height, Sats, StoredF32, Version};
|
||||
use vecdb::{Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{
|
||||
ComputedFromHeight, Identity, LazyFromHeight,
|
||||
NegPercentageDollarsF32, PercentageDollarsF32, PercentageSatsF64,
|
||||
Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent, LazyFromHeight,
|
||||
NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16, RatioSatsBp16,
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
|
||||
@@ -16,19 +16,19 @@ use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeBase<M: StorageMode = Rw> {
|
||||
// === Supply in Profit/Loss Relative to Own Supply ===
|
||||
pub supply_in_profit_rel_to_own_supply: ComputedFromHeight<StoredF64, M>,
|
||||
pub supply_in_loss_rel_to_own_supply: ComputedFromHeight<StoredF64, M>,
|
||||
pub supply_in_profit_rel_to_own_supply: PercentFromHeight<BasisPoints16, M>,
|
||||
pub supply_in_loss_rel_to_own_supply: PercentFromHeight<BasisPoints16, M>,
|
||||
|
||||
// === Unrealized vs Market Cap ===
|
||||
pub unrealized_profit_rel_to_market_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub unrealized_loss_rel_to_market_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub neg_unrealized_loss_rel_to_market_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub net_unrealized_pnl_rel_to_market_cap: ComputedFromHeight<StoredF32, M>,
|
||||
pub nupl: LazyFromHeight<StoredF32, StoredF32>,
|
||||
pub unrealized_profit_rel_to_market_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
pub unrealized_loss_rel_to_market_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
pub neg_unrealized_loss_rel_to_market_cap: PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub net_unrealized_pnl_rel_to_market_cap: PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub nupl: LazyFromHeight<StoredF32, BasisPointsSigned16>,
|
||||
|
||||
// === Invested Capital in Profit/Loss as % of Realized Cap ===
|
||||
pub invested_capital_in_profit_pct: ComputedFromHeight<StoredF32, M>,
|
||||
pub invested_capital_in_loss_pct: ComputedFromHeight<StoredF32, M>,
|
||||
pub invested_capital_in_profit_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
pub invested_capital_in_loss_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
impl RelativeBase {
|
||||
@@ -36,41 +36,49 @@ impl RelativeBase {
|
||||
let v1 = Version::ONE;
|
||||
let v2 = Version::new(2);
|
||||
|
||||
let net_unrealized_pnl_rel_to_market_cap = ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
|
||||
)?;
|
||||
let net_unrealized_pnl_rel_to_market_cap =
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db, &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
|
||||
)?;
|
||||
|
||||
let nupl = LazyFromHeight::from_computed::<Identity<StoredF32>>(
|
||||
let nupl = LazyFromHeight::from_computed::<Bps16ToFloat>(
|
||||
&cfg.name("nupl"),
|
||||
cfg.version + v2,
|
||||
net_unrealized_pnl_rel_to_market_cap.height.read_only_boxed_clone(),
|
||||
&net_unrealized_pnl_rel_to_market_cap,
|
||||
net_unrealized_pnl_rel_to_market_cap.bps.height.read_only_boxed_clone(),
|
||||
&net_unrealized_pnl_rel_to_market_cap.bps,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
supply_in_profit_rel_to_own_supply: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("supply_in_profit_rel_to_own_supply"), cfg.version + v1, cfg.indexes,
|
||||
)?,
|
||||
supply_in_loss_rel_to_own_supply: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("supply_in_loss_rel_to_own_supply"), cfg.version + v1, cfg.indexes,
|
||||
)?,
|
||||
unrealized_profit_rel_to_market_cap: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("unrealized_profit_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
|
||||
)?,
|
||||
unrealized_loss_rel_to_market_cap: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
|
||||
)?,
|
||||
neg_unrealized_loss_rel_to_market_cap: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("neg_unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
|
||||
)?,
|
||||
supply_in_profit_rel_to_own_supply:
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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>(
|
||||
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>(
|
||||
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>(
|
||||
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>(
|
||||
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_pct: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("invested_capital_in_profit_pct"), cfg.version, cfg.indexes,
|
||||
)?,
|
||||
invested_capital_in_loss_pct: ComputedFromHeight::forced_import(
|
||||
cfg.db, &cfg.name("invested_capital_in_loss_pct"), cfg.version, cfg.indexes,
|
||||
)?,
|
||||
invested_capital_in_profit_rel_to_realized_cap:
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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>(
|
||||
cfg.db, &cfg.name("invested_capital_in_loss_rel_to_realized_cap"), cfg.version, cfg.indexes,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -84,35 +92,35 @@ impl RelativeBase {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit_rel_to_own_supply
|
||||
.compute_binary::<Sats, Sats, PercentageSatsF64>(
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from, &unrealized.supply_in_profit.sats.height, supply_total_sats, exit,
|
||||
)?;
|
||||
self.supply_in_loss_rel_to_own_supply
|
||||
.compute_binary::<Sats, Sats, PercentageSatsF64>(
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from, &unrealized.supply_in_loss.sats.height, supply_total_sats, exit,
|
||||
)?;
|
||||
self.unrealized_profit_rel_to_market_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.unrealized_profit.usd.height, market_cap, exit,
|
||||
)?;
|
||||
self.unrealized_loss_rel_to_market_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, market_cap, exit,
|
||||
)?;
|
||||
self.neg_unrealized_loss_rel_to_market_cap
|
||||
.compute_binary::<Dollars, Dollars, NegPercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, NegRatioDollarsBps16>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, market_cap, exit,
|
||||
)?;
|
||||
self.net_unrealized_pnl_rel_to_market_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBps16>(
|
||||
max_from, &unrealized.net_unrealized_pnl.usd.height, market_cap, exit,
|
||||
)?;
|
||||
self.invested_capital_in_profit_pct
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
self.invested_capital_in_profit_rel_to_realized_cap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.invested_capital_in_profit.usd.height, &realized.realized_cap.height, exit,
|
||||
)?;
|
||||
self.invested_capital_in_loss_pct
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
self.invested_capital_in_loss_rel_to_realized_cap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.invested_capital_in_loss.usd.height, &realized.realized_cap.height, exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32};
|
||||
use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{
|
||||
ComputedFromHeight, NegPercentageDollarsF32, PercentageDollarsF32,
|
||||
Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent,
|
||||
NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16,
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
|
||||
@@ -13,13 +14,13 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeExtendedOwnMarketCap<M: StorageMode = Rw> {
|
||||
pub unrealized_profit_rel_to_own_market_cap:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
pub unrealized_loss_rel_to_own_market_cap:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
pub neg_unrealized_loss_rel_to_own_market_cap:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub net_unrealized_pnl_rel_to_own_market_cap:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
PercentFromHeight<BasisPointsSigned16, M>,
|
||||
}
|
||||
|
||||
impl RelativeExtendedOwnMarketCap {
|
||||
@@ -30,28 +31,28 @@ impl RelativeExtendedOwnMarketCap {
|
||||
|
||||
Ok(Self {
|
||||
unrealized_profit_rel_to_own_market_cap:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("unrealized_profit_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
unrealized_loss_rel_to_own_market_cap:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("unrealized_loss_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
neg_unrealized_loss_rel_to_own_market_cap:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
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:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
@@ -68,19 +69,19 @@ impl RelativeExtendedOwnMarketCap {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.unrealized_profit_rel_to_own_market_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.unrealized_profit.usd.height, own_market_cap, exit,
|
||||
)?;
|
||||
self.unrealized_loss_rel_to_own_market_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, own_market_cap, exit,
|
||||
)?;
|
||||
self.neg_unrealized_loss_rel_to_own_market_cap
|
||||
.compute_binary::<Dollars, Dollars, NegPercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, NegRatioDollarsBps16>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, own_market_cap, exit,
|
||||
)?;
|
||||
self.net_unrealized_pnl_rel_to_own_market_cap
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBps16>(
|
||||
max_from, &unrealized.net_unrealized_pnl.usd.height, own_market_cap, exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, StoredF32};
|
||||
use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height};
|
||||
use vecdb::{Exit, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{
|
||||
ComputedFromHeight, NegPercentageDollarsF32, PercentageDollarsF32,
|
||||
Bp16ToFloat, Bp16ToPercent, Bps16ToFloat, Bps16ToPercent,
|
||||
NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16,
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
|
||||
@@ -12,14 +13,14 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
|
||||
/// Extended relative metrics for own total unrealized PnL (extended only).
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeExtendedOwnPnl<M: StorageMode = Rw> {
|
||||
pub unrealized_profit_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
pub unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight<StoredF32, M>,
|
||||
pub unrealized_profit_rel_to_own_gross_pnl:
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
pub unrealized_loss_rel_to_own_gross_pnl:
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
pub neg_unrealized_loss_rel_to_own_gross_pnl:
|
||||
PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub net_unrealized_pnl_rel_to_own_gross_pnl:
|
||||
PercentFromHeight<BasisPointsSigned16, M>,
|
||||
}
|
||||
|
||||
impl RelativeExtendedOwnPnl {
|
||||
@@ -30,31 +31,31 @@ impl RelativeExtendedOwnPnl {
|
||||
let v2 = brk_types::Version::new(2);
|
||||
|
||||
Ok(Self {
|
||||
unrealized_profit_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight::forced_import(
|
||||
unrealized_profit_rel_to_own_gross_pnl:
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("unrealized_profit_rel_to_own_total_unrealized_pnl"),
|
||||
&cfg.name("unrealized_profit_rel_to_own_gross_pnl"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight::forced_import(
|
||||
unrealized_loss_rel_to_own_gross_pnl:
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("unrealized_loss_rel_to_own_total_unrealized_pnl"),
|
||||
&cfg.name("unrealized_loss_rel_to_own_gross_pnl"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
neg_unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight::forced_import(
|
||||
neg_unrealized_loss_rel_to_own_gross_pnl:
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("neg_unrealized_loss_rel_to_own_total_unrealized_pnl"),
|
||||
&cfg.name("neg_unrealized_loss_rel_to_own_gross_pnl"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
net_unrealized_pnl_rel_to_own_total_unrealized_pnl:
|
||||
ComputedFromHeight::forced_import(
|
||||
net_unrealized_pnl_rel_to_own_gross_pnl:
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_total_unrealized_pnl"),
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_gross_pnl"),
|
||||
cfg.version + v2,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -67,21 +68,21 @@ impl RelativeExtendedOwnPnl {
|
||||
unrealized: &UnrealizedBase,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.unrealized_profit_rel_to_own_total_unrealized_pnl
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
max_from, &unrealized.unrealized_profit.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit,
|
||||
self.unrealized_profit_rel_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.unrealized_profit.usd.height, &unrealized.gross_pnl.usd.height, exit,
|
||||
)?;
|
||||
self.unrealized_loss_rel_to_own_total_unrealized_pnl
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit,
|
||||
self.unrealized_loss_rel_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, &unrealized.gross_pnl.usd.height, exit,
|
||||
)?;
|
||||
self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl
|
||||
.compute_binary::<Dollars, Dollars, NegPercentageDollarsF32>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit,
|
||||
self.neg_unrealized_loss_rel_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, NegRatioDollarsBps16>(
|
||||
max_from, &unrealized.unrealized_loss.usd.height, &unrealized.gross_pnl.usd.height, exit,
|
||||
)?;
|
||||
self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl
|
||||
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
|
||||
max_from, &unrealized.net_unrealized_pnl.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit,
|
||||
self.net_unrealized_pnl_rel_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBps16>(
|
||||
max_from, &unrealized.net_unrealized_pnl.usd.height, &unrealized.gross_pnl.usd.height, exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Sats, StoredF64};
|
||||
use brk_types::{BasisPoints16, Height, Sats};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeight, PercentageSatsF64};
|
||||
use crate::internal::{Bp16ToFloat, Bp16ToPercent, PercentFromHeight, RatioSatsBp16};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
|
||||
|
||||
@@ -11,11 +11,11 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeToAll<M: StorageMode = Rw> {
|
||||
pub supply_rel_to_circulating_supply:
|
||||
ComputedFromHeight<StoredF64, M>,
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
pub supply_in_profit_rel_to_circulating_supply:
|
||||
ComputedFromHeight<StoredF64, M>,
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
pub supply_in_loss_rel_to_circulating_supply:
|
||||
ComputedFromHeight<StoredF64, M>,
|
||||
PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
impl RelativeToAll {
|
||||
@@ -24,21 +24,21 @@ impl RelativeToAll {
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
supply_rel_to_circulating_supply:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("supply_rel_to_circulating_supply"),
|
||||
cfg.version + brk_types::Version::ONE,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
supply_in_profit_rel_to_circulating_supply:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
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:
|
||||
ComputedFromHeight::forced_import(
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
cfg.db,
|
||||
&cfg.name("supply_in_loss_rel_to_circulating_supply"),
|
||||
cfg.version + brk_types::Version::ONE,
|
||||
@@ -56,15 +56,15 @@ impl RelativeToAll {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_rel_to_circulating_supply
|
||||
.compute_binary::<Sats, Sats, PercentageSatsF64>(
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from, supply_total_sats, all_supply_sats, exit,
|
||||
)?;
|
||||
self.supply_in_profit_rel_to_circulating_supply
|
||||
.compute_binary::<Sats, Sats, PercentageSatsF64>(
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from, &unrealized.supply_in_profit.sats.height, all_supply_sats, exit,
|
||||
)?;
|
||||
self.supply_in_loss_rel_to_circulating_supply
|
||||
.compute_binary::<Sats, Sats, PercentageSatsF64>(
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from, &unrealized.supply_in_loss.sats.height, all_supply_sats, exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -18,8 +18,8 @@ use super::ImportConfig;
|
||||
pub struct SupplyMetrics<M: StorageMode = Rw> {
|
||||
pub total: ValueFromHeight<M>,
|
||||
pub halved: LazyValueFromHeight,
|
||||
/// 30-day change in supply (net position change) - sats, btc, usd
|
||||
pub _30d_change: ValueFromHeightChange<M>,
|
||||
/// 1-month change in supply (net position change) - sats, btc, usd
|
||||
pub change_1m: ValueFromHeightChange<M>,
|
||||
}
|
||||
|
||||
impl SupplyMetrics {
|
||||
@@ -39,9 +39,9 @@ impl SupplyMetrics {
|
||||
HalveDollars,
|
||||
>(&cfg.name("supply_halved"), &supply, cfg.version);
|
||||
|
||||
let _30d_change = ValueFromHeightChange::forced_import(
|
||||
let change_1m = ValueFromHeightChange::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("_30d_change"),
|
||||
&cfg.name("supply_change_1m"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
@@ -49,7 +49,7 @@ impl SupplyMetrics {
|
||||
Ok(Self {
|
||||
total: supply,
|
||||
halved: supply_halved,
|
||||
_30d_change,
|
||||
change_1m,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ impl SupplyMetrics {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self._30d_change.compute_rolling(
|
||||
self.change_1m.compute_rolling(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
&self.total.sats.height,
|
||||
|
||||
@@ -51,7 +51,7 @@ pub struct UnrealizedBase<M: StorageMode = Rw> {
|
||||
|
||||
// === Net and Total ===
|
||||
pub net_unrealized_pnl: FiatFromHeight<CentsSigned, M>,
|
||||
pub total_unrealized_pnl: FiatFromHeight<Cents, M>,
|
||||
pub gross_pnl: FiatFromHeight<Cents, M>,
|
||||
}
|
||||
|
||||
impl UnrealizedBase {
|
||||
@@ -148,9 +148,9 @@ impl UnrealizedBase {
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
let total_unrealized_pnl = FiatFromHeight::forced_import(
|
||||
let gross_pnl = FiatFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("total_unrealized_pnl"),
|
||||
&cfg.name("gross_pnl"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
@@ -171,7 +171,7 @@ impl UnrealizedBase {
|
||||
net_sentiment,
|
||||
neg_unrealized_loss,
|
||||
net_unrealized_pnl,
|
||||
total_unrealized_pnl,
|
||||
gross_pnl,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -444,7 +444,7 @@ impl UnrealizedBase {
|
||||
&self.unrealized_loss.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
self.total_unrealized_pnl.cents.height.compute_add(
|
||||
self.gross_pnl.cents.height.compute_add(
|
||||
starting_indexes.height,
|
||||
&self.unrealized_profit.cents.height,
|
||||
&self.unrealized_loss.cents.height,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod _14d;
|
||||
mod _7d_30d;
|
||||
mod _1w_1m;
|
||||
mod _2w;
|
||||
|
||||
pub use _14d::*;
|
||||
pub use _7d_30d::*;
|
||||
pub use _1w_1m::*;
|
||||
pub use _2w::*;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, Version};
|
||||
use brk_types::{Height, StoredF32, Version};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode, UnaryTransform};
|
||||
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 float view.
|
||||
/// Basis-point storage with lazy ratio float view (÷10000).
|
||||
///
|
||||
/// Stores integer basis points on disk (Pco-compressed),
|
||||
/// exposes a lazy StoredF32 view (bps / 100).
|
||||
/// exposes a lazy StoredF32 ratio (e.g., 25000 bps → 2.5).
|
||||
#[derive(Traversable)]
|
||||
pub struct BpsFromHeight<B, M: StorageMode = Rw>
|
||||
pub struct Float32FromHeight<B, M: StorageMode = Rw>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
@@ -22,7 +22,7 @@ where
|
||||
pub float: LazyFromHeight<StoredF32, B>,
|
||||
}
|
||||
|
||||
impl<B> BpsFromHeight<B>
|
||||
impl<B> Float32FromHeight<B>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
@@ -43,4 +43,19 @@ where
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
mod aggregated;
|
||||
mod base;
|
||||
mod bps;
|
||||
mod by_unit;
|
||||
mod constant;
|
||||
mod cumulative;
|
||||
mod cumulative_sum;
|
||||
mod distribution;
|
||||
mod fiat;
|
||||
mod float32;
|
||||
mod full;
|
||||
mod lazy_base;
|
||||
mod percent;
|
||||
mod percentiles;
|
||||
mod price;
|
||||
mod ratio;
|
||||
@@ -17,15 +18,16 @@ mod value;
|
||||
|
||||
pub use aggregated::*;
|
||||
pub use base::*;
|
||||
pub use bps::*;
|
||||
pub use by_unit::*;
|
||||
pub use constant::*;
|
||||
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 percentiles::*;
|
||||
pub use price::*;
|
||||
pub use ratio::*;
|
||||
|
||||
96
crates/brk_computer/src/internal/from_height/percent.rs
Normal file
96
crates/brk_computer/src/internal/from_height/percent.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
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,
|
||||
internal::NumericValue,
|
||||
traits::ComputeDrawdown,
|
||||
};
|
||||
|
||||
use super::{ComputedFromHeight, LazyFromHeight};
|
||||
|
||||
/// Basis-point storage with both ratio and percentage float views.
|
||||
///
|
||||
/// Stores integer basis points on disk (Pco-compressed),
|
||||
/// exposes two lazy StoredF32 views:
|
||||
/// - `ratio`: bps ÷ 10000 (e.g., 4523 bps → 0.4523)
|
||||
/// - `percent`: bps ÷ 100 (e.g., 4523 bps → 45.23%)
|
||||
///
|
||||
/// Use for dominance, adoption, RSI, and other percentage-valued metrics.
|
||||
#[derive(Traversable)]
|
||||
pub struct PercentFromHeight<B, M: StorageMode = Rw>
|
||||
where
|
||||
B: NumericValue + JsonSchema,
|
||||
{
|
||||
pub bps: ComputedFromHeight<B, M>,
|
||||
pub ratio: LazyFromHeight<StoredF32, B>,
|
||||
pub percent: LazyFromHeight<StoredF32, B>,
|
||||
}
|
||||
|
||||
impl<B> PercentFromHeight<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 = ComputedFromHeight::forced_import(db, name, version, indexes)?;
|
||||
|
||||
let ratio = LazyFromHeight::from_computed::<RatioTransform>(
|
||||
&format!("{name}_ratio"),
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
&bps,
|
||||
);
|
||||
|
||||
let percent = LazyFromHeight::from_computed::<PercentTransform>(
|
||||
&format!("{name}_percent"),
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
&bps,
|
||||
);
|
||||
|
||||
Ok(Self { bps, ratio, percent })
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub(crate) fn compute_drawdown<C, A>(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
current: &impl ReadableVec<Height, C>,
|
||||
ath: &impl ReadableVec<Height, A>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
C: VecValue,
|
||||
A: VecValue,
|
||||
f64: From<C> + From<A>,
|
||||
vecdb::EagerVec<vecdb::PcoVec<Height, B>>: ComputeDrawdown<Height>,
|
||||
{
|
||||
self.bps.height.compute_drawdown(max_from, current, ath, exit)
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ use super::super::ComputedFromHeight;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
|
||||
pub ratio_1w_sma: ComputedFromHeight<StoredF32, M>,
|
||||
pub ratio_1m_sma: ComputedFromHeight<StoredF32, M>,
|
||||
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>,
|
||||
@@ -28,9 +28,9 @@ pub struct ComputedFromHeightRatioExtension<M: StorageMode = Rw> {
|
||||
pub ratio_pct1_price: Price<ComputedFromHeight<Cents, M>>,
|
||||
|
||||
pub ratio_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_4y_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_2y_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_1y_sd: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_sd_4y: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_sd_2y: ComputedFromHeightStdDevExtended<M>,
|
||||
pub ratio_sd_1y: ComputedFromHeightStdDevExtended<M>,
|
||||
|
||||
#[traversable(skip)]
|
||||
tdigest: TDigest,
|
||||
@@ -59,10 +59,11 @@ impl ComputedFromHeightRatioExtension {
|
||||
}
|
||||
|
||||
macro_rules! import_sd {
|
||||
($suffix:expr, $days:expr) => {
|
||||
($suffix:expr, $period:expr, $days:expr) => {
|
||||
ComputedFromHeightStdDevExtended::forced_import(
|
||||
db,
|
||||
&format!("{name}_{}", $suffix),
|
||||
$period,
|
||||
$days,
|
||||
v,
|
||||
indexes,
|
||||
@@ -77,12 +78,12 @@ impl ComputedFromHeightRatioExtension {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
ratio_1w_sma: import!("ratio_1w_sma"),
|
||||
ratio_1m_sma: import!("ratio_1m_sma"),
|
||||
ratio_sd: import_sd!("ratio", usize::MAX),
|
||||
ratio_1y_sd: import_sd!("ratio_1y", 365),
|
||||
ratio_2y_sd: import_sd!("ratio_2y", 2 * 365),
|
||||
ratio_4y_sd: import_sd!("ratio_4y", 4 * 365),
|
||||
ratio_sma_1w: import!("ratio_sma_1w"),
|
||||
ratio_sma_1m: import!("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"),
|
||||
@@ -108,14 +109,14 @@ impl ComputedFromHeightRatioExtension {
|
||||
ratio_source: &impl ReadableVec<Height, StoredF32>,
|
||||
) -> Result<()> {
|
||||
// SMA using lookback vecs
|
||||
self.ratio_1w_sma.height.compute_rolling_average(
|
||||
self.ratio_sma_1w.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1w_ago,
|
||||
ratio_source,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.ratio_1m_sma.height.compute_rolling_average(
|
||||
self.ratio_sma_1m.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1m_ago,
|
||||
ratio_source,
|
||||
@@ -183,11 +184,11 @@ impl ComputedFromHeightRatioExtension {
|
||||
// Compute stddev at height level
|
||||
self.ratio_sd
|
||||
.compute_all(blocks, starting_indexes, exit, ratio_source)?;
|
||||
self.ratio_4y_sd
|
||||
self.ratio_sd_4y
|
||||
.compute_all(blocks, starting_indexes, exit, ratio_source)?;
|
||||
self.ratio_2y_sd
|
||||
self.ratio_sd_2y
|
||||
.compute_all(blocks, starting_indexes, exit, ratio_source)?;
|
||||
self.ratio_1y_sd
|
||||
self.ratio_sd_1y
|
||||
.compute_all(blocks, starting_indexes, exit, ratio_source)?;
|
||||
|
||||
Ok(())
|
||||
@@ -225,11 +226,11 @@ impl ComputedFromHeightRatioExtension {
|
||||
// Stddev cents bands
|
||||
self.ratio_sd
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_4y_sd
|
||||
self.ratio_sd_4y
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_2y_sd
|
||||
self.ratio_sd_2y
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
self.ratio_1y_sd
|
||||
self.ratio_sd_1y
|
||||
.compute_cents_bands(starting_indexes, metric_price, exit)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -51,17 +51,19 @@ impl ComputedFromHeightStdDevExtended {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
period: &str,
|
||||
days: usize,
|
||||
parent_version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let version = parent_version + Version::TWO;
|
||||
let p = super::period_suffix(period);
|
||||
|
||||
macro_rules! import {
|
||||
($suffix:expr) => {
|
||||
ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&format!("{name}_{}", $suffix),
|
||||
&format!("{name}_{}{p}", $suffix),
|
||||
version,
|
||||
indexes,
|
||||
)?
|
||||
@@ -70,12 +72,12 @@ impl ComputedFromHeightStdDevExtended {
|
||||
|
||||
macro_rules! import_price {
|
||||
($suffix:expr) => {
|
||||
Price::forced_import(db, &format!("{name}_{}", $suffix), version, indexes)?
|
||||
Price::forced_import(db, &format!("{name}_{}{p}", $suffix), version, indexes)?
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
base: ComputedFromHeightStdDev::forced_import(db, name, days, parent_version, indexes)?,
|
||||
base: ComputedFromHeightStdDev::forced_import(db, name, period, days, parent_version, indexes)?,
|
||||
zscore: import!("zscore"),
|
||||
p0_5sd: import!("p0_5sd"),
|
||||
p1sd: import!("p1sd"),
|
||||
|
||||
@@ -11,6 +11,14 @@ use crate::{ComputeIndexes, blocks, indexes};
|
||||
|
||||
use crate::internal::ComputedFromHeight;
|
||||
|
||||
fn period_suffix(period: &str) -> String {
|
||||
if period.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("_{period}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ComputedFromHeightStdDev<M: StorageMode = Rw> {
|
||||
days: usize,
|
||||
@@ -22,21 +30,23 @@ impl ComputedFromHeightStdDev {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
period: &str,
|
||||
days: usize,
|
||||
parent_version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let version = parent_version + Version::TWO;
|
||||
let p = period_suffix(period);
|
||||
|
||||
let sma = ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&format!("{name}_sma"),
|
||||
&format!("{name}_sma{p}"),
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
let sd = ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&format!("{name}_sd"),
|
||||
&format!("{name}_sd{p}"),
|
||||
version,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
@@ -74,18 +74,18 @@ where
|
||||
&mut self.0.pct75._24h.height, &mut self.0.pct90._24h.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._7d, source,
|
||||
&mut self.0.average._7d.height, &mut self.0.min._7d.height,
|
||||
&mut self.0.max._7d.height, &mut self.0.pct10._7d.height,
|
||||
&mut self.0.pct25._7d.height, &mut self.0.median._7d.height,
|
||||
&mut self.0.pct75._7d.height, &mut self.0.pct90._7d.height, exit,
|
||||
max_from, windows._1w, source,
|
||||
&mut self.0.average._1w.height, &mut self.0.min._1w.height,
|
||||
&mut self.0.max._1w.height, &mut self.0.pct10._1w.height,
|
||||
&mut self.0.pct25._1w.height, &mut self.0.median._1w.height,
|
||||
&mut self.0.pct75._1w.height, &mut self.0.pct90._1w.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._30d, source,
|
||||
&mut self.0.average._30d.height, &mut self.0.min._30d.height,
|
||||
&mut self.0.max._30d.height, &mut self.0.pct10._30d.height,
|
||||
&mut self.0.pct25._30d.height, &mut self.0.median._30d.height,
|
||||
&mut self.0.pct75._30d.height, &mut self.0.pct90._30d.height, exit,
|
||||
max_from, windows._1m, source,
|
||||
&mut self.0.average._1m.height, &mut self.0.min._1m.height,
|
||||
&mut self.0.max._1m.height, &mut self.0.pct10._1m.height,
|
||||
&mut self.0.pct25._1m.height, &mut self.0.median._1m.height,
|
||||
&mut self.0.pct75._1m.height, &mut self.0.pct90._1m.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._1y, source,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
mod _14d;
|
||||
mod _7d_30d;
|
||||
mod _1w_1m;
|
||||
mod _2w;
|
||||
mod percent_1w_1m;
|
||||
|
||||
pub use _14d::*;
|
||||
pub use _7d_30d::*;
|
||||
pub use _1w_1m::*;
|
||||
pub use _2w::*;
|
||||
pub use percent_1w_1m::*;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{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},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
/// 2 EMA vecs (1w, 1m) sourced from 24h rolling window,
|
||||
/// each storing basis points with lazy ratio and percent float views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct PercentRollingEmas1w1m<B, M: StorageMode = Rw>(pub Emas1w1m<PercentFromHeight<B, M>>)
|
||||
where
|
||||
B: NumericValue + JsonSchema;
|
||||
|
||||
impl<B> PercentRollingEmas1w1m<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 v = version + VERSION;
|
||||
Ok(Self(Emas1w1m::try_from_fn(|suffix| {
|
||||
PercentFromHeight::forced_import::<RatioTransform, PercentTransform>(
|
||||
db,
|
||||
&format!("{name}_{suffix}"),
|
||||
v,
|
||||
indexes,
|
||||
)
|
||||
})?))
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_24h(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
height_1w_ago: &impl ReadableVec<Height, Height>,
|
||||
height_1m_ago: &impl ReadableVec<Height, Height>,
|
||||
source: &impl ReadableVec<Height, B>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
f64: From<B>,
|
||||
B: From<f64> + Default,
|
||||
{
|
||||
self._1w
|
||||
.bps
|
||||
.height
|
||||
.compute_rolling_ema(max_from, height_1w_ago, source, exit)?;
|
||||
self._1m
|
||||
.bps
|
||||
.height
|
||||
.compute_rolling_ema(max_from, height_1m_ago, source, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
mod distribution;
|
||||
mod emas;
|
||||
mod full;
|
||||
mod percent_windows;
|
||||
mod value_windows;
|
||||
mod windows;
|
||||
|
||||
pub use distribution::*;
|
||||
pub use emas::*;
|
||||
pub use full::*;
|
||||
pub use percent_windows::*;
|
||||
pub use value_windows::*;
|
||||
pub use windows::*;
|
||||
|
||||
47
crates/brk_computer/src/internal/rolling/percent_windows.rs
Normal file
47
crates/brk_computer/src/internal/rolling/percent_windows.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{Database, Rw, StorageMode, UnaryTransform};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{NumericValue, PercentFromHeight, Windows},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
/// 4 rolling window vecs (24h, 1w, 1m, 1y), each storing basis points
|
||||
/// with lazy ratio and percent float views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct PercentRollingWindows<B, M: StorageMode = Rw>(pub Windows<PercentFromHeight<B, M>>)
|
||||
where
|
||||
B: NumericValue + JsonSchema;
|
||||
|
||||
impl<B> PercentRollingWindows<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 v = version + VERSION;
|
||||
Ok(Self(Windows::try_from_fn(|suffix| {
|
||||
PercentFromHeight::forced_import::<RatioTransform, PercentTransform>(
|
||||
db,
|
||||
&format!("{name}_{suffix}"),
|
||||
v,
|
||||
indexes,
|
||||
)
|
||||
})?))
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//! RollingWindows - newtype on Windows with ComputedFromHeight per window duration.
|
||||
//!
|
||||
//! Each of the 4 windows (24h, 7d, 30d, 1y) contains a height-level stored vec
|
||||
//! Each of the 4 windows (24h, 1w, 1m, 1y) contains a height-level stored vec
|
||||
//! plus all 17 LazyAggVec index views.
|
||||
|
||||
use std::ops::SubAssign;
|
||||
@@ -18,10 +18,10 @@ use crate::{
|
||||
internal::{ComputedFromHeight, ComputedVecValue, NumericValue, Windows},
|
||||
};
|
||||
|
||||
/// Rolling window start heights — the 4 height-ago vecs (24h, 7d, 30d, 1y).
|
||||
/// Rolling window start heights — the 4 height-ago vecs (24h, 1w, 1m, 1y).
|
||||
pub type WindowStarts<'a> = Windows<&'a EagerVec<PcoVec<Height, Height>>>;
|
||||
|
||||
/// 4 rolling window vecs (24h, 7d, 30d, 1y), each with height data + all 17 index views.
|
||||
/// 4 rolling window vecs (24h, 1w, 1m, 1y), each with height data + all 17 index views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct RollingWindows<T, M: StorageMode = Rw>(pub Windows<ComputedFromHeight<T, M>>)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
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;
|
||||
@@ -16,19 +20,15 @@ mod dollars_to_sats_fract;
|
||||
mod neg_cents_to_dollars;
|
||||
mod ohlc_cents_to_dollars;
|
||||
mod ohlc_cents_to_sats;
|
||||
mod percentage_cents_f32;
|
||||
mod percentage_cents_signed_dollars_f32;
|
||||
mod percentage_cents_signed_f32;
|
||||
mod percentage_diff_close_cents;
|
||||
mod percentage_diff_close_dollars;
|
||||
mod percentage_dollars_f32;
|
||||
mod percentage_dollars_f32_neg;
|
||||
mod percentage_sats_f64;
|
||||
mod percentage_u32_f32;
|
||||
mod price_times_ratio_cents;
|
||||
mod ratio32;
|
||||
mod ratio_cents64;
|
||||
mod per_sec;
|
||||
mod ratio_bp16;
|
||||
mod ratio_bps16;
|
||||
mod ratio_bps32;
|
||||
mod ratio_u64_f32;
|
||||
mod return_f32_tenths;
|
||||
mod return_i8;
|
||||
@@ -43,9 +43,13 @@ mod days_to_years;
|
||||
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::*;
|
||||
@@ -58,22 +62,17 @@ pub use cents_to_sats::*;
|
||||
pub use neg_cents_to_dollars::*;
|
||||
pub use ohlc_cents_to_dollars::*;
|
||||
pub use ohlc_cents_to_sats::*;
|
||||
pub use percentage_cents_f32::*;
|
||||
pub use percentage_cents_signed_dollars_f32::*;
|
||||
pub use percentage_cents_signed_f32::*;
|
||||
|
||||
pub use dollar_halve::*;
|
||||
pub use dollars_to_sats_fract::*;
|
||||
pub use percentage_diff_close_cents::*;
|
||||
pub use percentage_diff_close_dollars::*;
|
||||
pub use percentage_dollars_f32::*;
|
||||
pub use percentage_dollars_f32_neg::*;
|
||||
pub use percentage_sats_f64::*;
|
||||
pub use percentage_u32_f32::*;
|
||||
pub use price_times_ratio_cents::*;
|
||||
pub use ratio32::*;
|
||||
pub use ratio_cents64::*;
|
||||
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::*;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Cents, Cents) -> StoredF32 percentage (a/b × 100)
|
||||
pub struct PercentageCentsF32;
|
||||
|
||||
impl BinaryTransform<Cents, Cents, StoredF32> for PercentageCentsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> StoredF32 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / denominator.inner() as f64 * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
use brk_types::{CentsSigned, Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (CentsSigned, Dollars) -> StoredF32 percentage (a/b × 100)
|
||||
/// For cross-type percentage when numerator is CentsSigned and denominator is Dollars.
|
||||
pub struct PercentageCentsSignedDollarsF32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Dollars, StoredF32> for PercentageCentsSignedDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Dollars) -> StoredF32 {
|
||||
if denominator == Dollars::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / *denominator * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
use brk_types::{Cents, CentsSigned, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (CentsSigned, Cents) -> StoredF32 percentage (a/b × 100)
|
||||
/// For cross-type percentage when numerator is signed.
|
||||
pub struct PercentageCentsSignedCentsF32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Cents, StoredF32> for PercentageCentsSignedCentsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Cents) -> StoredF32 {
|
||||
if denominator == Cents::ZERO {
|
||||
StoredF32::default()
|
||||
} else {
|
||||
StoredF32::from(numerator.inner() as f64 / denominator.inner() as f64 * 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF32 percentage (a/b × 100)
|
||||
/// Used for unrealized/realized ratio calculations
|
||||
pub struct PercentageDollarsF32;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, StoredF32> for PercentageDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 {
|
||||
// Dollars / Dollars returns StoredF64, so dereference and multiply
|
||||
StoredF32::from(*(numerator / denominator) * 100.0)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF32 negated percentage (-(a/b × 100))
|
||||
/// Used for negated loss ratio calculations, avoiding lazy-from-lazy chains.
|
||||
pub struct NegPercentageDollarsF32;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, StoredF32> for NegPercentageDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 {
|
||||
// Dollars / Dollars returns StoredF64, so dereference and multiply
|
||||
StoredF32::from(-(*(numerator / denominator) * 100.0))
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use brk_types::{Sats, StoredF64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (Sats, Sats) -> StoredF64 percentage (a/b × 100)
|
||||
/// Used for supply ratio calculations (equivalent to Bitcoin/Bitcoin since 1e8 cancels)
|
||||
pub struct PercentageSatsF64;
|
||||
|
||||
impl BinaryTransform<Sats, Sats, StoredF64> for PercentageSatsF64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Sats, denominator: Sats) -> StoredF64 {
|
||||
StoredF64::from((*numerator as f64 / *denominator as f64) * 100.0)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use brk_types::{StoredF32, StoredU32};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (StoredU32, StoredU32) -> StoredF32 percentage (a/b × 100)
|
||||
/// Used for pool dominance calculations (pool_blocks / total_blocks × 100)
|
||||
pub struct PercentageU32F32;
|
||||
|
||||
impl BinaryTransform<StoredU32, StoredU32, StoredF32> for PercentageU32F32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: StoredU32, denominator: StoredU32) -> StoredF32 {
|
||||
StoredF32::from((*numerator as f64 / *denominator as f64) * 100.0)
|
||||
}
|
||||
}
|
||||
73
crates/brk_computer/src/internal/transform/ratio_bp16.rs
Normal file
73
crates/brk_computer/src/internal/transform/ratio_bp16.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
62
crates/brk_computer/src/internal/transform/ratio_bps16.rs
Normal file
62
crates/brk_computer/src/internal/transform/ratio_bps16.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
32
crates/brk_computer/src/internal/transform/ratio_bps32.rs
Normal file
32
crates/brk_computer/src/internal/transform/ratio_bps32.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
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,6 +1,6 @@
|
||||
//! Base generic struct with 4 type parameters — one per rolling window duration.
|
||||
//!
|
||||
//! Foundation for all rolling window types (24h, 7d, 30d, 1y).
|
||||
//! Foundation for all rolling window types (24h, 1w, 1m, 1y).
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
|
||||
@@ -8,33 +8,33 @@ use brk_traversable::Traversable;
|
||||
pub struct Windows<A, B = A, C = A, D = A> {
|
||||
#[traversable(rename = "24h")]
|
||||
pub _24h: A,
|
||||
#[traversable(rename = "7d")]
|
||||
pub _7d: B,
|
||||
#[traversable(rename = "30d")]
|
||||
pub _30d: C,
|
||||
#[traversable(rename = "1w")]
|
||||
pub _1w: B,
|
||||
#[traversable(rename = "1m")]
|
||||
pub _1m: C,
|
||||
#[traversable(rename = "1y")]
|
||||
pub _1y: D,
|
||||
}
|
||||
|
||||
impl<A> Windows<A> {
|
||||
pub const SUFFIXES: [&'static str; 4] = ["24h", "7d", "30d", "1y"];
|
||||
pub const SUFFIXES: [&'static str; 4] = ["24h", "1w", "1m", "1y"];
|
||||
|
||||
pub fn try_from_fn<E>(
|
||||
mut f: impl FnMut(&str) -> std::result::Result<A, E>,
|
||||
) -> std::result::Result<Self, E> {
|
||||
Ok(Self {
|
||||
_24h: f(Self::SUFFIXES[0])?,
|
||||
_7d: f(Self::SUFFIXES[1])?,
|
||||
_30d: f(Self::SUFFIXES[2])?,
|
||||
_1w: f(Self::SUFFIXES[1])?,
|
||||
_1m: f(Self::SUFFIXES[2])?,
|
||||
_1y: f(Self::SUFFIXES[3])?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_array(&self) -> [&A; 4] {
|
||||
[&self._24h, &self._7d, &self._30d, &self._1y]
|
||||
[&self._24h, &self._1w, &self._1m, &self._1y]
|
||||
}
|
||||
|
||||
pub fn as_mut_array(&mut self) -> [&mut A; 4] {
|
||||
[&mut self._24h, &mut self._7d, &mut self._30d, &mut self._1y]
|
||||
[&mut self._24h, &mut self._1w, &mut self._1m, &mut self._1y]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
let mut prev = None;
|
||||
self.max_days_between_price_aths.height.compute_transform(
|
||||
self.max_days_between_price_ath.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&self.days_since_price_ath.height,
|
||||
|(i, days, slf)| {
|
||||
@@ -66,7 +66,7 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_drawdown.height.compute_drawdown(
|
||||
self.price_drawdown.compute_drawdown(
|
||||
starting_indexes.height,
|
||||
&prices.price.cents.height,
|
||||
&self.price_ath.cents.height,
|
||||
|
||||
@@ -5,7 +5,7 @@ use vecdb::Database;
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeight, DaysToYears, LazyHeightDerived, Price},
|
||||
internal::{Bps16ToFloat, Bps16ToPercent, ComputedFromHeight, DaysToYears, LazyHeightDerived, PercentFromHeight, Price},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
@@ -20,14 +20,14 @@ impl Vecs {
|
||||
|
||||
let price_ath = Price::forced_import(db, "price_ath", v, indexes)?;
|
||||
|
||||
let max_days_between_price_aths =
|
||||
ComputedFromHeight::forced_import(db, "max_days_between_price_aths", v, indexes)?;
|
||||
let max_days_between_price_ath =
|
||||
ComputedFromHeight::forced_import(db, "max_days_between_price_ath", v, indexes)?;
|
||||
|
||||
let max_years_between_price_aths =
|
||||
let max_years_between_price_ath =
|
||||
LazyHeightDerived::from_computed::<DaysToYears>(
|
||||
"max_years_between_price_aths",
|
||||
"max_years_between_price_ath",
|
||||
v,
|
||||
&max_days_between_price_aths,
|
||||
&max_days_between_price_ath,
|
||||
);
|
||||
|
||||
let days_since_price_ath =
|
||||
@@ -40,15 +40,15 @@ impl Vecs {
|
||||
);
|
||||
|
||||
let price_drawdown =
|
||||
ComputedFromHeight::forced_import(db, "price_drawdown", v, indexes)?;
|
||||
PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(db, "price_drawdown", v, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
price_ath,
|
||||
price_drawdown,
|
||||
days_since_price_ath,
|
||||
years_since_price_ath,
|
||||
max_days_between_price_aths,
|
||||
max_years_between_price_aths,
|
||||
max_days_between_price_ath,
|
||||
max_years_between_price_ath,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use brk_types::{BasisPointsSigned16, Cents, StoredF32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeight, LazyHeightDerived, Price};
|
||||
use crate::internal::{ComputedFromHeight, LazyHeightDerived, PercentFromHeight, Price};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_ath: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_drawdown: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_drawdown: PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub days_since_price_ath: ComputedFromHeight<StoredF32, M>,
|
||||
pub years_since_price_ath: LazyHeightDerived<StoredF32, StoredF32>,
|
||||
pub max_days_between_price_aths: ComputedFromHeight<StoredF32, M>,
|
||||
pub max_years_between_price_aths: LazyHeightDerived<StoredF32, StoredF32>,
|
||||
pub max_days_between_price_ath: ComputedFromHeight<StoredF32, M>,
|
||||
pub max_years_between_price_ath: LazyHeightDerived<StoredF32, StoredF32>,
|
||||
}
|
||||
|
||||
@@ -3,51 +3,51 @@ use brk_types::{Date, Day1};
|
||||
|
||||
/// DCA class years
|
||||
pub const DCA_CLASS_YEARS: ByDcaClass<u16> = ByDcaClass {
|
||||
_2015: 2015,
|
||||
_2016: 2016,
|
||||
_2017: 2017,
|
||||
_2018: 2018,
|
||||
_2019: 2019,
|
||||
_2020: 2020,
|
||||
_2021: 2021,
|
||||
_2022: 2022,
|
||||
_2023: 2023,
|
||||
_2024: 2024,
|
||||
_2025: 2025,
|
||||
_2026: 2026,
|
||||
from_2015: 2015,
|
||||
from_2016: 2016,
|
||||
from_2017: 2017,
|
||||
from_2018: 2018,
|
||||
from_2019: 2019,
|
||||
from_2020: 2020,
|
||||
from_2021: 2021,
|
||||
from_2022: 2022,
|
||||
from_2023: 2023,
|
||||
from_2024: 2024,
|
||||
from_2025: 2025,
|
||||
from_2026: 2026,
|
||||
};
|
||||
|
||||
/// DCA class names
|
||||
pub const DCA_CLASS_NAMES: ByDcaClass<&'static str> = ByDcaClass {
|
||||
_2015: "dca_class_2015",
|
||||
_2016: "dca_class_2016",
|
||||
_2017: "dca_class_2017",
|
||||
_2018: "dca_class_2018",
|
||||
_2019: "dca_class_2019",
|
||||
_2020: "dca_class_2020",
|
||||
_2021: "dca_class_2021",
|
||||
_2022: "dca_class_2022",
|
||||
_2023: "dca_class_2023",
|
||||
_2024: "dca_class_2024",
|
||||
_2025: "dca_class_2025",
|
||||
_2026: "dca_class_2026",
|
||||
from_2015: "from_2015",
|
||||
from_2016: "from_2016",
|
||||
from_2017: "from_2017",
|
||||
from_2018: "from_2018",
|
||||
from_2019: "from_2019",
|
||||
from_2020: "from_2020",
|
||||
from_2021: "from_2021",
|
||||
from_2022: "from_2022",
|
||||
from_2023: "from_2023",
|
||||
from_2024: "from_2024",
|
||||
from_2025: "from_2025",
|
||||
from_2026: "from_2026",
|
||||
};
|
||||
|
||||
/// Generic wrapper for DCA year class data
|
||||
#[derive(Clone, Default, Traversable)]
|
||||
pub struct ByDcaClass<T> {
|
||||
pub _2015: T,
|
||||
pub _2016: T,
|
||||
pub _2017: T,
|
||||
pub _2018: T,
|
||||
pub _2019: T,
|
||||
pub _2020: T,
|
||||
pub _2021: T,
|
||||
pub _2022: T,
|
||||
pub _2023: T,
|
||||
pub _2024: T,
|
||||
pub _2025: T,
|
||||
pub _2026: T,
|
||||
pub from_2015: T,
|
||||
pub from_2016: T,
|
||||
pub from_2017: T,
|
||||
pub from_2018: T,
|
||||
pub from_2019: T,
|
||||
pub from_2020: T,
|
||||
pub from_2021: T,
|
||||
pub from_2022: T,
|
||||
pub from_2023: T,
|
||||
pub from_2024: T,
|
||||
pub from_2025: T,
|
||||
pub from_2026: T,
|
||||
}
|
||||
|
||||
impl<T> ByDcaClass<T> {
|
||||
@@ -58,18 +58,18 @@ impl<T> ByDcaClass<T> {
|
||||
let n = DCA_CLASS_NAMES;
|
||||
let y = DCA_CLASS_YEARS;
|
||||
Ok(Self {
|
||||
_2015: create(n._2015, y._2015, Self::day1(y._2015))?,
|
||||
_2016: create(n._2016, y._2016, Self::day1(y._2016))?,
|
||||
_2017: create(n._2017, y._2017, Self::day1(y._2017))?,
|
||||
_2018: create(n._2018, y._2018, Self::day1(y._2018))?,
|
||||
_2019: create(n._2019, y._2019, Self::day1(y._2019))?,
|
||||
_2020: create(n._2020, y._2020, Self::day1(y._2020))?,
|
||||
_2021: create(n._2021, y._2021, Self::day1(y._2021))?,
|
||||
_2022: create(n._2022, y._2022, Self::day1(y._2022))?,
|
||||
_2023: create(n._2023, y._2023, Self::day1(y._2023))?,
|
||||
_2024: create(n._2024, y._2024, Self::day1(y._2024))?,
|
||||
_2025: create(n._2025, y._2025, Self::day1(y._2025))?,
|
||||
_2026: create(n._2026, y._2026, Self::day1(y._2026))?,
|
||||
from_2015: create(n.from_2015, y.from_2015, Self::day1(y.from_2015))?,
|
||||
from_2016: create(n.from_2016, y.from_2016, Self::day1(y.from_2016))?,
|
||||
from_2017: create(n.from_2017, y.from_2017, Self::day1(y.from_2017))?,
|
||||
from_2018: create(n.from_2018, y.from_2018, Self::day1(y.from_2018))?,
|
||||
from_2019: create(n.from_2019, y.from_2019, Self::day1(y.from_2019))?,
|
||||
from_2020: create(n.from_2020, y.from_2020, Self::day1(y.from_2020))?,
|
||||
from_2021: create(n.from_2021, y.from_2021, Self::day1(y.from_2021))?,
|
||||
from_2022: create(n.from_2022, y.from_2022, Self::day1(y.from_2022))?,
|
||||
from_2023: create(n.from_2023, y.from_2023, Self::day1(y.from_2023))?,
|
||||
from_2024: create(n.from_2024, y.from_2024, Self::day1(y.from_2024))?,
|
||||
from_2025: create(n.from_2025, y.from_2025, Self::day1(y.from_2025))?,
|
||||
from_2026: create(n.from_2026, y.from_2026, Self::day1(y.from_2026))?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,36 +79,36 @@ impl<T> ByDcaClass<T> {
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
[
|
||||
&self._2015,
|
||||
&self._2016,
|
||||
&self._2017,
|
||||
&self._2018,
|
||||
&self._2019,
|
||||
&self._2020,
|
||||
&self._2021,
|
||||
&self._2022,
|
||||
&self._2023,
|
||||
&self._2024,
|
||||
&self._2025,
|
||||
&self._2026,
|
||||
&self.from_2015,
|
||||
&self.from_2016,
|
||||
&self.from_2017,
|
||||
&self.from_2018,
|
||||
&self.from_2019,
|
||||
&self.from_2020,
|
||||
&self.from_2021,
|
||||
&self.from_2022,
|
||||
&self.from_2023,
|
||||
&self.from_2024,
|
||||
&self.from_2025,
|
||||
&self.from_2026,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||
[
|
||||
&mut self._2015,
|
||||
&mut self._2016,
|
||||
&mut self._2017,
|
||||
&mut self._2018,
|
||||
&mut self._2019,
|
||||
&mut self._2020,
|
||||
&mut self._2021,
|
||||
&mut self._2022,
|
||||
&mut self._2023,
|
||||
&mut self._2024,
|
||||
&mut self._2025,
|
||||
&mut self._2026,
|
||||
&mut self.from_2015,
|
||||
&mut self.from_2016,
|
||||
&mut self.from_2017,
|
||||
&mut self.from_2018,
|
||||
&mut self.from_2019,
|
||||
&mut self.from_2020,
|
||||
&mut self.from_2021,
|
||||
&mut self.from_2022,
|
||||
&mut self.from_2023,
|
||||
&mut self.from_2024,
|
||||
&mut self.from_2025,
|
||||
&mut self.from_2026,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
@@ -116,19 +116,18 @@ impl<T> ByDcaClass<T> {
|
||||
pub(crate) fn start_days() -> [Day1; 12] {
|
||||
let y = DCA_CLASS_YEARS;
|
||||
[
|
||||
Self::day1(y._2015),
|
||||
Self::day1(y._2016),
|
||||
Self::day1(y._2017),
|
||||
Self::day1(y._2018),
|
||||
Self::day1(y._2019),
|
||||
Self::day1(y._2020),
|
||||
Self::day1(y._2021),
|
||||
Self::day1(y._2022),
|
||||
Self::day1(y._2023),
|
||||
Self::day1(y._2024),
|
||||
Self::day1(y._2025),
|
||||
Self::day1(y._2026),
|
||||
Self::day1(y.from_2015),
|
||||
Self::day1(y.from_2016),
|
||||
Self::day1(y.from_2017),
|
||||
Self::day1(y.from_2018),
|
||||
Self::day1(y.from_2019),
|
||||
Self::day1(y.from_2020),
|
||||
Self::day1(y.from_2021),
|
||||
Self::day1(y.from_2022),
|
||||
Self::day1(y.from_2023),
|
||||
Self::day1(y.from_2024),
|
||||
Self::day1(y.from_2025),
|
||||
Self::day1(y.from_2026),
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Bitcoin, Cents, Date, Day1, Dollars, Sats, StoredF32};
|
||||
use brk_types::{BasisPointsSigned32, Bitcoin, Cents, Date, Day1, Dollars, Sats};
|
||||
use vecdb::{AnyVec, Exit, ReadableOptionVec, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
ComputeIndexes, blocks, indexes, internal::PercentageDiffCents, market::lookback, prices,
|
||||
ComputeIndexes, blocks, indexes, internal::RatioDiffCentsBps32, market::lookback, prices,
|
||||
};
|
||||
|
||||
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
|
||||
@@ -65,7 +65,7 @@ impl Vecs {
|
||||
// DCA by period - average price (derived from stack)
|
||||
let sh = starting_indexes.height.to_usize();
|
||||
for (average_price, stack, days) in self
|
||||
.period_average_price
|
||||
.period_cost_basis
|
||||
.zip_mut_with_days(&self.period_stack)
|
||||
{
|
||||
let days = days as usize;
|
||||
@@ -93,11 +93,11 @@ impl Vecs {
|
||||
|
||||
// DCA by period - returns (compute from average price)
|
||||
for (returns, (average_price, _)) in self
|
||||
.period_returns
|
||||
.period_return
|
||||
.iter_mut()
|
||||
.zip(self.period_average_price.iter_with_days())
|
||||
.zip(self.period_cost_basis.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Cents, Cents, PercentageDiffCents>(
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCentsBps32>(
|
||||
starting_indexes.height,
|
||||
&prices.price.cents.height,
|
||||
&average_price.cents.height,
|
||||
@@ -106,21 +106,22 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// DCA by period - CAGR (computed from returns at height level)
|
||||
for (cagr, returns, days) in self.period_cagr.zip_mut_with_period(&self.period_returns) {
|
||||
let years = days as f32 / 365.0;
|
||||
cagr.height.compute_transform(
|
||||
for (cagr, returns, days) in self.period_cagr.zip_mut_with_period(&self.period_return) {
|
||||
let years = days as f64 / 365.0;
|
||||
cagr.bps.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&returns.height,
|
||||
&returns.bps.height,
|
||||
|(h, r, ..)| {
|
||||
let v = ((*r / 100.0 + 1.0).powf(1.0 / years) - 1.0) * 100.0;
|
||||
(h, StoredF32::from(v))
|
||||
let ratio = f64::from(r);
|
||||
let v = (ratio + 1.0).powf(1.0 / years) - 1.0;
|
||||
(h, BasisPointsSigned32::from(v))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
// Lump sum by period - stack
|
||||
let lookback_dca = lookback.price_ago.as_dca_period();
|
||||
let lookback_dca = lookback.price_lookback.as_dca_period();
|
||||
for (stack, lookback_price, days) in
|
||||
self.period_lump_sum_stack.zip_mut_with_days(&lookback_dca)
|
||||
{
|
||||
@@ -146,13 +147,13 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// Lump sum by period - returns (compute from lookback price)
|
||||
let lookback_dca2 = lookback.price_ago.as_dca_period();
|
||||
let lookback_dca2 = lookback.price_lookback.as_dca_period();
|
||||
for (returns, (lookback_price, _)) in self
|
||||
.period_lump_sum_returns
|
||||
.period_lump_sum_return
|
||||
.iter_mut()
|
||||
.zip(lookback_dca2.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Cents, Cents, PercentageDiffCents>(
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCentsBps32>(
|
||||
starting_indexes.height,
|
||||
&prices.price.cents.height,
|
||||
&lookback_price.cents.height,
|
||||
@@ -214,7 +215,7 @@ impl Vecs {
|
||||
// DCA by year class - average price (derived from stack)
|
||||
let start_days = super::ByDcaClass::<()>::start_days();
|
||||
for ((average_price, stack), from) in self
|
||||
.class_average_price
|
||||
.class_cost_basis
|
||||
.iter_mut()
|
||||
.zip(self.class_stack.iter())
|
||||
.zip(start_days)
|
||||
@@ -243,11 +244,11 @@ impl Vecs {
|
||||
|
||||
// DCA by year class - returns (compute from average price)
|
||||
for (returns, average_price) in self
|
||||
.class_returns
|
||||
.class_return
|
||||
.iter_mut()
|
||||
.zip(self.class_average_price.iter())
|
||||
.zip(self.class_cost_basis.iter())
|
||||
{
|
||||
returns.compute_binary::<Cents, Cents, PercentageDiffCents>(
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCentsBps32>(
|
||||
starting_indexes.height,
|
||||
&prices.price.cents.height,
|
||||
&average_price.cents.height,
|
||||
|
||||
@@ -5,7 +5,7 @@ use vecdb::{Database, ImportableVec};
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, Vecs};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeight, Price, ValueFromHeight},
|
||||
internal::{Bps32ToFloat, Bps32ToPercent, PercentFromHeight, Price, ValueFromHeight},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -15,57 +15,72 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let period_stack = ByDcaPeriod::try_new(|name, _days| {
|
||||
ValueFromHeight::forced_import(db, &format!("{name}_dca_stack"), version, indexes)
|
||||
ValueFromHeight::forced_import(db, &format!("dca_stack_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let period_average_price = ByDcaPeriod::try_new(|name, _days| {
|
||||
Price::forced_import(db, &format!("{name}_dca_average_price"), version, indexes)
|
||||
let period_cost_basis = ByDcaPeriod::try_new(|name, _days| {
|
||||
Price::forced_import(db, &format!("dca_cost_basis_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let period_returns = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromHeight::forced_import(db, &format!("{name}_dca_returns"), version, indexes)
|
||||
let period_return = ByDcaPeriod::try_new(|name, _days| {
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
&format!("dca_return_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_cagr = ByDcaCagr::try_new(|name, _days| {
|
||||
ComputedFromHeight::forced_import(db, &format!("{name}_dca_cagr"), version, indexes)
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
&format!("dca_cagr_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_lump_sum_stack = ByDcaPeriod::try_new(|name, _days| {
|
||||
ValueFromHeight::forced_import(db, &format!("{name}_lump_sum_stack"), version, indexes)
|
||||
ValueFromHeight::forced_import(db, &format!("lump_sum_stack_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let period_lump_sum_returns = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromHeight::forced_import(
|
||||
let period_lump_sum_return = ByDcaPeriod::try_new(|name, _days| {
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
&format!("{name}_lump_sum_returns"),
|
||||
&format!("lump_sum_return_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let class_stack = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
ValueFromHeight::forced_import(db, &format!("{name}_stack"), version, indexes)
|
||||
ValueFromHeight::forced_import(db, &format!("dca_stack_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let class_average_price = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
Price::forced_import(db, &format!("{name}_average_price"), version, indexes)
|
||||
let class_cost_basis = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
Price::forced_import(db, &format!("dca_cost_basis_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let class_returns = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
ComputedFromHeight::forced_import(db, &format!("{name}_returns"), version, indexes)
|
||||
let class_return = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
&format!("dca_return_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
dca_sats_per_day: ImportableVec::forced_import(db, "dca_sats_per_day", version)?,
|
||||
period_stack,
|
||||
period_average_price,
|
||||
period_returns,
|
||||
period_cost_basis,
|
||||
period_return,
|
||||
period_cagr,
|
||||
period_lump_sum_stack,
|
||||
period_lump_sum_returns,
|
||||
period_lump_sum_return,
|
||||
class_stack,
|
||||
class_average_price,
|
||||
class_returns,
|
||||
class_cost_basis,
|
||||
class_return,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Height, Sats, StoredF32};
|
||||
use brk_types::{BasisPointsSigned32, Cents, Height, Sats};
|
||||
use vecdb::{EagerVec, PcoVec, Rw, StorageMode};
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod};
|
||||
use crate::internal::{ComputedFromHeight, Price, ValueFromHeight};
|
||||
use crate::internal::{ComputedFromHeight, PercentFromHeight, Price, ValueFromHeight};
|
||||
|
||||
/// Dollar-cost averaging metrics by time period and year class
|
||||
#[derive(Traversable)]
|
||||
@@ -14,16 +14,16 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
// DCA by period
|
||||
pub period_stack: ByDcaPeriod<ValueFromHeight<M>>,
|
||||
pub period_average_price: ByDcaPeriod<Price<ComputedFromHeight<Cents, M>>>,
|
||||
pub period_returns: ByDcaPeriod<ComputedFromHeight<StoredF32, M>>,
|
||||
pub period_cagr: ByDcaCagr<ComputedFromHeight<StoredF32, M>>,
|
||||
pub period_cost_basis: ByDcaPeriod<Price<ComputedFromHeight<Cents, M>>>,
|
||||
pub period_return: ByDcaPeriod<PercentFromHeight<BasisPointsSigned32, M>>,
|
||||
pub period_cagr: ByDcaCagr<PercentFromHeight<BasisPointsSigned32, M>>,
|
||||
|
||||
// Lump sum by period (for comparison with DCA)
|
||||
pub period_lump_sum_stack: ByDcaPeriod<ValueFromHeight<M>>,
|
||||
pub period_lump_sum_returns: ByDcaPeriod<ComputedFromHeight<StoredF32, M>>,
|
||||
pub period_lump_sum_return: ByDcaPeriod<PercentFromHeight<BasisPointsSigned32, M>>,
|
||||
|
||||
// DCA by year class
|
||||
pub class_stack: ByDcaClass<ValueFromHeight<M>>,
|
||||
pub class_average_price: ByDcaClass<Price<ComputedFromHeight<Cents, M>>>,
|
||||
pub class_returns: ByDcaClass<ComputedFromHeight<StoredF32, M>>,
|
||||
pub class_cost_basis: ByDcaClass<Price<ComputedFromHeight<Cents, M>>>,
|
||||
pub class_return: ByDcaClass<PercentFromHeight<BasisPointsSigned32, M>>,
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ use vecdb::Exit;
|
||||
use super::{super::range, Vecs};
|
||||
use crate::{
|
||||
ComputeIndexes, blocks, distribution,
|
||||
internal::Ratio32,
|
||||
internal::{Ratio32, Windows},
|
||||
mining, prices, transactions,
|
||||
};
|
||||
|
||||
fn tf_multiplier(tf: &str) -> usize {
|
||||
match tf {
|
||||
"1d" => 1,
|
||||
"24h" => 1,
|
||||
"1w" => 7,
|
||||
"1m" => 30,
|
||||
"1y" => 365,
|
||||
@@ -37,7 +37,7 @@ impl Vecs {
|
||||
self.puell_multiple.height.compute_divide(
|
||||
starting_indexes.height,
|
||||
&rewards.subsidy.base.usd.height,
|
||||
&rewards.subsidy_usd_1y_sma.usd.height,
|
||||
&rewards.subsidy_sma_1y.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -47,8 +47,8 @@ impl Vecs {
|
||||
self.stoch_k.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
price,
|
||||
&range.price_2w_min.usd.height,
|
||||
&range.price_2w_max.usd.height,
|
||||
&range.price_min_2w.usd.height,
|
||||
&range.price_max_2w.usd.height,
|
||||
|(h, close, low, high, ..)| {
|
||||
let range = *high - *low;
|
||||
let stoch = if range == 0.0 {
|
||||
@@ -70,13 +70,15 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// RSI per timeframe
|
||||
for (tf, rsi_chain) in self.rsi.iter_mut() {
|
||||
for (tf, rsi_chain) in Windows::<()>::SUFFIXES.into_iter()
|
||||
.zip(self.rsi.as_mut_array())
|
||||
{
|
||||
let m = tf_multiplier(tf);
|
||||
let returns_source = match tf {
|
||||
"1d" => &returns.price_returns._24h.height,
|
||||
"1w" => &returns.price_returns._1w.height,
|
||||
"1m" => &returns.price_returns._1m.height,
|
||||
"1y" => &returns.price_returns._1y.height,
|
||||
"24h" => &returns.price_return._24h.height,
|
||||
"1w" => &returns.price_return._1w.height,
|
||||
"1m" => &returns.price_return._1m.height,
|
||||
"1y" => &returns.price_return._1y.height,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
super::rsi::compute(
|
||||
@@ -91,7 +93,9 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// MACD per timeframe
|
||||
for (tf, macd_chain) in self.macd.iter_mut() {
|
||||
for (tf, macd_chain) in Windows::<()>::SUFFIXES.into_iter()
|
||||
.zip(self.macd.as_mut_array())
|
||||
{
|
||||
let m = tf_multiplier(tf);
|
||||
super::macd::compute(
|
||||
macd_chain,
|
||||
@@ -124,8 +128,8 @@ impl Vecs {
|
||||
// Pi Cycle: sma_111d / sma_350d_x2
|
||||
self.pi_cycle.compute_binary::<Dollars, Dollars, Ratio32>(
|
||||
starting_indexes.height,
|
||||
&moving_average.price_111d_sma.price.usd.height,
|
||||
&moving_average.price_350d_sma_x2.usd.height,
|
||||
&moving_average.price_sma_111d.price.usd.height,
|
||||
&moving_average.price_sma_350d_x2.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Sats, StoredF32, StoredU64, Version};
|
||||
use brk_types::{BasisPoints16, Sats, StoredU64, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec};
|
||||
|
||||
use crate::{ComputeIndexes, distribution, internal::ComputedFromHeight};
|
||||
use crate::{ComputeIndexes, distribution, internal::PercentFromHeight};
|
||||
|
||||
pub(super) fn compute(
|
||||
gini: &mut ComputedFromHeight<StoredF32>,
|
||||
gini: &mut PercentFromHeight<BasisPoints16>,
|
||||
distribution: &distribution::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
@@ -32,10 +32,10 @@ pub(super) fn compute(
|
||||
.iter()
|
||||
.fold(Version::ZERO, |acc, v| acc + v.version());
|
||||
|
||||
gini.height
|
||||
gini.bps.height
|
||||
.validate_computed_version_or_reset(source_version)?;
|
||||
gini.height
|
||||
.truncate_if_needed_at(gini.height.len().min(starting_indexes.height.to_usize()))?;
|
||||
gini.bps.height
|
||||
.truncate_if_needed_at(gini.bps.height.len().min(starting_indexes.height.to_usize()))?;
|
||||
|
||||
let total_heights = supply_vecs
|
||||
.iter()
|
||||
@@ -44,7 +44,7 @@ pub(super) fn compute(
|
||||
.unwrap_or(0)
|
||||
.min(count_vecs.iter().map(|v| v.len()).min().unwrap_or(0));
|
||||
|
||||
let start_height = gini.height.len();
|
||||
let start_height = gini.bps.height.len();
|
||||
if start_height >= total_heights {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -68,24 +68,24 @@ pub(super) fn compute(
|
||||
let count: u64 = count_data[c][offset].into();
|
||||
buckets.push((count, supply));
|
||||
}
|
||||
gini.height
|
||||
.push(StoredF32::from(gini_from_lorenz(&buckets)));
|
||||
gini.bps.height
|
||||
.push(gini_from_lorenz(&buckets));
|
||||
}
|
||||
|
||||
{
|
||||
let _lock = exit.lock();
|
||||
gini.height.write()?;
|
||||
gini.bps.height.write()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gini_from_lorenz(buckets: &[(u64, u64)]) -> f32 {
|
||||
fn gini_from_lorenz(buckets: &[(u64, u64)]) -> BasisPoints16 {
|
||||
let total_count: u64 = buckets.iter().map(|(c, _)| c).sum();
|
||||
let total_supply: u64 = buckets.iter().map(|(_, s)| s).sum();
|
||||
|
||||
if total_count == 0 || total_supply == 0 {
|
||||
return f32::NAN;
|
||||
return BasisPoints16::ZERO;
|
||||
}
|
||||
|
||||
let (mut cumulative_count, mut cumulative_supply, mut area) = (0u64, 0u64, 0.0f64);
|
||||
@@ -99,5 +99,5 @@ fn gini_from_lorenz(buckets: &[(u64, u64)]) -> f32 {
|
||||
area += (p1 - p0) * (w0 + w1) / 2.0;
|
||||
}
|
||||
|
||||
(1.0 - 2.0 * area) as f32
|
||||
BasisPoints16::from(1.0 - 2.0 * area)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
|
||||
use super::{ByIndicatorTimeframe, MacdChain, RsiChain, Vecs};
|
||||
use super::{MacdChain, RsiChain, Vecs};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::ComputedFromHeight,
|
||||
internal::{Bp16ToFloat, Bp16ToPercent, ComputedFromHeight, PercentFromHeight, Windows},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
@@ -28,8 +28,8 @@ impl RsiChain {
|
||||
};
|
||||
}
|
||||
|
||||
let average_gain = import!("avg_gain");
|
||||
let average_loss = import!("avg_loss");
|
||||
let average_gain = import!("average_gain");
|
||||
let average_loss = import!("average_loss");
|
||||
|
||||
let rsi = ComputedFromHeight::forced_import(
|
||||
db,
|
||||
@@ -44,11 +44,11 @@ impl RsiChain {
|
||||
average_gain,
|
||||
average_loss,
|
||||
rsi,
|
||||
rsi_min: import!("rsi_min"),
|
||||
rsi_max: import!("rsi_max"),
|
||||
stoch_rsi: import!("stoch_rsi"),
|
||||
stoch_rsi_k: import!("stoch_rsi_k"),
|
||||
stoch_rsi_d: import!("stoch_rsi_d"),
|
||||
rsi_min: import!("min"),
|
||||
rsi_max: import!("max"),
|
||||
stoch_rsi: import!("stoch"),
|
||||
stoch_rsi_k: import!("stoch_k"),
|
||||
stoch_rsi_d: import!("stoch_d"),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -110,12 +110,12 @@ impl Vecs {
|
||||
|
||||
let nvt = ComputedFromHeight::forced_import(db, "nvt", v, indexes)?;
|
||||
|
||||
let rsi = ByIndicatorTimeframe::try_new(|tf| RsiChain::forced_import(db, tf, v, indexes))?;
|
||||
let macd = ByIndicatorTimeframe::try_new(|tf| MacdChain::forced_import(db, tf, 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 = ComputedFromHeight::forced_import(db, "gini", v, indexes)?;
|
||||
let gini = PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, "gini", v, indexes)?;
|
||||
|
||||
let pi_cycle = ComputedFromHeight::forced_import(db, "pi_cycle", v, indexes)?;
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ mod macd;
|
||||
mod rsi;
|
||||
mod vecs;
|
||||
|
||||
pub use vecs::{ByIndicatorTimeframe, MacdChain, RsiChain, Vecs};
|
||||
pub use vecs::{MacdChain, RsiChain, Vecs};
|
||||
|
||||
@@ -1,39 +1,8 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::StoredF32;
|
||||
use brk_types::{BasisPoints16, StoredF32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::ComputedFromHeight;
|
||||
|
||||
pub const TIMEFRAME_NAMES: [&str; 4] = ["1d", "1w", "1m", "1y"];
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct ByIndicatorTimeframe<T> {
|
||||
pub _1d: T,
|
||||
pub _1w: T,
|
||||
pub _1m: T,
|
||||
pub _1y: T,
|
||||
}
|
||||
|
||||
impl<T> ByIndicatorTimeframe<T> {
|
||||
pub fn try_new<E>(mut create: impl FnMut(&str) -> Result<T, E>) -> Result<Self, E> {
|
||||
Ok(Self {
|
||||
_1d: create(TIMEFRAME_NAMES[0])?,
|
||||
_1w: create(TIMEFRAME_NAMES[1])?,
|
||||
_1m: create(TIMEFRAME_NAMES[2])?,
|
||||
_1y: create(TIMEFRAME_NAMES[3])?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut T)> {
|
||||
[
|
||||
(TIMEFRAME_NAMES[0], &mut self._1d),
|
||||
(TIMEFRAME_NAMES[1], &mut self._1w),
|
||||
(TIMEFRAME_NAMES[2], &mut self._1m),
|
||||
(TIMEFRAME_NAMES[3], &mut self._1y),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
use crate::internal::{ComputedFromHeight, PercentFromHeight, Windows};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RsiChain<M: StorageMode = Rw> {
|
||||
@@ -63,14 +32,14 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub puell_multiple: ComputedFromHeight<StoredF32, M>,
|
||||
pub nvt: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
pub rsi: ByIndicatorTimeframe<RsiChain<M>>,
|
||||
pub rsi: Windows<RsiChain<M>>,
|
||||
|
||||
pub stoch_k: ComputedFromHeight<StoredF32, M>,
|
||||
pub stoch_d: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
pub pi_cycle: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
pub macd: ByIndicatorTimeframe<MacdChain<M>>,
|
||||
pub macd: Windows<MacdChain<M>>,
|
||||
|
||||
pub gini: ComputedFromHeight<StoredF32, M>,
|
||||
pub gini: PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ impl Vecs {
|
||||
) -> Result<()> {
|
||||
let price = &prices.price.cents.height;
|
||||
|
||||
for (price_ago, days) in self.price_ago.iter_mut_with_days() {
|
||||
for (price_lookback, days) in self.price_lookback.iter_mut_with_days() {
|
||||
let window_starts = blocks.count.start_vec(days as usize);
|
||||
price_ago.cents.height.compute_lookback(
|
||||
price_lookback.cents.height.compute_lookback(
|
||||
starting_indexes.height,
|
||||
window_starts,
|
||||
price,
|
||||
|
||||
@@ -7,10 +7,10 @@ use crate::{indexes, internal::Price};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
|
||||
let price_ago = ByLookbackPeriod::try_new(|name, _days| {
|
||||
Price::forced_import(db, &format!("price_{name}_ago"), version, indexes)
|
||||
let price_lookback = ByLookbackPeriod::try_new(|name, _days| {
|
||||
Price::forced_import(db, &format!("price_lookback_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
Ok(Self { price_ago })
|
||||
Ok(Self { price_lookback })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ use crate::internal::{ComputedFromHeight, Price};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub price_ago: ByLookbackPeriod<Price<ComputedFromHeight<Cents, M>>>,
|
||||
pub price_lookback: ByLookbackPeriod<Price<ComputedFromHeight<Cents, M>>>,
|
||||
}
|
||||
|
||||
@@ -15,22 +15,22 @@ impl Vecs {
|
||||
let close = &prices.price.cents.height;
|
||||
|
||||
for (sma, period) in [
|
||||
(&mut self.price_1w_sma, 7),
|
||||
(&mut self.price_8d_sma, 8),
|
||||
(&mut self.price_13d_sma, 13),
|
||||
(&mut self.price_21d_sma, 21),
|
||||
(&mut self.price_1m_sma, 30),
|
||||
(&mut self.price_34d_sma, 34),
|
||||
(&mut self.price_55d_sma, 55),
|
||||
(&mut self.price_89d_sma, 89),
|
||||
(&mut self.price_111d_sma, 111),
|
||||
(&mut self.price_144d_sma, 144),
|
||||
(&mut self.price_200d_sma, 200),
|
||||
(&mut self.price_350d_sma, 350),
|
||||
(&mut self.price_1y_sma, 365),
|
||||
(&mut self.price_2y_sma, 2 * 365),
|
||||
(&mut self.price_200w_sma, 200 * 7),
|
||||
(&mut self.price_4y_sma, 4 * 365),
|
||||
(&mut self.price_sma_1w, 7),
|
||||
(&mut self.price_sma_8d, 8),
|
||||
(&mut self.price_sma_13d, 13),
|
||||
(&mut self.price_sma_21d, 21),
|
||||
(&mut self.price_sma_1m, 30),
|
||||
(&mut self.price_sma_34d, 34),
|
||||
(&mut self.price_sma_55d, 55),
|
||||
(&mut self.price_sma_89d, 89),
|
||||
(&mut self.price_sma_111d, 111),
|
||||
(&mut self.price_sma_144d, 144),
|
||||
(&mut self.price_sma_200d, 200),
|
||||
(&mut self.price_sma_350d, 350),
|
||||
(&mut self.price_sma_1y, 365),
|
||||
(&mut self.price_sma_2y, 2 * 365),
|
||||
(&mut self.price_sma_200w, 200 * 7),
|
||||
(&mut self.price_sma_4y, 4 * 365),
|
||||
] {
|
||||
let window_starts = blocks.count.start_vec(period);
|
||||
sma.compute_all(blocks, prices, starting_indexes, exit, |v| {
|
||||
@@ -40,22 +40,22 @@ impl Vecs {
|
||||
}
|
||||
|
||||
for (ema, period) in [
|
||||
(&mut self.price_1w_ema, 7),
|
||||
(&mut self.price_8d_ema, 8),
|
||||
(&mut self.price_12d_ema, 12),
|
||||
(&mut self.price_13d_ema, 13),
|
||||
(&mut self.price_21d_ema, 21),
|
||||
(&mut self.price_26d_ema, 26),
|
||||
(&mut self.price_1m_ema, 30),
|
||||
(&mut self.price_34d_ema, 34),
|
||||
(&mut self.price_55d_ema, 55),
|
||||
(&mut self.price_89d_ema, 89),
|
||||
(&mut self.price_144d_ema, 144),
|
||||
(&mut self.price_200d_ema, 200),
|
||||
(&mut self.price_1y_ema, 365),
|
||||
(&mut self.price_2y_ema, 2 * 365),
|
||||
(&mut self.price_200w_ema, 200 * 7),
|
||||
(&mut self.price_4y_ema, 4 * 365),
|
||||
(&mut self.price_ema_1w, 7),
|
||||
(&mut self.price_ema_8d, 8),
|
||||
(&mut self.price_ema_12d, 12),
|
||||
(&mut self.price_ema_13d, 13),
|
||||
(&mut self.price_ema_21d, 21),
|
||||
(&mut self.price_ema_26d, 26),
|
||||
(&mut self.price_ema_1m, 30),
|
||||
(&mut self.price_ema_34d, 34),
|
||||
(&mut self.price_ema_55d, 55),
|
||||
(&mut self.price_ema_89d, 89),
|
||||
(&mut self.price_ema_144d, 144),
|
||||
(&mut self.price_ema_200d, 200),
|
||||
(&mut self.price_ema_1y, 365),
|
||||
(&mut self.price_ema_2y, 2 * 365),
|
||||
(&mut self.price_ema_200w, 200 * 7),
|
||||
(&mut self.price_ema_4y, 4 * 365),
|
||||
] {
|
||||
let window_starts = blocks.count.start_vec(period);
|
||||
ema.compute_all(blocks, prices, starting_indexes, exit, |v| {
|
||||
|
||||
@@ -25,66 +25,66 @@ impl Vecs {
|
||||
};
|
||||
}
|
||||
|
||||
let price_200d_sma = import!("price_200d_sma");
|
||||
let price_350d_sma = import!("price_350d_sma");
|
||||
let price_sma_200d = import!("price_sma_200d");
|
||||
let price_sma_350d = import!("price_sma_350d");
|
||||
|
||||
let price_200d_sma_source = &price_200d_sma.price.cents;
|
||||
let price_200d_sma_x2_4 = Price::from_cents_source::<CentsTimesTenths<24>>(
|
||||
"price_200d_sma_x2_4",
|
||||
let price_sma_200d_source = &price_sma_200d.price.cents;
|
||||
let price_sma_200d_x2_4 = Price::from_cents_source::<CentsTimesTenths<24>>(
|
||||
"price_sma_200d_x2_4",
|
||||
version,
|
||||
price_200d_sma_source,
|
||||
price_sma_200d_source,
|
||||
);
|
||||
let price_200d_sma_x0_8 = Price::from_cents_source::<CentsTimesTenths<8>>(
|
||||
"price_200d_sma_x0_8",
|
||||
let price_sma_200d_x0_8 = Price::from_cents_source::<CentsTimesTenths<8>>(
|
||||
"price_sma_200d_x0_8",
|
||||
version,
|
||||
price_200d_sma_source,
|
||||
price_sma_200d_source,
|
||||
);
|
||||
|
||||
let price_350d_sma_source = &price_350d_sma.price.cents;
|
||||
let price_350d_sma_x2 = Price::from_cents_source::<CentsTimesTenths<20>>(
|
||||
"price_350d_sma_x2",
|
||||
let price_sma_350d_source = &price_sma_350d.price.cents;
|
||||
let price_sma_350d_x2 = Price::from_cents_source::<CentsTimesTenths<20>>(
|
||||
"price_sma_350d_x2",
|
||||
version,
|
||||
price_350d_sma_source,
|
||||
price_sma_350d_source,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
price_1w_sma: import!("price_1w_sma"),
|
||||
price_8d_sma: import!("price_8d_sma"),
|
||||
price_13d_sma: import!("price_13d_sma"),
|
||||
price_21d_sma: import!("price_21d_sma"),
|
||||
price_1m_sma: import!("price_1m_sma"),
|
||||
price_34d_sma: import!("price_34d_sma"),
|
||||
price_55d_sma: import!("price_55d_sma"),
|
||||
price_89d_sma: import!("price_89d_sma"),
|
||||
price_111d_sma: import!("price_111d_sma"),
|
||||
price_144d_sma: import!("price_144d_sma"),
|
||||
price_200d_sma,
|
||||
price_350d_sma,
|
||||
price_1y_sma: import!("price_1y_sma"),
|
||||
price_2y_sma: import!("price_2y_sma"),
|
||||
price_200w_sma: import!("price_200w_sma"),
|
||||
price_4y_sma: import!("price_4y_sma"),
|
||||
price_sma_1w: import!("price_sma_1w"),
|
||||
price_sma_8d: import!("price_sma_8d"),
|
||||
price_sma_13d: import!("price_sma_13d"),
|
||||
price_sma_21d: import!("price_sma_21d"),
|
||||
price_sma_1m: import!("price_sma_1m"),
|
||||
price_sma_34d: import!("price_sma_34d"),
|
||||
price_sma_55d: import!("price_sma_55d"),
|
||||
price_sma_89d: import!("price_sma_89d"),
|
||||
price_sma_111d: import!("price_sma_111d"),
|
||||
price_sma_144d: import!("price_sma_144d"),
|
||||
price_sma_200d,
|
||||
price_sma_350d,
|
||||
price_sma_1y: import!("price_sma_1y"),
|
||||
price_sma_2y: import!("price_sma_2y"),
|
||||
price_sma_200w: import!("price_sma_200w"),
|
||||
price_sma_4y: import!("price_sma_4y"),
|
||||
|
||||
price_1w_ema: import!("price_1w_ema"),
|
||||
price_8d_ema: import!("price_8d_ema"),
|
||||
price_12d_ema: import!("price_12d_ema"),
|
||||
price_13d_ema: import!("price_13d_ema"),
|
||||
price_21d_ema: import!("price_21d_ema"),
|
||||
price_26d_ema: import!("price_26d_ema"),
|
||||
price_1m_ema: import!("price_1m_ema"),
|
||||
price_34d_ema: import!("price_34d_ema"),
|
||||
price_55d_ema: import!("price_55d_ema"),
|
||||
price_89d_ema: import!("price_89d_ema"),
|
||||
price_144d_ema: import!("price_144d_ema"),
|
||||
price_200d_ema: import!("price_200d_ema"),
|
||||
price_1y_ema: import!("price_1y_ema"),
|
||||
price_2y_ema: import!("price_2y_ema"),
|
||||
price_200w_ema: import!("price_200w_ema"),
|
||||
price_4y_ema: import!("price_4y_ema"),
|
||||
price_ema_1w: import!("price_ema_1w"),
|
||||
price_ema_8d: import!("price_ema_8d"),
|
||||
price_ema_12d: import!("price_ema_12d"),
|
||||
price_ema_13d: import!("price_ema_13d"),
|
||||
price_ema_21d: import!("price_ema_21d"),
|
||||
price_ema_26d: import!("price_ema_26d"),
|
||||
price_ema_1m: import!("price_ema_1m"),
|
||||
price_ema_34d: import!("price_ema_34d"),
|
||||
price_ema_55d: import!("price_ema_55d"),
|
||||
price_ema_89d: import!("price_ema_89d"),
|
||||
price_ema_144d: import!("price_ema_144d"),
|
||||
price_ema_200d: import!("price_ema_200d"),
|
||||
price_ema_1y: import!("price_ema_1y"),
|
||||
price_ema_2y: import!("price_ema_2y"),
|
||||
price_ema_200w: import!("price_ema_200w"),
|
||||
price_ema_4y: import!("price_ema_4y"),
|
||||
|
||||
price_200d_sma_x2_4,
|
||||
price_200d_sma_x0_8,
|
||||
price_350d_sma_x2,
|
||||
price_sma_200d_x2_4,
|
||||
price_sma_200d_x0_8,
|
||||
price_sma_350d_x2,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,41 +7,41 @@ use crate::internal::{ComputedFromHeightPriceWithRatioExtended, LazyFromHeight,
|
||||
/// Simple and exponential moving average metrics
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_1w_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_8d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_13d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_21d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_1m_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_34d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_55d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_89d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_111d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_144d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_200d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_350d_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_1y_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_2y_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_200w_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_4y_sma: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_1w: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_8d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_13d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_21d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_1m: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_34d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_55d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_89d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_111d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_144d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_200d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_350d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_1y: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_2y: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_200w: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_sma_4y: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
|
||||
pub price_1w_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_8d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_12d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_13d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_21d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_26d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_1m_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_34d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_55d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_89d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_144d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_200d_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_1y_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_2y_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_200w_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_4y_ema: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_1w: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_8d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_12d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_13d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_21d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_26d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_1m: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_34d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_55d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_89d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_144d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_200d: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_1y: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_2y: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_200w: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
pub price_ema_4y: ComputedFromHeightPriceWithRatioExtended<M>,
|
||||
|
||||
pub price_200d_sma_x2_4: Price<LazyFromHeight<Cents, Cents>>,
|
||||
pub price_200d_sma_x0_8: Price<LazyFromHeight<Cents, Cents>>,
|
||||
pub price_350d_sma_x2: Price<LazyFromHeight<Cents, Cents>>,
|
||||
pub price_sma_200d_x2_4: Price<LazyFromHeight<Cents, Cents>>,
|
||||
pub price_sma_200d_x0_8: Price<LazyFromHeight<Cents, Cents>>,
|
||||
pub price_sma_350d_x2: Price<LazyFromHeight<Cents, Cents>>,
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ impl Vecs {
|
||||
let price = &prices.price.cents.height;
|
||||
|
||||
for (min_vec, max_vec, starts) in [
|
||||
(&mut self.price_1w_min.cents.height, &mut self.price_1w_max.cents.height, &blocks.count.height_1w_ago),
|
||||
(&mut self.price_2w_min.cents.height, &mut self.price_2w_max.cents.height, &blocks.count.height_2w_ago),
|
||||
(&mut self.price_1m_min.cents.height, &mut self.price_1m_max.cents.height, &blocks.count.height_1m_ago),
|
||||
(&mut self.price_1y_min.cents.height, &mut self.price_1y_max.cents.height, &blocks.count.height_1y_ago),
|
||||
(&mut self.price_min_1w.cents.height, &mut self.price_max_1w.cents.height, &blocks.count.height_1w_ago),
|
||||
(&mut self.price_min_2w.cents.height, &mut self.price_max_2w.cents.height, &blocks.count.height_2w_ago),
|
||||
(&mut self.price_min_1m.cents.height, &mut self.price_max_1m.cents.height, &blocks.count.height_1m_ago),
|
||||
(&mut self.price_min_1y.cents.height, &mut self.price_max_1y.cents.height, &blocks.count.height_1y_ago),
|
||||
] {
|
||||
min_vec.compute_rolling_min_from_starts(starting_indexes.height, starts, price, exit)?;
|
||||
max_vec.compute_rolling_max_from_starts(starting_indexes.height, starts, price, exit)?;
|
||||
@@ -47,18 +47,18 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
// 2w rolling sum of true range
|
||||
self.price_true_range_2w_sum.height.compute_rolling_sum(
|
||||
self.price_true_range_sum_2w.height.compute_rolling_sum(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.price_true_range.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.price_2w_choppiness_index.height.compute_transform4(
|
||||
self.price_choppiness_index_2w.height.compute_transform4(
|
||||
starting_indexes.height,
|
||||
&self.price_true_range_2w_sum.height,
|
||||
&self.price_2w_max.cents.height,
|
||||
&self.price_2w_min.cents.height,
|
||||
&self.price_true_range_sum_2w.height,
|
||||
&self.price_max_2w.cents.height,
|
||||
&self.price_min_2w.cents.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
|(h, tr_sum, max, min, window_start, ..)| {
|
||||
let range = f64::from(max) - f64::from(min);
|
||||
|
||||
@@ -10,22 +10,22 @@ impl Vecs {
|
||||
let v1 = Version::ONE;
|
||||
|
||||
Ok(Self {
|
||||
price_1w_min: Price::forced_import(db, "price_1w_min", version + v1, indexes)?,
|
||||
price_1w_max: Price::forced_import(db, "price_1w_max", version + v1, indexes)?,
|
||||
price_2w_min: Price::forced_import(db, "price_2w_min", version + v1, indexes)?,
|
||||
price_2w_max: Price::forced_import(db, "price_2w_max", version + v1, indexes)?,
|
||||
price_1m_min: Price::forced_import(db, "price_1m_min", version + v1, indexes)?,
|
||||
price_1m_max: Price::forced_import(db, "price_1m_max", version + v1, indexes)?,
|
||||
price_1y_min: Price::forced_import(db, "price_1y_min", version + v1, indexes)?,
|
||||
price_1y_max: Price::forced_import(db, "price_1y_max", version + v1, indexes)?,
|
||||
price_min_1w: Price::forced_import(db, "price_min_1w", version + v1, indexes)?,
|
||||
price_max_1w: Price::forced_import(db, "price_max_1w", version + v1, indexes)?,
|
||||
price_min_2w: Price::forced_import(db, "price_min_2w", version + v1, indexes)?,
|
||||
price_max_2w: Price::forced_import(db, "price_max_2w", version + v1, indexes)?,
|
||||
price_min_1m: Price::forced_import(db, "price_min_1m", version + v1, indexes)?,
|
||||
price_max_1m: Price::forced_import(db, "price_max_1m", version + v1, indexes)?,
|
||||
price_min_1y: Price::forced_import(db, "price_min_1y", version + v1, indexes)?,
|
||||
price_max_1y: Price::forced_import(db, "price_max_1y", version + v1, indexes)?,
|
||||
price_true_range: ComputedFromHeight::forced_import(
|
||||
db, "price_true_range", version + v1, indexes,
|
||||
)?,
|
||||
price_true_range_2w_sum: ComputedFromHeight::forced_import(
|
||||
db, "price_true_range_2w_sum", version + v1, indexes,
|
||||
price_true_range_sum_2w: ComputedFromHeight::forced_import(
|
||||
db, "price_true_range_sum_2w", version + v1, indexes,
|
||||
)?,
|
||||
price_2w_choppiness_index: ComputedFromHeight::forced_import(
|
||||
db, "price_2w_choppiness_index", version + v1, indexes,
|
||||
price_choppiness_index_2w: ComputedFromHeight::forced_import(
|
||||
db, "price_choppiness_index_2w", version + v1, indexes,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ use crate::internal::{ComputedFromHeight, Price};
|
||||
/// Price range and choppiness metrics
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_1w_min: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_1w_max: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_2w_min: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_2w_max: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_1m_min: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_1m_max: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_1y_min: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_1y_max: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_min_1w: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_max_1w: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_min_2w: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_max_2w: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_min_1m: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_max_1m: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_min_1y: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_max_1y: Price<ComputedFromHeight<Cents, M>>,
|
||||
pub price_true_range: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_true_range_2w_sum: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_2w_choppiness_index: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_true_range_sum_2w: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_choppiness_index_2w: ComputedFromHeight<StoredF32, M>,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use brk_types::{BasisPointsSigned32, Dollars, StoredF32};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{ComputeIndexes, blocks, internal::PercentageDiffDollars, market::lookback, prices};
|
||||
use crate::{ComputeIndexes, blocks, internal::RatioDiffDollarsBps32, market::lookback, prices};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
@@ -16,11 +16,11 @@ impl Vecs {
|
||||
) -> Result<()> {
|
||||
// Compute price returns at height level
|
||||
for ((returns, _), (lookback_price, _)) in self
|
||||
.price_returns
|
||||
.price_return
|
||||
.iter_mut_with_days()
|
||||
.zip(lookback.price_ago.iter_with_days())
|
||||
.zip(lookback.price_lookback.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Dollars, Dollars, PercentageDiffDollars>(
|
||||
returns.compute_binary::<Dollars, Dollars, RatioDiffDollarsBps32>(
|
||||
starting_indexes.height,
|
||||
&prices.price.usd.height,
|
||||
&lookback_price.usd.height,
|
||||
@@ -29,44 +29,48 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// CAGR computed from returns at height level (2y+ periods only)
|
||||
let price_returns_dca = self.price_returns.as_dca_period();
|
||||
for (cagr, returns, days) in self.cagr.zip_mut_with_period(&price_returns_dca) {
|
||||
let years = days as f32 / 365.0;
|
||||
cagr.height.compute_transform(
|
||||
let price_return_dca = self.price_return.as_dca_period();
|
||||
for (cagr, returns, days) in self.price_cagr.zip_mut_with_period(&price_return_dca) {
|
||||
let years = days as f64 / 365.0;
|
||||
cagr.bps.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&returns.height,
|
||||
&returns.bps.height,
|
||||
|(h, r, ..)| {
|
||||
let v = ((*r / 100.0 + 1.0).powf(1.0 / years) - 1.0) * 100.0;
|
||||
(h, StoredF32::from(v))
|
||||
let ratio = f64::from(r);
|
||||
let v = (ratio + 1.0).powf(1.0 / years) - 1.0;
|
||||
(h, BasisPointsSigned32::from(v))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
let _24h_price_returns_height = &self.price_returns._24h.height;
|
||||
let _24h_price_return_height = &self.price_return._24h.bps.height;
|
||||
|
||||
self._1d_returns_1w_sd
|
||||
.compute_all(blocks, starting_indexes, exit, _24h_price_returns_height)?;
|
||||
self._1d_returns_1m_sd
|
||||
.compute_all(blocks, starting_indexes, exit, _24h_price_returns_height)?;
|
||||
self._1d_returns_1y_sd
|
||||
.compute_all(blocks, starting_indexes, exit, _24h_price_returns_height)?;
|
||||
self.price_return_24h_sd_1w
|
||||
.compute_all(blocks, starting_indexes, exit, _24h_price_return_height)?;
|
||||
self.price_return_24h_sd_1m
|
||||
.compute_all(blocks, starting_indexes, exit, _24h_price_return_height)?;
|
||||
self.price_return_24h_sd_1y
|
||||
.compute_all(blocks, starting_indexes, exit, _24h_price_return_height)?;
|
||||
|
||||
// Downside returns: min(return, 0)
|
||||
self.downside_returns.compute_transform(
|
||||
self.price_downside_24h.compute_transform(
|
||||
starting_indexes.height,
|
||||
_24h_price_returns_height,
|
||||
|(i, ret, ..)| (i, StoredF32::from((*ret).min(0.0))),
|
||||
_24h_price_return_height,
|
||||
|(i, ret, ..)| {
|
||||
let v = f64::from(ret).min(0.0);
|
||||
(i, StoredF32::from(v as f32))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Downside deviation (SD of downside returns)
|
||||
self.downside_1w_sd
|
||||
.compute_all(blocks, starting_indexes, exit, &self.downside_returns)?;
|
||||
self.downside_1m_sd
|
||||
.compute_all(blocks, starting_indexes, exit, &self.downside_returns)?;
|
||||
self.downside_1y_sd
|
||||
.compute_all(blocks, starting_indexes, exit, &self.downside_returns)?;
|
||||
self.price_downside_24h_sd_1w
|
||||
.compute_all(blocks, starting_indexes, exit, &self.price_downside_24h)?;
|
||||
self.price_downside_24h_sd_1m
|
||||
.compute_all(blocks, starting_indexes, exit, &self.price_downside_24h)?;
|
||||
self.price_downside_24h_sd_1y
|
||||
.compute_all(blocks, starting_indexes, exit, &self.price_downside_24h)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ use super::super::lookback::ByLookbackPeriod;
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::ComputedFromHeight,
|
||||
internal::ComputedFromHeightStdDev,
|
||||
internal::{Bps32ToFloat, Bps32ToPercent, ComputedFromHeightStdDev, PercentFromHeight},
|
||||
market::dca::ByDcaCagr,
|
||||
};
|
||||
|
||||
@@ -19,75 +18,86 @@ impl Vecs {
|
||||
) -> Result<Self> {
|
||||
let v1 = Version::ONE;
|
||||
|
||||
let price_returns = ByLookbackPeriod::try_new(|name, _days| {
|
||||
ComputedFromHeight::forced_import(
|
||||
let price_return = ByLookbackPeriod::try_new(|name, _days| {
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
&format!("{name}_price_returns"),
|
||||
&format!("price_return_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
// CAGR (computed, 2y+ only)
|
||||
let cagr = ByDcaCagr::try_new(|name, _days| {
|
||||
ComputedFromHeight::forced_import(db, &format!("{name}_cagr"), version, indexes)
|
||||
let price_cagr = ByDcaCagr::try_new(|name, _days| {
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
db,
|
||||
&format!("price_cagr_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let _1d_returns_1w_sd = ComputedFromHeightStdDev::forced_import(
|
||||
let price_return_24h_sd_1w = ComputedFromHeightStdDev::forced_import(
|
||||
db,
|
||||
"1d_returns_1w_sd",
|
||||
"price_return_24h",
|
||||
"1w",
|
||||
7,
|
||||
version + v1,
|
||||
indexes,
|
||||
)?;
|
||||
let _1d_returns_1m_sd = ComputedFromHeightStdDev::forced_import(
|
||||
let price_return_24h_sd_1m = ComputedFromHeightStdDev::forced_import(
|
||||
db,
|
||||
"1d_returns_1m_sd",
|
||||
"price_return_24h",
|
||||
"1m",
|
||||
30,
|
||||
version + v1,
|
||||
indexes,
|
||||
)?;
|
||||
let _1d_returns_1y_sd = ComputedFromHeightStdDev::forced_import(
|
||||
let price_return_24h_sd_1y = ComputedFromHeightStdDev::forced_import(
|
||||
db,
|
||||
"1d_returns_1y_sd",
|
||||
"price_return_24h",
|
||||
"1y",
|
||||
365,
|
||||
version + v1,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
let downside_returns = EagerVec::forced_import(db, "downside_returns", version)?;
|
||||
let downside_1w_sd = ComputedFromHeightStdDev::forced_import(
|
||||
let price_downside_24h = EagerVec::forced_import(db, "price_downside_24h", version)?;
|
||||
let price_downside_24h_sd_1w = ComputedFromHeightStdDev::forced_import(
|
||||
db,
|
||||
"downside_1w_sd",
|
||||
"price_downside_24h",
|
||||
"1w",
|
||||
7,
|
||||
version + v1,
|
||||
indexes,
|
||||
)?;
|
||||
let downside_1m_sd = ComputedFromHeightStdDev::forced_import(
|
||||
let price_downside_24h_sd_1m = ComputedFromHeightStdDev::forced_import(
|
||||
db,
|
||||
"downside_1m_sd",
|
||||
"price_downside_24h",
|
||||
"1m",
|
||||
30,
|
||||
version + v1,
|
||||
indexes,
|
||||
)?;
|
||||
let downside_1y_sd = ComputedFromHeightStdDev::forced_import(
|
||||
let price_downside_24h_sd_1y = ComputedFromHeightStdDev::forced_import(
|
||||
db,
|
||||
"downside_1y_sd",
|
||||
"price_downside_24h",
|
||||
"1y",
|
||||
365,
|
||||
version + v1,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
price_returns,
|
||||
cagr,
|
||||
_1d_returns_1w_sd,
|
||||
_1d_returns_1m_sd,
|
||||
_1d_returns_1y_sd,
|
||||
downside_returns,
|
||||
downside_1w_sd,
|
||||
downside_1m_sd,
|
||||
downside_1y_sd,
|
||||
price_return,
|
||||
price_cagr,
|
||||
price_return_24h_sd_1w,
|
||||
price_return_24h_sd_1m,
|
||||
price_return_24h_sd_1y,
|
||||
price_downside_24h,
|
||||
price_downside_24h_sd_1w,
|
||||
price_downside_24h_sd_1m,
|
||||
price_downside_24h_sd_1y,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, StoredF32};
|
||||
use brk_types::{BasisPointsSigned32, Height, StoredF32};
|
||||
use vecdb::{EagerVec, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
internal::{ComputedFromHeight, ComputedFromHeightStdDev},
|
||||
internal::{ComputedFromHeight, ComputedFromHeightStdDev, PercentFromHeight},
|
||||
market::{dca::ByDcaCagr, lookback::ByLookbackPeriod},
|
||||
};
|
||||
|
||||
/// Price returns, CAGR, and returns standard deviation metrics
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_returns: ByLookbackPeriod<ComputedFromHeight<StoredF32, M>>,
|
||||
pub price_return: ByLookbackPeriod<PercentFromHeight<BasisPointsSigned32, M>>,
|
||||
|
||||
// CAGR (computed from returns, 2y+ only)
|
||||
pub cagr: ByDcaCagr<ComputedFromHeight<StoredF32, M>>,
|
||||
pub price_cagr: ByDcaCagr<PercentFromHeight<BasisPointsSigned32, M>>,
|
||||
|
||||
// Returns standard deviation (computed from 1d returns)
|
||||
pub _1d_returns_1w_sd: ComputedFromHeightStdDev<M>,
|
||||
pub _1d_returns_1m_sd: ComputedFromHeightStdDev<M>,
|
||||
pub _1d_returns_1y_sd: ComputedFromHeightStdDev<M>,
|
||||
// Returns standard deviation (computed from 24h returns)
|
||||
pub price_return_24h_sd_1w: ComputedFromHeightStdDev<M>,
|
||||
pub price_return_24h_sd_1m: ComputedFromHeightStdDev<M>,
|
||||
pub price_return_24h_sd_1y: ComputedFromHeightStdDev<M>,
|
||||
|
||||
// Downside returns and deviation (for Sortino ratio)
|
||||
pub downside_returns: M::Stored<EagerVec<PcoVec<Height, StoredF32>>>,
|
||||
pub downside_1w_sd: ComputedFromHeightStdDev<M>,
|
||||
pub downside_1m_sd: ComputedFromHeightStdDev<M>,
|
||||
pub downside_1y_sd: ComputedFromHeightStdDev<M>,
|
||||
pub price_downside_24h: M::Stored<EagerVec<PcoVec<Height, StoredF32>>>,
|
||||
pub price_downside_24h_sd_1w: ComputedFromHeightStdDev<M>,
|
||||
pub price_downside_24h_sd_1m: ComputedFromHeightStdDev<M>,
|
||||
pub price_downside_24h_sd_1y: ComputedFromHeightStdDev<M>,
|
||||
}
|
||||
|
||||
@@ -14,17 +14,17 @@ impl Vecs {
|
||||
) -> Result<()> {
|
||||
// Sharpe ratios: returns / volatility
|
||||
for (out, ret, vol) in [
|
||||
(&mut self.sharpe_1w, &returns.price_returns._1w.height, &self.price_1w_volatility.height),
|
||||
(&mut self.sharpe_1m, &returns.price_returns._1m.height, &self.price_1m_volatility.height),
|
||||
(&mut self.sharpe_1y, &returns.price_returns._1y.height, &self.price_1y_volatility.height),
|
||||
(&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),
|
||||
] {
|
||||
compute_ratio(&mut out.height, starting_indexes_height, ret, vol, exit)?;
|
||||
}
|
||||
|
||||
// Sortino ratios: returns / downside volatility
|
||||
compute_ratio(&mut self.sortino_1w.height, starting_indexes_height, &returns.price_returns._1w.height, &returns.downside_1w_sd.sd.height, exit)?;
|
||||
compute_ratio(&mut self.sortino_1m.height, starting_indexes_height, &returns.price_returns._1m.height, &returns.downside_1m_sd.sd.height, exit)?;
|
||||
compute_ratio(&mut self.sortino_1y.height, starting_indexes_height, &returns.price_returns._1y.height, &returns.downside_1y_sd.sd.height, exit)?;
|
||||
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)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -18,51 +18,51 @@ impl Vecs {
|
||||
) -> Result<Self> {
|
||||
let v2 = Version::TWO;
|
||||
|
||||
let price_1w_volatility = LazyFromHeight::from_computed::<TimesSqrt<Days7>>(
|
||||
"price_1w_volatility",
|
||||
let price_volatility_1w = LazyFromHeight::from_computed::<TimesSqrt<Days7>>(
|
||||
"price_volatility_1w",
|
||||
version + v2,
|
||||
returns._1d_returns_1w_sd.sd.height.read_only_boxed_clone(),
|
||||
&returns._1d_returns_1w_sd.sd,
|
||||
returns.price_return_24h_sd_1w.sd.height.read_only_boxed_clone(),
|
||||
&returns.price_return_24h_sd_1w.sd,
|
||||
);
|
||||
|
||||
let price_1m_volatility = LazyFromHeight::from_computed::<TimesSqrt<Days30>>(
|
||||
"price_1m_volatility",
|
||||
let price_volatility_1m = LazyFromHeight::from_computed::<TimesSqrt<Days30>>(
|
||||
"price_volatility_1m",
|
||||
version + v2,
|
||||
returns._1d_returns_1m_sd.sd.height.read_only_boxed_clone(),
|
||||
&returns._1d_returns_1m_sd.sd,
|
||||
returns.price_return_24h_sd_1m.sd.height.read_only_boxed_clone(),
|
||||
&returns.price_return_24h_sd_1m.sd,
|
||||
);
|
||||
|
||||
let price_1y_volatility = LazyFromHeight::from_computed::<TimesSqrt<Days365>>(
|
||||
"price_1y_volatility",
|
||||
let price_volatility_1y = LazyFromHeight::from_computed::<TimesSqrt<Days365>>(
|
||||
"price_volatility_1y",
|
||||
version + v2,
|
||||
returns._1d_returns_1y_sd.sd.height.read_only_boxed_clone(),
|
||||
&returns._1d_returns_1y_sd.sd,
|
||||
returns.price_return_24h_sd_1y.sd.height.read_only_boxed_clone(),
|
||||
&returns.price_return_24h_sd_1y.sd,
|
||||
);
|
||||
|
||||
let sharpe_1w =
|
||||
ComputedFromHeight::forced_import(db, "sharpe_1w", version + v2, indexes)?;
|
||||
let sharpe_1m =
|
||||
ComputedFromHeight::forced_import(db, "sharpe_1m", version + v2, indexes)?;
|
||||
let sharpe_1y =
|
||||
ComputedFromHeight::forced_import(db, "sharpe_1y", version + v2, indexes)?;
|
||||
let price_sharpe_1w =
|
||||
ComputedFromHeight::forced_import(db, "price_sharpe_1w", version + v2, indexes)?;
|
||||
let price_sharpe_1m =
|
||||
ComputedFromHeight::forced_import(db, "price_sharpe_1m", version + v2, indexes)?;
|
||||
let price_sharpe_1y =
|
||||
ComputedFromHeight::forced_import(db, "price_sharpe_1y", version + v2, indexes)?;
|
||||
|
||||
let sortino_1w =
|
||||
ComputedFromHeight::forced_import(db, "sortino_1w", version + v2, indexes)?;
|
||||
let sortino_1m =
|
||||
ComputedFromHeight::forced_import(db, "sortino_1m", version + v2, indexes)?;
|
||||
let sortino_1y =
|
||||
ComputedFromHeight::forced_import(db, "sortino_1y", version + v2, indexes)?;
|
||||
let price_sortino_1w =
|
||||
ComputedFromHeight::forced_import(db, "price_sortino_1w", version + v2, indexes)?;
|
||||
let price_sortino_1m =
|
||||
ComputedFromHeight::forced_import(db, "price_sortino_1m", version + v2, indexes)?;
|
||||
let price_sortino_1y =
|
||||
ComputedFromHeight::forced_import(db, "price_sortino_1y", version + v2, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
price_1w_volatility,
|
||||
price_1m_volatility,
|
||||
price_1y_volatility,
|
||||
sharpe_1w,
|
||||
sharpe_1m,
|
||||
sharpe_1y,
|
||||
sortino_1w,
|
||||
sortino_1m,
|
||||
sortino_1y,
|
||||
price_volatility_1w,
|
||||
price_volatility_1m,
|
||||
price_volatility_1y,
|
||||
price_sharpe_1w,
|
||||
price_sharpe_1m,
|
||||
price_sharpe_1y,
|
||||
price_sortino_1w,
|
||||
price_sortino_1m,
|
||||
price_sortino_1y,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ use brk_types::StoredF32;
|
||||
/// Price volatility metrics (derived from returns standard deviation)
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub price_1w_volatility: LazyFromHeight<StoredF32>,
|
||||
pub price_1m_volatility: LazyFromHeight<StoredF32>,
|
||||
pub price_1y_volatility: LazyFromHeight<StoredF32>,
|
||||
pub price_volatility_1w: LazyFromHeight<StoredF32>,
|
||||
pub price_volatility_1m: LazyFromHeight<StoredF32>,
|
||||
pub price_volatility_1y: LazyFromHeight<StoredF32>,
|
||||
|
||||
pub sharpe_1w: ComputedFromHeight<StoredF32, M>,
|
||||
pub sharpe_1m: ComputedFromHeight<StoredF32, M>,
|
||||
pub sharpe_1y: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_sharpe_1w: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_sharpe_1m: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_sharpe_1y: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
pub sortino_1w: ComputedFromHeight<StoredF32, M>,
|
||||
pub sortino_1m: ComputedFromHeight<StoredF32, M>,
|
||||
pub sortino_1y: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_sortino_1w: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_sortino_1m: ComputedFromHeight<StoredF32, M>,
|
||||
pub price_sortino_1y: ComputedFromHeight<StoredF32, M>,
|
||||
}
|
||||
|
||||
@@ -35,28 +35,28 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.hash_rate_1w_sma.height.compute_rolling_average(
|
||||
self.hash_rate_sma_1w.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&count_vecs.height_1w_ago,
|
||||
&self.hash_rate.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.hash_rate_1m_sma.height.compute_rolling_average(
|
||||
self.hash_rate_sma_1m.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&count_vecs.height_1m_ago,
|
||||
&self.hash_rate.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.hash_rate_2m_sma.height.compute_rolling_average(
|
||||
self.hash_rate_sma_2m.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&count_vecs.height_2m_ago,
|
||||
&self.hash_rate.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.hash_rate_1y_sma.height.compute_rolling_average(
|
||||
self.hash_rate_sma_1y.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&count_vecs.height_1y_ago,
|
||||
&self.hash_rate.height,
|
||||
@@ -69,7 +69,7 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.hash_rate_drawdown.height.compute_drawdown(
|
||||
self.hash_rate_drawdown.compute_drawdown(
|
||||
starting_indexes.height,
|
||||
&self.hash_rate.height,
|
||||
&self.hash_rate_ath.height,
|
||||
|
||||
@@ -5,7 +5,7 @@ use vecdb::Database;
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::ComputedFromHeight,
|
||||
internal::{Bps16ToFloat, Bps16ToPercent, ComputedFromHeight, PercentFromHeight},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -19,27 +19,27 @@ impl Vecs {
|
||||
|
||||
Ok(Self {
|
||||
hash_rate: ComputedFromHeight::forced_import(db, "hash_rate", version + v5, indexes)?,
|
||||
hash_rate_1w_sma: ComputedFromHeight::forced_import(
|
||||
hash_rate_sma_1w: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
"hash_rate_1w_sma",
|
||||
"hash_rate_sma_1w",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
hash_rate_1m_sma: ComputedFromHeight::forced_import(
|
||||
hash_rate_sma_1m: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
"hash_rate_1m_sma",
|
||||
"hash_rate_sma_1m",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
hash_rate_2m_sma: ComputedFromHeight::forced_import(
|
||||
hash_rate_sma_2m: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
"hash_rate_2m_sma",
|
||||
"hash_rate_sma_2m",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
hash_rate_1y_sma: ComputedFromHeight::forced_import(
|
||||
hash_rate_sma_1y: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
"hash_rate_1y_sma",
|
||||
"hash_rate_sma_1y",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
@@ -49,7 +49,7 @@ impl Vecs {
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
hash_rate_drawdown: ComputedFromHeight::forced_import(
|
||||
hash_rate_drawdown: PercentFromHeight::forced_import::<Bps16ToFloat, Bps16ToPercent>(
|
||||
db,
|
||||
"hash_rate_drawdown",
|
||||
version,
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, StoredF64};
|
||||
use brk_types::{BasisPointsSigned16, StoredF32, StoredF64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::ComputedFromHeight;
|
||||
use crate::internal::{ComputedFromHeight, PercentFromHeight};
|
||||
|
||||
/// Mining-related metrics: hash rate, hash price, hash value
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub hash_rate: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_1w_sma: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_1m_sma: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_2m_sma: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_1y_sma: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_sma_1w: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_sma_1m: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_sma_2m: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_sma_1y: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_ath: ComputedFromHeight<StoredF64, M>,
|
||||
pub hash_rate_drawdown: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_rate_drawdown: PercentFromHeight<BasisPointsSigned16, M>,
|
||||
pub hash_price_ths: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_price_ths_min: ComputedFromHeight<StoredF32, M>,
|
||||
pub hash_price_phs: ComputedFromHeight<StoredF32, M>,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{CheckedSub, HalvingEpoch, Sats, StoredF32};
|
||||
use brk_types::{BasisPoints16, CheckedSub, HalvingEpoch, Sats};
|
||||
use vecdb::{Exit, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{ComputeIndexes, blocks, indexes, prices, transactions};
|
||||
use crate::{ComputeIndexes, blocks, indexes, internal::RatioSatsBp16, prices, transactions};
|
||||
|
||||
impl Vecs {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -122,14 +122,14 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
// All-time cumulative fee dominance
|
||||
self.fee_dominance.height.compute_percentage(
|
||||
self.fee_dominance.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
starting_indexes.height,
|
||||
&self.fees.cumulative.sats.height,
|
||||
&self.coinbase.cumulative.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Rolling fee dominance = sum(fees) / sum(coinbase) * 100
|
||||
// Rolling fee dominance = sum(fees) / sum(coinbase)
|
||||
for ((fee_dom, fees_w), coinbase_w) in self
|
||||
.fee_dominance_rolling
|
||||
.as_mut_array()
|
||||
@@ -137,7 +137,7 @@ impl Vecs {
|
||||
.zip(self.fees.rolling.as_array())
|
||||
.zip(self.coinbase.rolling.as_array())
|
||||
{
|
||||
fee_dom.height.compute_percentage(
|
||||
fee_dom.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
starting_indexes.height,
|
||||
&fees_w.sum.sats.height,
|
||||
&coinbase_w.sum.sats.height,
|
||||
@@ -146,30 +146,29 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// All-time cumulative subsidy dominance
|
||||
self.subsidy_dominance.height.compute_percentage(
|
||||
self.subsidy_dominance.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
starting_indexes.height,
|
||||
&self.subsidy.cumulative.sats.height,
|
||||
&self.coinbase.cumulative.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Rolling subsidy dominance = 100 - fee_dominance
|
||||
let hundred = StoredF32::from(100u8);
|
||||
// Rolling subsidy dominance = 1 - fee_dominance
|
||||
for (sub_dom, fee_dom) in self
|
||||
.subsidy_dominance_rolling
|
||||
.as_mut_array()
|
||||
.into_iter()
|
||||
.zip(self.fee_dominance_rolling.as_array())
|
||||
{
|
||||
sub_dom.height.compute_transform(
|
||||
sub_dom.bps.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&fee_dom.height,
|
||||
|(height, fee_dom, _)| (height, hundred - fee_dom),
|
||||
&fee_dom.bps.height,
|
||||
|(height, fee, _)| (height, BasisPoints16::ONE - fee),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.subsidy_usd_1y_sma.cents.height.compute_rolling_average(
|
||||
self.subsidy_sma_1y.cents.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&count_vecs.height_1y_ago,
|
||||
&self.subsidy.base.cents.height,
|
||||
|
||||
@@ -6,8 +6,8 @@ use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
ComputedFromHeight, FiatFromHeight, RollingWindows, ValueFromHeightFull,
|
||||
ValueFromHeightCumulativeSum,
|
||||
Bp16ToFloat, Bp16ToPercent, FiatFromHeight, PercentFromHeight, PercentRollingWindows,
|
||||
ValueFromHeightFull, ValueFromHeightCumulativeSum,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -27,33 +27,33 @@ impl Vecs {
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
fee_dominance: ComputedFromHeight::forced_import(
|
||||
fee_dominance: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
db,
|
||||
"fee_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
fee_dominance_rolling: RollingWindows::forced_import(
|
||||
fee_dominance_rolling: PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
db,
|
||||
"fee_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
subsidy_dominance: ComputedFromHeight::forced_import(
|
||||
subsidy_dominance: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
db,
|
||||
"subsidy_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
subsidy_dominance_rolling: RollingWindows::forced_import(
|
||||
subsidy_dominance_rolling: PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
db,
|
||||
"subsidy_dominance",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
subsidy_usd_1y_sma: FiatFromHeight::forced_import(
|
||||
subsidy_sma_1y: FiatFromHeight::forced_import(
|
||||
db,
|
||||
"subsidy_usd_1y_sma",
|
||||
"subsidy_sma_1y",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, StoredF32};
|
||||
use brk_types::{BasisPoints16, Cents};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{
|
||||
ComputedFromHeight, FiatFromHeight, RollingWindows, ValueFromHeightFull,
|
||||
ValueFromHeightCumulativeSum,
|
||||
FiatFromHeight, PercentFromHeight, PercentRollingWindows, RollingWindows,
|
||||
ValueFromHeightFull, ValueFromHeightCumulativeSum,
|
||||
};
|
||||
|
||||
/// Coinbase/subsidy/rewards metrics
|
||||
@@ -14,9 +14,9 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub subsidy: ValueFromHeightFull<M>,
|
||||
pub fees: ValueFromHeightFull<M>,
|
||||
pub unclaimed_rewards: ValueFromHeightCumulativeSum<M>,
|
||||
pub fee_dominance: ComputedFromHeight<StoredF32, M>,
|
||||
pub fee_dominance_rolling: RollingWindows<StoredF32, M>,
|
||||
pub subsidy_dominance: ComputedFromHeight<StoredF32, M>,
|
||||
pub subsidy_dominance_rolling: RollingWindows<StoredF32, M>,
|
||||
pub subsidy_usd_1y_sma: FiatFromHeight<Cents, M>,
|
||||
pub fee_dominance: PercentFromHeight<BasisPoints16, M>,
|
||||
pub fee_dominance_rolling: PercentRollingWindows<BasisPoints16, M>,
|
||||
pub subsidy_dominance: PercentFromHeight<BasisPoints16, M>,
|
||||
pub subsidy_dominance_rolling: PercentRollingWindows<BasisPoints16, M>,
|
||||
pub subsidy_sma_1y: FiatFromHeight<Cents, M>,
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, PoolSlug, StoredF32, StoredU16, StoredU32};
|
||||
use brk_types::{BasisPoints16, Height, PoolSlug, StoredU32};
|
||||
use vecdb::{AnyVec, BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, Version};
|
||||
|
||||
use crate::{
|
||||
blocks,
|
||||
indexes::{self, ComputeIndexes},
|
||||
internal::{
|
||||
ComputedFromHeightCumulativeSum, ComputedFromHeight, MaskSats, PercentageU32F32,
|
||||
RollingWindows, ValueFromHeightCumulativeSum,
|
||||
Bp16ToFloat, Bp16ToPercent, ComputedFromHeightCumulativeSum, ComputedFromHeight, MaskSats,
|
||||
PercentFromHeight, PercentRollingWindows, RatioU32Bp16, RollingWindows,
|
||||
ValueFromHeightCumulativeSum,
|
||||
},
|
||||
mining, prices,
|
||||
};
|
||||
@@ -22,10 +23,9 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub subsidy: ValueFromHeightCumulativeSum<M>,
|
||||
pub fee: ValueFromHeightCumulativeSum<M>,
|
||||
pub coinbase: ValueFromHeightCumulativeSum<M>,
|
||||
pub dominance: ComputedFromHeight<StoredF32, M>,
|
||||
pub dominance_rolling: RollingWindows<StoredF32, M>,
|
||||
pub blocks_since_block: ComputedFromHeight<StoredU32, M>,
|
||||
pub days_since_block: ComputedFromHeight<StoredU16, M>,
|
||||
pub dominance: PercentFromHeight<BasisPoints16, M>,
|
||||
pub dominance_rolling: PercentRollingWindows<BasisPoints16, M>,
|
||||
pub blocks_since_last_mined: ComputedFromHeight<StoredU32, M>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -58,9 +58,9 @@ impl Vecs {
|
||||
ValueFromHeightCumulativeSum::forced_import(db, &suffix("coinbase"), version, indexes)?;
|
||||
|
||||
let dominance =
|
||||
ComputedFromHeight::forced_import(db, &suffix("dominance"), version, indexes)?;
|
||||
PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, &suffix("dominance"), version, indexes)?;
|
||||
let dominance_rolling =
|
||||
RollingWindows::forced_import(db, &suffix("dominance"), version, indexes)?;
|
||||
PercentRollingWindows::forced_import::<Bp16ToFloat, Bp16ToPercent>(db, &suffix("dominance"), version, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
dominance,
|
||||
@@ -71,15 +71,9 @@ impl Vecs {
|
||||
coinbase,
|
||||
subsidy,
|
||||
fee,
|
||||
blocks_since_block: ComputedFromHeight::forced_import(
|
||||
blocks_since_last_mined: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("blocks_since_block"),
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
days_since_block: ComputedFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("days_since_block"),
|
||||
&suffix("blocks_since_last_mined"),
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
@@ -126,7 +120,7 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
self.dominance
|
||||
.compute_binary::<StoredU32, StoredU32, PercentageU32F32>(
|
||||
.compute_binary::<StoredU32, StoredU32, RatioU32Bp16>(
|
||||
starting_indexes.height,
|
||||
&self.blocks_mined.cumulative.height,
|
||||
&blocks.count.block_count.cumulative.height,
|
||||
@@ -140,7 +134,7 @@ impl Vecs {
|
||||
.zip(self.blocks_mined_sum.as_array())
|
||||
.zip(blocks.count.block_count_sum.as_array())
|
||||
{
|
||||
dom.compute_binary::<StoredU32, StoredU32, PercentageU32F32>(
|
||||
dom.compute_binary::<StoredU32, StoredU32, RatioU32Bp16>(
|
||||
starting_indexes.height,
|
||||
&mined.height,
|
||||
&total.height,
|
||||
@@ -198,19 +192,19 @@ impl Vecs {
|
||||
|
||||
{
|
||||
let resume_from = self
|
||||
.blocks_since_block
|
||||
.blocks_since_last_mined
|
||||
.height
|
||||
.len()
|
||||
.min(starting_indexes.height.to_usize());
|
||||
let mut prev = if resume_from > 0 {
|
||||
self.blocks_since_block
|
||||
self.blocks_since_last_mined
|
||||
.height
|
||||
.collect_one_at(resume_from - 1)
|
||||
.unwrap()
|
||||
} else {
|
||||
StoredU32::ZERO
|
||||
};
|
||||
self.blocks_since_block.height.compute_transform(
|
||||
self.blocks_since_last_mined.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&self.blocks_mined.height,
|
||||
|(h, mined, ..)| {
|
||||
@@ -226,18 +220,6 @@ impl Vecs {
|
||||
)?;
|
||||
}
|
||||
|
||||
self.days_since_block.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&self.blocks_since_block.height,
|
||||
|(h, blocks, ..)| {
|
||||
(
|
||||
h,
|
||||
StoredU16::from(u16::try_from(*blocks).unwrap_or(u16::MAX)),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, Version};
|
||||
use brk_types::{BasisPoints16, Version};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{ComputeIndexes, indexes, internal::{ComputedFromHeight, RatioU64F32}, outputs};
|
||||
use crate::{
|
||||
ComputeIndexes, indexes,
|
||||
internal::{Bp16ToFloat, Bp16ToPercent, PercentFromHeight, RatioU64Bp16},
|
||||
outputs,
|
||||
};
|
||||
|
||||
use super::count::Vecs as CountVecs;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub taproot: ComputedFromHeight<StoredF32, M>,
|
||||
pub segwit: ComputedFromHeight<StoredF32, M>,
|
||||
pub taproot: PercentFromHeight<BasisPoints16, M>,
|
||||
pub segwit: PercentFromHeight<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -20,13 +24,18 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
taproot: ComputedFromHeight::forced_import(
|
||||
taproot: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
db,
|
||||
"taproot_adoption",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
segwit: ComputedFromHeight::forced_import(db, "segwit_adoption", version, indexes)?,
|
||||
segwit: PercentFromHeight::forced_import::<Bp16ToFloat, Bp16ToPercent>(
|
||||
db,
|
||||
"segwit_adoption",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -37,14 +46,14 @@ impl Vecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.taproot.compute_binary::<_, _, RatioU64F32>(
|
||||
self.taproot.compute_binary::<_, _, RatioU64Bp16>(
|
||||
starting_indexes.height,
|
||||
&count.p2tr.height,
|
||||
&outputs_count.total_count.full.sum_cumulative.sum.0,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.segwit.compute_binary::<_, _, RatioU64F32>(
|
||||
self.segwit.compute_binary::<_, _, RatioU64Bp16>(
|
||||
starting_indexes.height,
|
||||
&count.segwit.height,
|
||||
&outputs_count.total_count.full.sum_cumulative.sum.0,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::StoredF32;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
@@ -22,9 +21,9 @@ impl Vecs {
|
||||
self.burned
|
||||
.compute(scripts, mining, &blocks.count, prices, starting_indexes, exit)?;
|
||||
|
||||
// 2. Compute inflation rate at height level: (supply[h] - supply[1y_ago]) / supply[1y_ago] * 100
|
||||
// 2. Compute inflation rate: (supply[h] / supply[1y_ago]) - 1
|
||||
let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.total.sats;
|
||||
self.inflation.height.compute_rolling_percentage_change(
|
||||
self.inflation_rate.bps.height.compute_rolling_ratio_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1y_ago,
|
||||
&circulating_supply.height,
|
||||
@@ -35,10 +34,11 @@ impl Vecs {
|
||||
self.velocity
|
||||
.compute(blocks, transactions, distribution, starting_indexes, exit)?;
|
||||
|
||||
// 4. Compute cap growth rates at height level using 1y lookback
|
||||
// 4. Compute cap growth rates using 1y lookback
|
||||
self.market_cap_growth_rate
|
||||
.bps
|
||||
.height
|
||||
.compute_rolling_percentage_change(
|
||||
.compute_rolling_ratio_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1y_ago,
|
||||
&self.market_cap.height,
|
||||
@@ -46,20 +46,20 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
self.realized_cap_growth_rate
|
||||
.bps
|
||||
.height
|
||||
.compute_rolling_percentage_change(
|
||||
.compute_rolling_ratio_change(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_1y_ago,
|
||||
&distribution.utxo_cohorts.all.metrics.realized.realized_cap.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// 5. Compute cap growth rate diff: market_cap_growth_rate - realized_cap_growth_rate
|
||||
self.cap_growth_rate_diff.height.compute_transform2(
|
||||
// 5. Compute cap growth rate diff: market - realized
|
||||
self.market_minus_realized_cap_growth_rate.height.compute_subtract(
|
||||
starting_indexes.height,
|
||||
&self.market_cap_growth_rate.height,
|
||||
&self.realized_cap_growth_rate.height,
|
||||
|(h, a, b, ..)| (h, StoredF32::from(*a - *b)),
|
||||
&self.market_cap_growth_rate.bps.height,
|
||||
&self.realized_cap_growth_rate.bps.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ use super::Vecs;
|
||||
use crate::{
|
||||
distribution, indexes,
|
||||
internal::{
|
||||
ComputedFromHeight, Identity, LazyFromHeight, LazyValueFromHeight, SatsToBitcoin,
|
||||
Bps32ToFloat, Bps32ToPercent, ComputedFromHeight, Identity, LazyFromHeight,
|
||||
LazyValueFromHeight, PercentFromHeight, SatsToBitcoin,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -40,8 +41,8 @@ impl Vecs {
|
||||
let burned = super::burned::Vecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
// Inflation rate
|
||||
let inflation =
|
||||
ComputedFromHeight::forced_import(&db, "inflation_rate", version, indexes)?;
|
||||
let inflation_rate =
|
||||
PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(&db, "inflation_rate", version, indexes)?;
|
||||
|
||||
// Velocity
|
||||
let velocity = super::velocity::Vecs::forced_import(&db, version, indexes)?;
|
||||
@@ -54,31 +55,31 @@ impl Vecs {
|
||||
);
|
||||
|
||||
// Growth rates
|
||||
let market_cap_growth_rate = ComputedFromHeight::forced_import(
|
||||
let market_cap_growth_rate = PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
&db,
|
||||
"market_cap_growth_rate",
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)?;
|
||||
let realized_cap_growth_rate = ComputedFromHeight::forced_import(
|
||||
let realized_cap_growth_rate = PercentFromHeight::forced_import::<Bps32ToFloat, Bps32ToPercent>(
|
||||
&db,
|
||||
"realized_cap_growth_rate",
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)?;
|
||||
let cap_growth_rate_diff =
|
||||
ComputedFromHeight::forced_import(&db, "cap_growth_rate_diff", version, indexes)?;
|
||||
let market_minus_realized_cap_growth_rate =
|
||||
ComputedFromHeight::forced_import(&db, "market_minus_realized_cap_growth_rate", version, indexes)?;
|
||||
|
||||
let this = Self {
|
||||
db,
|
||||
circulating,
|
||||
burned,
|
||||
inflation,
|
||||
inflation_rate,
|
||||
velocity,
|
||||
market_cap,
|
||||
market_cap_growth_rate,
|
||||
realized_cap_growth_rate,
|
||||
cap_growth_rate_diff,
|
||||
market_minus_realized_cap_growth_rate,
|
||||
};
|
||||
|
||||
this.db.retain_regions(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, StoredF32};
|
||||
use brk_types::{BasisPointsSigned32, Dollars};
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use super::{burned, velocity};
|
||||
use crate::internal::{
|
||||
ComputedFromHeight, LazyFromHeight, LazyValueFromHeight,
|
||||
ComputedFromHeight, LazyFromHeight, LazyValueFromHeight, PercentFromHeight,
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -14,10 +14,10 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
pub circulating: LazyValueFromHeight,
|
||||
pub burned: burned::Vecs<M>,
|
||||
pub inflation: ComputedFromHeight<StoredF32, M>,
|
||||
pub inflation_rate: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
pub velocity: velocity::Vecs<M>,
|
||||
pub market_cap: LazyFromHeight<Dollars>,
|
||||
pub market_cap_growth_rate: ComputedFromHeight<StoredF32, M>,
|
||||
pub realized_cap_growth_rate: ComputedFromHeight<StoredF32, M>,
|
||||
pub cap_growth_rate_diff: ComputedFromHeight<StoredF32, M>,
|
||||
pub market_cap_growth_rate: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
pub realized_cap_growth_rate: PercentFromHeight<BasisPointsSigned32, M>,
|
||||
pub market_minus_realized_cap_growth_rate: ComputedFromHeight<BasisPointsSigned32, M>,
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
btc: ComputedFromHeight::forced_import(db, "btc_velocity", version, indexes)?,
|
||||
usd: ComputedFromHeight::forced_import(db, "usd_velocity", version, indexes)?,
|
||||
btc: ComputedFromHeight::forced_import(db, "velocity_btc", version, indexes)?,
|
||||
usd: ComputedFromHeight::forced_import(db, "velocity_usd", version, indexes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::StoredF32;
|
||||
use brk_types::{BasisPointsSigned16, StoredF32};
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, EagerVec, Exit, PcoVec, PcoVecValue, ReadableVec, VecIndex, VecValue,
|
||||
WritableVec,
|
||||
@@ -243,3 +243,38 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ComputeDrawdown<I> for EagerVec<PcoVec<I, BasisPointsSigned16>>
|
||||
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 {
|
||||
BasisPointsSigned16::default()
|
||||
} else {
|
||||
BasisPointsSigned16::from((f64::from(current) - ath_f64) / ath_f64)
|
||||
};
|
||||
(i, drawdown)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user