risq 0.4.1

Re-implementation of Bisq (https://github.com/bisq-network/bisq) in rust
use crate::domain::amount::*;
use std::time::SystemTime;

pub struct Hloc {
    pub period_start: SystemTime,
    pub high: NumberWithPrecision,
    pub low: NumberWithPrecision,
    pub open: NumberWithPrecision,
    pub close: NumberWithPrecision,
    pub volume_left: NumberWithPrecision,
    pub volume_right: NumberWithPrecision,
}

#[cfg(feature = "statistics")]
pub use inner::*;
#[cfg(feature = "statistics")]
mod inner {
    use super::*;
    use crate::domain::{
        market::*,
        statistics::{interval::*, trade::*},
    };
    use std::time::{SystemTime, UNIX_EPOCH};

    pub struct HlocQuery {
        pub market: &'static Market,
        pub timestamp_from: Option<SystemTime>,
        pub timestamp_to: Option<SystemTime>,
        pub interval: Option<Interval>,
    }

    impl Hloc {
        pub fn from_trades(
            history: &TradeHistory,
            HlocQuery {
                market,
                timestamp_from,
                timestamp_to,
                interval,
            }: HlocQuery,
        ) -> Vec<Hloc> {
            let from = match history.first_trade_time() {
                None => return Vec::new(),
                Some(time) => time.max(timestamp_from.unwrap_or(UNIX_EPOCH)),
            };
            let to = from.max(timestamp_to.unwrap_or_else(SystemTime::now));
            let interval = interval.unwrap_or_else(|| Interval::default_for_range(&from, &to));

            let mut ret = Vec::new();
            let mut trades = history.iter().filter(|t| t.market.pair == market.pair);
            let mut trade = match trades.next() {
                None => return ret,
                Some(next) => next,
            };
            for (period_start, end) in interval.intervals(from, to) {
                while trade.timestamp < period_start {
                    trade = match trades.next() {
                        None => return ret,
                        Some(next) => next,
                    };
                }
                if trade.timestamp >= end {
                    continue;
                }

                let mut current = Hloc {
                    period_start,
                    high: trade.price,
                    low: trade.price,
                    open: trade.price,
                    close: trade.price,
                    volume_left: NumberWithPrecision::new(0, 4),
                    volume_right: NumberWithPrecision::new(0, 4),
                };
                while trade.timestamp < end {
                    current.high = current.high.max(trade.price);
                    current.low = current.low.min(trade.price);
                    current.close = trade.price;
                    current.volume_left += trade.amount;
                    current.volume_right += trade.volume;
                    trade = match trades.next() {
                        None => {
                            ret.push(current);
                            return ret;
                        }
                        Some(next) => next,
                    };
                }
                ret.push(current);
            }
            ret
        }
    }
}