use brk_traversable::Traversable;
use brk_types::Cents;
use rayon::prelude::*;
use serde::Serialize;
use super::CohortName;
pub const PROFITABILITY_BOUNDARY_COUNT: usize = 24;
pub fn compute_profitability_boundaries(spot: Cents) -> [Cents; PROFITABILITY_BOUNDARY_COUNT] {
let s = spot.as_u128();
let divisors: [u128; PROFITABILITY_BOUNDARY_COUNT] = [
1100, 600, 400, 300, 200, 190, 180, 170, 160, 150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, ];
let mut boundaries = [Cents::ZERO; PROFITABILITY_BOUNDARY_COUNT];
for (i, &d) in divisors.iter().enumerate() {
boundaries[i] = Cents::from(s * 100 / d);
}
boundaries
}
pub const PROFITABILITY_RANGE_NAMES: ProfitabilityRange<CohortName> = ProfitabilityRange {
over_1000pct_in_profit: CohortName::new("utxos_over_1000pct_in_profit", "+>1000%", "Over 1000% in Profit"),
_500pct_to_1000pct_in_profit: CohortName::new("utxos_500pct_to_1000pct_in_profit", "+500-1000%", "500-1000% in Profit"),
_300pct_to_500pct_in_profit: CohortName::new("utxos_300pct_to_500pct_in_profit", "+300-500%", "300-500% in Profit"),
_200pct_to_300pct_in_profit: CohortName::new("utxos_200pct_to_300pct_in_profit", "+200-300%", "200-300% in Profit"),
_100pct_to_200pct_in_profit: CohortName::new("utxos_100pct_to_200pct_in_profit", "+100-200%", "100-200% in Profit"),
_90pct_to_100pct_in_profit: CohortName::new("utxos_90pct_to_100pct_in_profit", "+90-100%", "90-100% in Profit"),
_80pct_to_90pct_in_profit: CohortName::new("utxos_80pct_to_90pct_in_profit", "+80-90%", "80-90% in Profit"),
_70pct_to_80pct_in_profit: CohortName::new("utxos_70pct_to_80pct_in_profit", "+70-80%", "70-80% in Profit"),
_60pct_to_70pct_in_profit: CohortName::new("utxos_60pct_to_70pct_in_profit", "+60-70%", "60-70% in Profit"),
_50pct_to_60pct_in_profit: CohortName::new("utxos_50pct_to_60pct_in_profit", "+50-60%", "50-60% in Profit"),
_40pct_to_50pct_in_profit: CohortName::new("utxos_40pct_to_50pct_in_profit", "+40-50%", "40-50% in Profit"),
_30pct_to_40pct_in_profit: CohortName::new("utxos_30pct_to_40pct_in_profit", "+30-40%", "30-40% in Profit"),
_20pct_to_30pct_in_profit: CohortName::new("utxos_20pct_to_30pct_in_profit", "+20-30%", "20-30% in Profit"),
_10pct_to_20pct_in_profit: CohortName::new("utxos_10pct_to_20pct_in_profit", "+10-20%", "10-20% in Profit"),
_0pct_to_10pct_in_profit: CohortName::new("utxos_0pct_to_10pct_in_profit", "+0-10%", "0-10% in Profit"),
_0pct_to_10pct_in_loss: CohortName::new("utxos_0pct_to_10pct_in_loss", "-0-10%", "0-10% in Loss"),
_10pct_to_20pct_in_loss: CohortName::new("utxos_10pct_to_20pct_in_loss", "-10-20%", "10-20% in Loss"),
_20pct_to_30pct_in_loss: CohortName::new("utxos_20pct_to_30pct_in_loss", "-20-30%", "20-30% in Loss"),
_30pct_to_40pct_in_loss: CohortName::new("utxos_30pct_to_40pct_in_loss", "-30-40%", "30-40% in Loss"),
_40pct_to_50pct_in_loss: CohortName::new("utxos_40pct_to_50pct_in_loss", "-40-50%", "40-50% in Loss"),
_50pct_to_60pct_in_loss: CohortName::new("utxos_50pct_to_60pct_in_loss", "-50-60%", "50-60% in Loss"),
_60pct_to_70pct_in_loss: CohortName::new("utxos_60pct_to_70pct_in_loss", "-60-70%", "60-70% in Loss"),
_70pct_to_80pct_in_loss: CohortName::new("utxos_70pct_to_80pct_in_loss", "-70-80%", "70-80% in Loss"),
_80pct_to_90pct_in_loss: CohortName::new("utxos_80pct_to_90pct_in_loss", "-80-90%", "80-90% in Loss"),
_90pct_to_100pct_in_loss: CohortName::new("utxos_90pct_to_100pct_in_loss", "-90-100%", "90-100% in Loss"),
};
impl ProfitabilityRange<CohortName> {
pub const fn names() -> &'static Self {
&PROFITABILITY_RANGE_NAMES
}
}
#[derive(Default, Clone, Traversable, Serialize)]
pub struct ProfitabilityRange<T> {
pub over_1000pct_in_profit: T,
pub _500pct_to_1000pct_in_profit: T,
pub _300pct_to_500pct_in_profit: T,
pub _200pct_to_300pct_in_profit: T,
pub _100pct_to_200pct_in_profit: T,
pub _90pct_to_100pct_in_profit: T,
pub _80pct_to_90pct_in_profit: T,
pub _70pct_to_80pct_in_profit: T,
pub _60pct_to_70pct_in_profit: T,
pub _50pct_to_60pct_in_profit: T,
pub _40pct_to_50pct_in_profit: T,
pub _30pct_to_40pct_in_profit: T,
pub _20pct_to_30pct_in_profit: T,
pub _10pct_to_20pct_in_profit: T,
pub _0pct_to_10pct_in_profit: T,
pub _0pct_to_10pct_in_loss: T,
pub _10pct_to_20pct_in_loss: T,
pub _20pct_to_30pct_in_loss: T,
pub _30pct_to_40pct_in_loss: T,
pub _40pct_to_50pct_in_loss: T,
pub _50pct_to_60pct_in_loss: T,
pub _60pct_to_70pct_in_loss: T,
pub _70pct_to_80pct_in_loss: T,
pub _80pct_to_90pct_in_loss: T,
pub _90pct_to_100pct_in_loss: T,
}
pub const PROFITABILITY_RANGE_COUNT: usize = 25;
impl<T> ProfitabilityRange<T> {
pub fn new<F>(mut create: F) -> Self
where
F: FnMut(&'static str) -> T,
{
let n = &PROFITABILITY_RANGE_NAMES;
Self {
over_1000pct_in_profit: create(n.over_1000pct_in_profit.id),
_500pct_to_1000pct_in_profit: create(n._500pct_to_1000pct_in_profit.id),
_300pct_to_500pct_in_profit: create(n._300pct_to_500pct_in_profit.id),
_200pct_to_300pct_in_profit: create(n._200pct_to_300pct_in_profit.id),
_100pct_to_200pct_in_profit: create(n._100pct_to_200pct_in_profit.id),
_90pct_to_100pct_in_profit: create(n._90pct_to_100pct_in_profit.id),
_80pct_to_90pct_in_profit: create(n._80pct_to_90pct_in_profit.id),
_70pct_to_80pct_in_profit: create(n._70pct_to_80pct_in_profit.id),
_60pct_to_70pct_in_profit: create(n._60pct_to_70pct_in_profit.id),
_50pct_to_60pct_in_profit: create(n._50pct_to_60pct_in_profit.id),
_40pct_to_50pct_in_profit: create(n._40pct_to_50pct_in_profit.id),
_30pct_to_40pct_in_profit: create(n._30pct_to_40pct_in_profit.id),
_20pct_to_30pct_in_profit: create(n._20pct_to_30pct_in_profit.id),
_10pct_to_20pct_in_profit: create(n._10pct_to_20pct_in_profit.id),
_0pct_to_10pct_in_profit: create(n._0pct_to_10pct_in_profit.id),
_0pct_to_10pct_in_loss: create(n._0pct_to_10pct_in_loss.id),
_10pct_to_20pct_in_loss: create(n._10pct_to_20pct_in_loss.id),
_20pct_to_30pct_in_loss: create(n._20pct_to_30pct_in_loss.id),
_30pct_to_40pct_in_loss: create(n._30pct_to_40pct_in_loss.id),
_40pct_to_50pct_in_loss: create(n._40pct_to_50pct_in_loss.id),
_50pct_to_60pct_in_loss: create(n._50pct_to_60pct_in_loss.id),
_60pct_to_70pct_in_loss: create(n._60pct_to_70pct_in_loss.id),
_70pct_to_80pct_in_loss: create(n._70pct_to_80pct_in_loss.id),
_80pct_to_90pct_in_loss: create(n._80pct_to_90pct_in_loss.id),
_90pct_to_100pct_in_loss: create(n._90pct_to_100pct_in_loss.id),
}
}
pub fn try_new<F, E>(mut create: F) -> Result<Self, E>
where
F: FnMut(&'static str) -> Result<T, E>,
{
let n = &PROFITABILITY_RANGE_NAMES;
Ok(Self {
over_1000pct_in_profit: create(n.over_1000pct_in_profit.id)?,
_500pct_to_1000pct_in_profit: create(n._500pct_to_1000pct_in_profit.id)?,
_300pct_to_500pct_in_profit: create(n._300pct_to_500pct_in_profit.id)?,
_200pct_to_300pct_in_profit: create(n._200pct_to_300pct_in_profit.id)?,
_100pct_to_200pct_in_profit: create(n._100pct_to_200pct_in_profit.id)?,
_90pct_to_100pct_in_profit: create(n._90pct_to_100pct_in_profit.id)?,
_80pct_to_90pct_in_profit: create(n._80pct_to_90pct_in_profit.id)?,
_70pct_to_80pct_in_profit: create(n._70pct_to_80pct_in_profit.id)?,
_60pct_to_70pct_in_profit: create(n._60pct_to_70pct_in_profit.id)?,
_50pct_to_60pct_in_profit: create(n._50pct_to_60pct_in_profit.id)?,
_40pct_to_50pct_in_profit: create(n._40pct_to_50pct_in_profit.id)?,
_30pct_to_40pct_in_profit: create(n._30pct_to_40pct_in_profit.id)?,
_20pct_to_30pct_in_profit: create(n._20pct_to_30pct_in_profit.id)?,
_10pct_to_20pct_in_profit: create(n._10pct_to_20pct_in_profit.id)?,
_0pct_to_10pct_in_profit: create(n._0pct_to_10pct_in_profit.id)?,
_0pct_to_10pct_in_loss: create(n._0pct_to_10pct_in_loss.id)?,
_10pct_to_20pct_in_loss: create(n._10pct_to_20pct_in_loss.id)?,
_20pct_to_30pct_in_loss: create(n._20pct_to_30pct_in_loss.id)?,
_30pct_to_40pct_in_loss: create(n._30pct_to_40pct_in_loss.id)?,
_40pct_to_50pct_in_loss: create(n._40pct_to_50pct_in_loss.id)?,
_50pct_to_60pct_in_loss: create(n._50pct_to_60pct_in_loss.id)?,
_60pct_to_70pct_in_loss: create(n._60pct_to_70pct_in_loss.id)?,
_70pct_to_80pct_in_loss: create(n._70pct_to_80pct_in_loss.id)?,
_80pct_to_90pct_in_loss: create(n._80pct_to_90pct_in_loss.id)?,
_90pct_to_100pct_in_loss: create(n._90pct_to_100pct_in_loss.id)?,
})
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
[
&self.over_1000pct_in_profit,
&self._500pct_to_1000pct_in_profit,
&self._300pct_to_500pct_in_profit,
&self._200pct_to_300pct_in_profit,
&self._100pct_to_200pct_in_profit,
&self._90pct_to_100pct_in_profit,
&self._80pct_to_90pct_in_profit,
&self._70pct_to_80pct_in_profit,
&self._60pct_to_70pct_in_profit,
&self._50pct_to_60pct_in_profit,
&self._40pct_to_50pct_in_profit,
&self._30pct_to_40pct_in_profit,
&self._20pct_to_30pct_in_profit,
&self._10pct_to_20pct_in_profit,
&self._0pct_to_10pct_in_profit,
&self._0pct_to_10pct_in_loss,
&self._10pct_to_20pct_in_loss,
&self._20pct_to_30pct_in_loss,
&self._30pct_to_40pct_in_loss,
&self._40pct_to_50pct_in_loss,
&self._50pct_to_60pct_in_loss,
&self._60pct_to_70pct_in_loss,
&self._70pct_to_80pct_in_loss,
&self._80pct_to_90pct_in_loss,
&self._90pct_to_100pct_in_loss,
]
.into_iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.iter_mut_with_is_profit().map(|(_, v)| v)
}
pub fn iter_mut_with_is_profit(&mut self) -> impl Iterator<Item = (bool, &mut T)> {
[
(true, &mut self.over_1000pct_in_profit),
(true, &mut self._500pct_to_1000pct_in_profit),
(true, &mut self._300pct_to_500pct_in_profit),
(true, &mut self._200pct_to_300pct_in_profit),
(true, &mut self._100pct_to_200pct_in_profit),
(true, &mut self._90pct_to_100pct_in_profit),
(true, &mut self._80pct_to_90pct_in_profit),
(true, &mut self._70pct_to_80pct_in_profit),
(true, &mut self._60pct_to_70pct_in_profit),
(true, &mut self._50pct_to_60pct_in_profit),
(true, &mut self._40pct_to_50pct_in_profit),
(true, &mut self._30pct_to_40pct_in_profit),
(true, &mut self._20pct_to_30pct_in_profit),
(true, &mut self._10pct_to_20pct_in_profit),
(true, &mut self._0pct_to_10pct_in_profit),
(false, &mut self._0pct_to_10pct_in_loss),
(false, &mut self._10pct_to_20pct_in_loss),
(false, &mut self._20pct_to_30pct_in_loss),
(false, &mut self._30pct_to_40pct_in_loss),
(false, &mut self._40pct_to_50pct_in_loss),
(false, &mut self._50pct_to_60pct_in_loss),
(false, &mut self._60pct_to_70pct_in_loss),
(false, &mut self._70pct_to_80pct_in_loss),
(false, &mut self._80pct_to_90pct_in_loss),
(false, &mut self._90pct_to_100pct_in_loss),
]
.into_iter()
}
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut T>
where
T: Send + Sync,
{
[
&mut self.over_1000pct_in_profit,
&mut self._500pct_to_1000pct_in_profit,
&mut self._300pct_to_500pct_in_profit,
&mut self._200pct_to_300pct_in_profit,
&mut self._100pct_to_200pct_in_profit,
&mut self._90pct_to_100pct_in_profit,
&mut self._80pct_to_90pct_in_profit,
&mut self._70pct_to_80pct_in_profit,
&mut self._60pct_to_70pct_in_profit,
&mut self._50pct_to_60pct_in_profit,
&mut self._40pct_to_50pct_in_profit,
&mut self._30pct_to_40pct_in_profit,
&mut self._20pct_to_30pct_in_profit,
&mut self._10pct_to_20pct_in_profit,
&mut self._0pct_to_10pct_in_profit,
&mut self._0pct_to_10pct_in_loss,
&mut self._10pct_to_20pct_in_loss,
&mut self._20pct_to_30pct_in_loss,
&mut self._30pct_to_40pct_in_loss,
&mut self._40pct_to_50pct_in_loss,
&mut self._50pct_to_60pct_in_loss,
&mut self._60pct_to_70pct_in_loss,
&mut self._70pct_to_80pct_in_loss,
&mut self._80pct_to_90pct_in_loss,
&mut self._90pct_to_100pct_in_loss,
]
.into_par_iter()
}
pub fn as_array(&self) -> [&T; PROFITABILITY_RANGE_COUNT] {
[
&self.over_1000pct_in_profit,
&self._500pct_to_1000pct_in_profit,
&self._300pct_to_500pct_in_profit,
&self._200pct_to_300pct_in_profit,
&self._100pct_to_200pct_in_profit,
&self._90pct_to_100pct_in_profit,
&self._80pct_to_90pct_in_profit,
&self._70pct_to_80pct_in_profit,
&self._60pct_to_70pct_in_profit,
&self._50pct_to_60pct_in_profit,
&self._40pct_to_50pct_in_profit,
&self._30pct_to_40pct_in_profit,
&self._20pct_to_30pct_in_profit,
&self._10pct_to_20pct_in_profit,
&self._0pct_to_10pct_in_profit,
&self._0pct_to_10pct_in_loss,
&self._10pct_to_20pct_in_loss,
&self._20pct_to_30pct_in_loss,
&self._30pct_to_40pct_in_loss,
&self._40pct_to_50pct_in_loss,
&self._50pct_to_60pct_in_loss,
&self._60pct_to_70pct_in_loss,
&self._70pct_to_80pct_in_loss,
&self._80pct_to_90pct_in_loss,
&self._90pct_to_100pct_in_loss,
]
}
pub fn as_array_mut(&mut self) -> [&mut T; PROFITABILITY_RANGE_COUNT] {
[
&mut self.over_1000pct_in_profit,
&mut self._500pct_to_1000pct_in_profit,
&mut self._300pct_to_500pct_in_profit,
&mut self._200pct_to_300pct_in_profit,
&mut self._100pct_to_200pct_in_profit,
&mut self._90pct_to_100pct_in_profit,
&mut self._80pct_to_90pct_in_profit,
&mut self._70pct_to_80pct_in_profit,
&mut self._60pct_to_70pct_in_profit,
&mut self._50pct_to_60pct_in_profit,
&mut self._40pct_to_50pct_in_profit,
&mut self._30pct_to_40pct_in_profit,
&mut self._20pct_to_30pct_in_profit,
&mut self._10pct_to_20pct_in_profit,
&mut self._0pct_to_10pct_in_profit,
&mut self._0pct_to_10pct_in_loss,
&mut self._10pct_to_20pct_in_loss,
&mut self._20pct_to_30pct_in_loss,
&mut self._30pct_to_40pct_in_loss,
&mut self._40pct_to_50pct_in_loss,
&mut self._50pct_to_60pct_in_loss,
&mut self._60pct_to_70pct_in_loss,
&mut self._70pct_to_80pct_in_loss,
&mut self._80pct_to_90pct_in_loss,
&mut self._90pct_to_100pct_in_loss,
]
}
}