pub trait WindowAggregate: Clone {
fn leaf(value: f64) -> Self;
fn combine(&self, other: &Self) -> Self;
fn ratio(&self) -> f64;
}
#[derive(Debug, Clone)]
pub struct MonoidWindow<A: WindowAggregate> {
front: Vec<(f64, A)>, back: Vec<(f64, A)>, }
impl<A: WindowAggregate> Default for MonoidWindow<A> {
fn default() -> Self {
Self {
front: Vec::new(),
back: Vec::new(),
}
}
}
impl<A: WindowAggregate> MonoidWindow<A> {
pub fn clear(&mut self) {
self.front.clear();
self.back.clear();
}
pub fn push_back(&mut self, value: f64) {
let leaf = A::leaf(value);
let agg = match self.back.last() {
Some((_, below)) => below.combine(&leaf),
None => leaf,
};
self.back.push((value, agg));
}
pub fn pop_front(&mut self) -> Option<f64> {
if self.front.is_empty() {
let mut acc: Option<A> = None;
while let Some((value, _)) = self.back.pop() {
let leaf = A::leaf(value);
let agg = match &acc {
Some(below) => leaf.combine(below),
None => leaf,
};
acc = Some(agg.clone());
self.front.push((value, agg));
}
}
self.front.pop().map(|(value, _)| value)
}
pub fn aggregate(&self) -> Option<A> {
match (self.front.last(), self.back.last()) {
(Some((_, f)), Some((_, b))) => Some(f.combine(b)),
(Some((_, f)), None) => Some(f.clone()),
(None, Some((_, b))) => Some(b.clone()),
(None, None) => None,
}
}
}
#[derive(Debug, Clone)]
pub struct DrawdownAgg {
min: f64,
max: f64,
ratio: f64,
}
impl WindowAggregate for DrawdownAgg {
fn leaf(value: f64) -> Self {
Self {
min: value,
max: value,
ratio: 0.0,
}
}
fn combine(&self, other: &Self) -> Self {
let cross = (self.max - other.min) / self.max;
Self {
min: self.min.min(other.min),
max: self.max.max(other.max),
ratio: self.ratio.max(other.ratio).max(cross),
}
}
fn ratio(&self) -> f64 {
self.ratio
}
}
#[derive(Debug, Clone)]
pub struct DrawupAgg {
min: f64,
max: f64,
ratio: f64,
}
impl WindowAggregate for DrawupAgg {
fn leaf(value: f64) -> Self {
Self {
min: value,
max: value,
ratio: 0.0,
}
}
fn combine(&self, other: &Self) -> Self {
let cross = (other.max - self.min) / self.min;
Self {
min: self.min.min(other.min),
max: self.max.max(other.max),
ratio: self.ratio.max(other.ratio).max(cross),
}
}
fn ratio(&self) -> f64 {
self.ratio
}
}