mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-22 00:18:10 -07:00
global: snapshot
This commit is contained in:
@@ -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>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user