mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-25 07:09:59 -07:00
investing: more data + charts
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Close, Dollars, StoredF32, StoredU32};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use super::{ByDcaClass, ByDcaPeriod, Vecs};
|
||||
use crate::{
|
||||
ComputeIndexes,
|
||||
internal::{ComputedFromDateLast, LazyBinaryFromDateLast},
|
||||
market::lookback,
|
||||
price,
|
||||
traits::{ComputeDCAAveragePriceViaLen, ComputeDCAStackViaLen, ComputeLumpSumStackViaLen},
|
||||
@@ -61,6 +63,17 @@ impl Vecs {
|
||||
})?;
|
||||
}
|
||||
|
||||
// DCA by period - profitability
|
||||
compute_period_profitability(
|
||||
&mut self.period_days_in_profit,
|
||||
&mut self.period_days_in_loss,
|
||||
&mut self.period_max_drawdown,
|
||||
&mut self.period_max_return,
|
||||
&self.period_returns,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Lump sum by period - stack (for comparison with DCA)
|
||||
let lookback_dca = lookback.price_ago.as_dca_period();
|
||||
for (stack, lookback_price, days) in
|
||||
@@ -78,6 +91,17 @@ impl Vecs {
|
||||
})?;
|
||||
}
|
||||
|
||||
// Lump sum by period - profitability
|
||||
compute_period_profitability(
|
||||
&mut self.period_lump_sum_days_in_profit,
|
||||
&mut self.period_lump_sum_days_in_loss,
|
||||
&mut self.period_lump_sum_max_drawdown,
|
||||
&mut self.period_lump_sum_max_return,
|
||||
&self.period_lump_sum_returns,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// DCA by year class - stack and average_price
|
||||
let dateindexes = super::ByDcaClass::<()>::dateindexes();
|
||||
for ((stack, average_price), dateindex) in self
|
||||
@@ -102,6 +126,134 @@ impl Vecs {
|
||||
})?;
|
||||
}
|
||||
|
||||
// DCA by year class - profitability
|
||||
compute_class_profitability(
|
||||
&mut self.class_days_in_profit,
|
||||
&mut self.class_days_in_loss,
|
||||
&mut self.class_max_drawdown,
|
||||
&mut self.class_max_return,
|
||||
&self.class_returns,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_period_profitability(
|
||||
days_in_profit: &mut ByDcaPeriod<ComputedFromDateLast<StoredU32>>,
|
||||
days_in_loss: &mut ByDcaPeriod<ComputedFromDateLast<StoredU32>>,
|
||||
max_drawdown: &mut ByDcaPeriod<ComputedFromDateLast<StoredF32>>,
|
||||
max_return: &mut ByDcaPeriod<ComputedFromDateLast<StoredF32>>,
|
||||
returns: &ByDcaPeriod<LazyBinaryFromDateLast<StoredF32, Close<Dollars>, Dollars>>,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for ((((dip, dil), md), mr), (ret, days)) in days_in_profit
|
||||
.iter_mut()
|
||||
.zip(days_in_loss.iter_mut())
|
||||
.zip(max_drawdown.iter_mut())
|
||||
.zip(max_return.iter_mut())
|
||||
.zip(returns.iter_with_days())
|
||||
{
|
||||
dip.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_rolling_count(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
days as usize,
|
||||
|r| f32::from(*r) > 0.0,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
|
||||
dil.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_rolling_count(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
days as usize,
|
||||
|r| f32::from(*r) < 0.0,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
|
||||
md.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_min(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
days as usize,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
|
||||
mr.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_max(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
days as usize,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compute_class_profitability(
|
||||
days_in_profit: &mut ByDcaClass<ComputedFromDateLast<StoredU32>>,
|
||||
days_in_loss: &mut ByDcaClass<ComputedFromDateLast<StoredU32>>,
|
||||
max_drawdown: &mut ByDcaClass<ComputedFromDateLast<StoredF32>>,
|
||||
max_return: &mut ByDcaClass<ComputedFromDateLast<StoredF32>>,
|
||||
returns: &ByDcaClass<LazyBinaryFromDateLast<StoredF32, Close<Dollars>, Dollars>>,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let dateindexes = ByDcaClass::<()>::dateindexes();
|
||||
|
||||
for (((((dip, dil), md), mr), ret), from) in days_in_profit
|
||||
.iter_mut()
|
||||
.zip(days_in_loss.iter_mut())
|
||||
.zip(max_drawdown.iter_mut())
|
||||
.zip(max_return.iter_mut())
|
||||
.zip(returns.iter())
|
||||
.zip(dateindexes)
|
||||
{
|
||||
dip.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_cumulative_count_from(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
from,
|
||||
|r| f32::from(*r) > 0.0,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
|
||||
dil.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_cumulative_count_from(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
from,
|
||||
|r| f32::from(*r) < 0.0,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
|
||||
md.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_all_time_low_from(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
from,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
|
||||
mr.compute_all(starting_indexes, exit, |v| {
|
||||
Ok(v.compute_all_time_high_from(
|
||||
starting_indexes.dateindex,
|
||||
&ret.dateindex,
|
||||
from,
|
||||
exit,
|
||||
)?)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
use vecdb::{Database, IterableCloneableVec};
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, DCA_CLASS_NAMES, DCA_PERIOD_NAMES, Vecs};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromDateLast, LazyBinaryFromDateLast, PercentageDiffCloseDollars, ValueFromDateLast},
|
||||
internal::{
|
||||
ComputedFromDateLast, LazyBinaryFromDateLast, PercentageDiffCloseDollars,
|
||||
ValueFromDateLast,
|
||||
},
|
||||
market::lookback,
|
||||
price,
|
||||
};
|
||||
|
||||
@@ -15,6 +19,7 @@ impl Vecs {
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
price: &price::Vecs,
|
||||
lookback: &lookback::Vecs,
|
||||
) -> Result<Self> {
|
||||
// DCA by period - stack (KISS)
|
||||
let period_stack = ByDcaPeriod::try_new(|name, _days| {
|
||||
@@ -48,6 +53,43 @@ impl Vecs {
|
||||
ComputedFromDateLast::forced_import(db, &format!("{name}_dca_cagr"), version, indexes)
|
||||
})?;
|
||||
|
||||
// DCA by period - profitability
|
||||
let period_days_in_profit = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_dca_days_in_profit"),
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_days_in_loss = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_dca_days_in_loss"),
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_max_drawdown = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_dca_max_drawdown"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_max_return = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_dca_max_return"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Lump sum by period - stack (KISS)
|
||||
let period_lump_sum_stack = ByDcaPeriod::try_new(|name, _days| {
|
||||
ValueFromDateLast::forced_import(
|
||||
@@ -59,6 +101,58 @@ impl Vecs {
|
||||
)
|
||||
})?;
|
||||
|
||||
// Lump sum by period - returns
|
||||
let period_lump_sum_returns = DCA_PERIOD_NAMES
|
||||
.zip_ref(&lookback.price_ago.as_dca_period())
|
||||
.map(|(name, lookback_price)| {
|
||||
LazyBinaryFromDateLast::from_derived_last_and_computed_last::<
|
||||
PercentageDiffCloseDollars,
|
||||
>(
|
||||
&format!("{name}_lump_sum_returns"),
|
||||
version,
|
||||
price.usd.split.close.dateindex.boxed_clone(),
|
||||
&price.usd.split.close.rest,
|
||||
lookback_price,
|
||||
)
|
||||
});
|
||||
|
||||
// Lump sum by period - profitability
|
||||
let period_lump_sum_days_in_profit = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_lump_sum_days_in_profit"),
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_lump_sum_days_in_loss = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_lump_sum_days_in_loss"),
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_lump_sum_max_drawdown = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_lump_sum_max_drawdown"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let period_lump_sum_max_return = ByDcaPeriod::try_new(|name, _days| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_lump_sum_max_return"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
// DCA by year class - stack (KISS)
|
||||
let class_stack = ByDcaClass::try_new(|name, _year, _dateindex| {
|
||||
ValueFromDateLast::forced_import(db, &format!("{name}_stack"), version, true, indexes)
|
||||
@@ -81,15 +175,65 @@ impl Vecs {
|
||||
)
|
||||
});
|
||||
|
||||
// DCA by year class - profitability
|
||||
let class_days_in_profit = ByDcaClass::try_new(|name, _year, _dateindex| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_days_in_profit"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let class_days_in_loss = ByDcaClass::try_new(|name, _year, _dateindex| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_days_in_loss"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let class_max_drawdown = ByDcaClass::try_new(|name, _year, _dateindex| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_max_drawdown"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
let class_max_return = ByDcaClass::try_new(|name, _year, _dateindex| {
|
||||
ComputedFromDateLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_max_return"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
period_stack,
|
||||
period_average_price,
|
||||
period_returns,
|
||||
period_cagr,
|
||||
period_days_in_profit,
|
||||
period_days_in_loss,
|
||||
period_max_drawdown,
|
||||
period_max_return,
|
||||
period_lump_sum_stack,
|
||||
period_lump_sum_returns,
|
||||
period_lump_sum_days_in_profit,
|
||||
period_lump_sum_days_in_loss,
|
||||
period_lump_sum_max_drawdown,
|
||||
period_lump_sum_max_return,
|
||||
class_stack,
|
||||
class_average_price,
|
||||
class_returns,
|
||||
class_days_in_profit,
|
||||
class_days_in_loss,
|
||||
class_max_drawdown,
|
||||
class_max_return,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Close, Dollars, StoredF32};
|
||||
use brk_types::{Close, Dollars, StoredF32, StoredU32};
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod};
|
||||
use crate::internal::{ComputedFromDateLast, LazyBinaryFromDateLast, ValueFromDateLast};
|
||||
@@ -13,11 +13,30 @@ pub struct Vecs {
|
||||
pub period_returns: ByDcaPeriod<LazyBinaryFromDateLast<StoredF32, Close<Dollars>, Dollars>>,
|
||||
pub period_cagr: ByDcaCagr<ComputedFromDateLast<StoredF32>>,
|
||||
|
||||
// DCA by period - profitability
|
||||
pub period_days_in_profit: ByDcaPeriod<ComputedFromDateLast<StoredU32>>,
|
||||
pub period_days_in_loss: ByDcaPeriod<ComputedFromDateLast<StoredU32>>,
|
||||
pub period_max_drawdown: ByDcaPeriod<ComputedFromDateLast<StoredF32>>,
|
||||
pub period_max_return: ByDcaPeriod<ComputedFromDateLast<StoredF32>>,
|
||||
|
||||
// Lump sum by period (for comparison with DCA) - KISS types
|
||||
pub period_lump_sum_stack: ByDcaPeriod<ValueFromDateLast>,
|
||||
pub period_lump_sum_returns: ByDcaPeriod<LazyBinaryFromDateLast<StoredF32, Close<Dollars>, Dollars>>,
|
||||
|
||||
// Lump sum by period - profitability
|
||||
pub period_lump_sum_days_in_profit: ByDcaPeriod<ComputedFromDateLast<StoredU32>>,
|
||||
pub period_lump_sum_days_in_loss: ByDcaPeriod<ComputedFromDateLast<StoredU32>>,
|
||||
pub period_lump_sum_max_drawdown: ByDcaPeriod<ComputedFromDateLast<StoredF32>>,
|
||||
pub period_lump_sum_max_return: ByDcaPeriod<ComputedFromDateLast<StoredF32>>,
|
||||
|
||||
// DCA by year class - KISS types
|
||||
pub class_stack: ByDcaClass<ValueFromDateLast>,
|
||||
pub class_average_price: ByDcaClass<ComputedFromDateLast<Dollars>>,
|
||||
pub class_returns: ByDcaClass<LazyBinaryFromDateLast<StoredF32, Close<Dollars>, Dollars>>,
|
||||
|
||||
// DCA by year class - profitability
|
||||
pub class_days_in_profit: ByDcaClass<ComputedFromDateLast<StoredU32>>,
|
||||
pub class_days_in_loss: ByDcaClass<ComputedFromDateLast<StoredU32>>,
|
||||
pub class_max_drawdown: ByDcaClass<ComputedFromDateLast<StoredF32>>,
|
||||
pub class_max_return: ByDcaClass<ComputedFromDateLast<StoredF32>>,
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl Vecs {
|
||||
let volatility = VolatilityVecs::forced_import(version, &returns);
|
||||
let range = RangeVecs::forced_import(&db, version, indexes)?;
|
||||
let moving_average = MovingAverageVecs::forced_import(&db, version, indexes, Some(price))?;
|
||||
let dca = DcaVecs::forced_import(&db, version, indexes, price)?;
|
||||
let dca = DcaVecs::forced_import(&db, version, indexes, price, &lookback)?;
|
||||
let indicators = IndicatorsVecs::forced_import(
|
||||
&db,
|
||||
version,
|
||||
|
||||
Reference in New Issue
Block a user