mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snap
This commit is contained in:
@@ -3,7 +3,7 @@ use std::path::Path;
|
||||
use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
|
||||
use super::{Vecs, realized_envelope::RealizedEnvelope};
|
||||
use super::{Vecs, rarity_meter::RarityMeter};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
@@ -40,7 +40,7 @@ impl Vecs {
|
||||
let stock_to_flow = PerBlock::forced_import(&db, "stock_to_flow", v, indexes)?;
|
||||
let seller_exhaustion = PerBlock::forced_import(&db, "seller_exhaustion", v, indexes)?;
|
||||
|
||||
let realized_envelope = RealizedEnvelope::forced_import(&db, v, indexes)?;
|
||||
let rarity_meter = RarityMeter::forced_import(&db, v, indexes)?;
|
||||
|
||||
let this = Self {
|
||||
db,
|
||||
@@ -54,7 +54,7 @@ impl Vecs {
|
||||
dormancy,
|
||||
stock_to_flow,
|
||||
seller_exhaustion,
|
||||
realized_envelope,
|
||||
rarity_meter,
|
||||
};
|
||||
finalize_db(&this.db, &this)?;
|
||||
Ok(this)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod compute;
|
||||
mod gini;
|
||||
mod import;
|
||||
pub mod realized_envelope;
|
||||
pub mod rarity_meter;
|
||||
mod vecs;
|
||||
|
||||
pub use vecs::Vecs;
|
||||
|
||||
@@ -4,13 +4,12 @@ use brk_types::{Cents, Height, Indexes, StoredI8, Version};
|
||||
use vecdb::{AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
cointime, distribution, indexes,
|
||||
indexes,
|
||||
internal::{PerBlock, Price, RatioPerBlockPercentiles},
|
||||
prices,
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedEnvelope<M: StorageMode = Rw> {
|
||||
pub struct RarityMeterInner<M: StorageMode = Rw> {
|
||||
pub pct0_5: Price<PerBlock<Cents, M>>,
|
||||
pub pct1: Price<PerBlock<Cents, M>>,
|
||||
pub pct2: Price<PerBlock<Cents, M>>,
|
||||
@@ -23,113 +22,85 @@ pub struct RealizedEnvelope<M: StorageMode = Rw> {
|
||||
pub score: PerBlock<StoredI8, M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::new(3);
|
||||
|
||||
impl RealizedEnvelope {
|
||||
impl RarityMeterInner {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
prefix: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
Ok(Self {
|
||||
pct0_5: Price::forced_import(db, "realized_envelope_pct0_5", v, indexes)?,
|
||||
pct1: Price::forced_import(db, "realized_envelope_pct01", v, indexes)?,
|
||||
pct2: Price::forced_import(db, "realized_envelope_pct02", v, indexes)?,
|
||||
pct5: Price::forced_import(db, "realized_envelope_pct05", v, indexes)?,
|
||||
pct95: Price::forced_import(db, "realized_envelope_pct95", v, indexes)?,
|
||||
pct98: Price::forced_import(db, "realized_envelope_pct98", v, indexes)?,
|
||||
pct99: Price::forced_import(db, "realized_envelope_pct99", v, indexes)?,
|
||||
pct99_5: Price::forced_import(db, "realized_envelope_pct99_5", v, indexes)?,
|
||||
index: PerBlock::forced_import(db, "realized_envelope_index", v, indexes)?,
|
||||
score: PerBlock::forced_import(db, "realized_envelope_score", v, indexes)?,
|
||||
pct0_5: Price::forced_import(db, &format!("{prefix}_pct0_5"), version, indexes)?,
|
||||
pct1: Price::forced_import(db, &format!("{prefix}_pct01"), version, indexes)?,
|
||||
pct2: Price::forced_import(db, &format!("{prefix}_pct02"), version, indexes)?,
|
||||
pct5: Price::forced_import(db, &format!("{prefix}_pct05"), version, indexes)?,
|
||||
pct95: Price::forced_import(db, &format!("{prefix}_pct95"), version, indexes)?,
|
||||
pct98: Price::forced_import(db, &format!("{prefix}_pct98"), version, indexes)?,
|
||||
pct99: Price::forced_import(db, &format!("{prefix}_pct99"), version, indexes)?,
|
||||
pct99_5: Price::forced_import(db, &format!("{prefix}_pct99_5"), version, indexes)?,
|
||||
index: PerBlock::forced_import(db, &format!("{prefix}_index"), version, indexes)?,
|
||||
score: PerBlock::forced_import(db, &format!("{prefix}_score"), version, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
pub(super) fn compute(
|
||||
&mut self,
|
||||
distribution: &distribution::Vecs,
|
||||
cointime: &cointime::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
models: &[&RatioPerBlockPercentiles],
|
||||
spot: &impl ReadableVec<Height, Cents>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let realized = &distribution.utxo_cohorts.all.metrics.realized;
|
||||
let ct = &cointime.prices;
|
||||
|
||||
let sth_realized = &distribution.utxo_cohorts.sth.metrics.realized;
|
||||
let lth_realized = &distribution.utxo_cohorts.lth.metrics.realized;
|
||||
|
||||
let models: [&RatioPerBlockPercentiles; 10] = [
|
||||
&realized.price_ratio_percentiles,
|
||||
&realized.investor.price.percentiles,
|
||||
&sth_realized.price_ratio_percentiles,
|
||||
&sth_realized.investor.price.percentiles,
|
||||
<h_realized.price_ratio_percentiles,
|
||||
<h_realized.investor.price.percentiles,
|
||||
&ct.vaulted.percentiles,
|
||||
&ct.active.percentiles,
|
||||
&ct.true_market_mean.percentiles,
|
||||
&ct.cointime.percentiles,
|
||||
];
|
||||
|
||||
macro_rules! sources {
|
||||
($pct:ident) => {
|
||||
models.each_ref().map(|m| &m.$pct.price.cents.height)
|
||||
};
|
||||
}
|
||||
let gather = |f: fn(&RatioPerBlockPercentiles) -> &_| -> Vec<_> {
|
||||
models.iter().map(|m| f(m)).collect()
|
||||
};
|
||||
|
||||
// Lower percentiles: max across all models (tightest lower bound)
|
||||
self.pct0_5.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct0_5),
|
||||
&gather(|m| &m.pct0_5.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct1.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct1),
|
||||
&gather(|m| &m.pct1.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct2.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct2),
|
||||
&gather(|m| &m.pct2.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct5.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct5),
|
||||
&gather(|m| &m.pct5.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Upper percentiles: min across all models (tightest upper bound)
|
||||
self.pct95.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct95),
|
||||
&gather(|m| &m.pct95.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct98.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct98),
|
||||
&gather(|m| &m.pct98.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct99.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct99),
|
||||
&gather(|m| &m.pct99.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct99_5.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
&sources!(pct99_5),
|
||||
&gather(|m| &m.pct99_5.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let spot = &prices.spot.cents.height;
|
||||
|
||||
// Zone: spot vs own envelope bands (-4 to +4)
|
||||
self.compute_index(spot, starting_indexes, exit)?;
|
||||
|
||||
// Temperature: per-model band crossings (-40 to +40)
|
||||
self.compute_score(&models, spot, starting_indexes, exit)?;
|
||||
self.compute_score(models, spot, starting_indexes, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -140,7 +111,7 @@ impl RealizedEnvelope {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let bands: [&_; 8] = [
|
||||
let bands = [
|
||||
&self.pct0_5.cents.height,
|
||||
&self.pct1.cents.height,
|
||||
&self.pct2.cents.height,
|
||||
@@ -213,7 +184,7 @@ impl RealizedEnvelope {
|
||||
|
||||
fn compute_score(
|
||||
&mut self,
|
||||
models: &[&RatioPerBlockPercentiles; 10],
|
||||
models: &[&RatioPerBlockPercentiles],
|
||||
spot: &impl ReadableVec<Height, Cents>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
88
crates/brk_computer/src/indicators/rarity_meter/mod.rs
Normal file
88
crates/brk_computer/src/indicators/rarity_meter/mod.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
mod inner;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Indexes, Version};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{distribution, indexes, prices};
|
||||
|
||||
pub use inner::RarityMeterInner;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RarityMeter<M: StorageMode = Rw> {
|
||||
pub full: RarityMeterInner<M>,
|
||||
pub local: RarityMeterInner<M>,
|
||||
pub cycle: RarityMeterInner<M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::new(4);
|
||||
|
||||
impl RarityMeter {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
Ok(Self {
|
||||
full: RarityMeterInner::forced_import(db, "rarity_meter", v, indexes)?,
|
||||
local: RarityMeterInner::forced_import(db, "local_rarity_meter", v, indexes)?,
|
||||
cycle: RarityMeterInner::forced_import(db, "cycle_rarity_meter", v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
distribution: &distribution::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let realized = &distribution.utxo_cohorts.all.metrics.realized;
|
||||
let sth_realized = &distribution.utxo_cohorts.sth.metrics.realized;
|
||||
let lth_realized = &distribution.utxo_cohorts.lth.metrics.realized;
|
||||
let spot = &prices.spot.cents.height;
|
||||
|
||||
// Full: all + sth + lth (rp + ip), 6 models
|
||||
self.full.compute(
|
||||
&[
|
||||
&realized.price_ratio_percentiles,
|
||||
&realized.investor.price.percentiles,
|
||||
&sth_realized.price_ratio_percentiles,
|
||||
&sth_realized.investor.price.percentiles,
|
||||
<h_realized.price_ratio_percentiles,
|
||||
<h_realized.investor.price.percentiles,
|
||||
],
|
||||
spot,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Local: sth only, 2 models
|
||||
self.local.compute(
|
||||
&[
|
||||
&sth_realized.price_ratio_percentiles,
|
||||
&sth_realized.investor.price.percentiles,
|
||||
],
|
||||
spot,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Cycle: all + lth, 4 models
|
||||
self.cycle.compute(
|
||||
&[
|
||||
&realized.price_ratio_percentiles,
|
||||
&realized.investor.price.percentiles,
|
||||
<h_realized.price_ratio_percentiles,
|
||||
<h_realized.investor.price.percentiles,
|
||||
],
|
||||
spot,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, StoredF32};
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use super::realized_envelope::RealizedEnvelope;
|
||||
use super::rarity_meter::RarityMeter;
|
||||
use crate::internal::{PerBlock, PercentPerBlock, RatioPerBlock};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -25,5 +25,5 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub dormancy: DormancyVecs<M>,
|
||||
pub stock_to_flow: PerBlock<StoredF32, M>,
|
||||
pub seller_exhaustion: PerBlock<StoredF32, M>,
|
||||
pub realized_envelope: RealizedEnvelope<M>,
|
||||
pub rarity_meter: RarityMeter<M>,
|
||||
}
|
||||
|
||||
@@ -467,9 +467,8 @@ impl Computer {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indicators.realized_envelope.compute(
|
||||
self.indicators.rarity_meter.compute(
|
||||
&self.distribution,
|
||||
&self.cointime,
|
||||
&self.prices,
|
||||
&starting_indexes,
|
||||
exit,
|
||||
|
||||
Reference in New Issue
Block a user