global: snapshot

This commit is contained in:
nym21
2026-03-03 22:10:05 +01:00
parent 28f6b0f18b
commit 269c1d5fdf
99 changed files with 1565 additions and 1146 deletions
@@ -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,
+9 -9
View File
@@ -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,
})
}
}
+5 -5
View File
@@ -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>,
}
+84 -85
View File
@@ -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),
]
}
}
+21 -20
View File
@@ -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,
+36 -21
View File
@@ -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,
})
}
}
+8 -8
View File
@@ -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);
+12 -12
View File
@@ -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,
)?,
})
}
+10 -10
View File
@@ -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,
})
}
}
+12 -12
View File
@@ -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>,
}