apple-quant-algorithmic 0.4.0

Apple Quant's algorithmic library.
Documentation
use std::{fmt::Debug, marker::PhantomData};

use smallvec::SmallVec;

use crate::{
	instrument::{InstrumentData, InstrumentSpec},
	aggregation::Aggregator,
};

#[derive(Debug)]
pub struct FixedHotData<
	'instrument_data,
	'aggregated_data,
	const COUNT: usize,
	IS: InstrumentSpec,
	AggregationData,
	T: Aggregator<'instrument_data, 'aggregated_data, T, AggregationData, IS>
		+ 'aggregated_data
		+ Clone
		+ Debug,
> {
	data: SmallVec<[T; COUNT]>,
	_aggregation_data: PhantomData<AggregationData>,
	_instrument_spec: PhantomData<IS>,
	_instrument_data: PhantomData<&'instrument_data ()>,
	_a: PhantomData<&'aggregated_data ()>,
}

impl<
	'instrument_data,
	'aggregated_data,
	const COUNT: usize,
	IS: InstrumentSpec,
	AggregationData,
	T: Aggregator<'instrument_data, 'aggregated_data, T, AggregationData, IS>
		+ 'aggregated_data
		+ Clone
		+ Debug,
> Default for FixedHotData<
	'instrument_data,
	'aggregated_data,
	COUNT,
	IS,
	AggregationData,
	T,
> {
	fn default() -> Self {
		Self {
			data: SmallVec::default(),
			_aggregation_data: PhantomData::default(),
			_instrument_spec: PhantomData::default(),
			_instrument_data: PhantomData::default(),
			_a: PhantomData::default(),
		}
	}
}

impl<
	'instrument_data,
	'aggregated_data,
	const COUNT: usize,
	IS: InstrumentSpec,
	AggregationData,
	T: Aggregator<'instrument_data, 'aggregated_data, T, AggregationData, IS>
		+ 'aggregated_data
		+ Clone
		+ Debug,
> FixedHotData<
	'instrument_data,
	'aggregated_data,
	COUNT,
	IS,
	AggregationData,
	T,
> {
	pub fn len(
		&self,
	) -> usize {
		self.data.len()
	}

	pub fn capacity(
		&self,
	) -> usize {
		COUNT
	}

	pub fn is_empty(
		&self,
	) -> bool {
		self.data.is_empty()
	}

	pub fn clear(
		&mut self,
	) {
		self.data.clear();
	}

	pub fn remove_newest(
		&mut self,
	) -> Option<T> {
		self.data.pop()
	}

	pub fn newest(
		&self,
	) -> Option<&T> {
		self.data.last()
	}

	pub fn oldest(
		&self,
	) -> Option<&T> {
		self.data.first()
	}

	pub fn data_update(
		&mut self,
		instrument_data: &'instrument_data InstrumentData<
			'instrument_data,
			'aggregated_data,
			IS,
		>,
	) {
		let aggregated_data: SmallVec<[T; 4]> = {
			let aggregation_data = T::hot_data(instrument_data, self.iter_rev());
			T::aggregate_hot(&aggregation_data).collect()
		};

		self.append_manual(aggregated_data.into_iter());
	}

	pub fn append_manual(
		&mut self,
		append_data: impl ExactSizeIterator<Item = T>,
	) {
		debug_assert!(self.data.len() <= COUNT);

		let unused_capacity = COUNT - self.data.len();

		let mut drain_count = append_data.len().saturating_sub(unused_capacity).min(
			COUNT,
		);

		let data_skip_count = append_data.len().saturating_sub(COUNT).min(COUNT);

		drain_count = drain_count.checked_sub(data_skip_count).unwrap();

		self.data.drain(0..drain_count);
		self.data.extend(append_data.into_iter().take(COUNT).skip(data_skip_count));

		debug_assert!(!self.data.spilled());
	}

	pub fn get(
		&self,
		idx: usize,
	) -> Option<&T> {
		debug_assert!(idx < COUNT);
		self.data.get(idx)
	}

	pub fn iter(
		&self,
	) -> impl Iterator<Item = &T> {
		self.data.iter()
	}

	pub fn iter_rev(
		&self,
	) -> impl Iterator<Item = &T> + use<'_, COUNT, IS, AggregationData, T> {
		self.data.iter().rev()
	}

	pub fn forward_slice_from<P: FnMut(&T) -> bool>(
		&'aggregated_data self,
		exclude: P,
	) -> &'aggregated_data [T] {
		let Some(
			idx,
		) = self.data.iter().rev().position(exclude) else {
			return &self.data;
		};

		let idx = idx + 1;

		if idx >= self.data.len() {
			return &self.data;
		}

		&self.data[idx..]
	}

	pub fn forward_slice(
		&'aggregated_data self,
	) -> &'aggregated_data [T] {
		&self.data
	}
}