apple-quant-algorithmic 0.4.0

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

use crate::{
	binned_method::{BinnedDataError, BinnedPoint, FlexBinnedData},
	timestamp::{Timestamp, Timestamped, TradeTimestamped},
	aggregation::Aggregator, instrument::InstrumentSpec,
};

/// Flex Binned - Flexible size; bins for each T.
/// Time Point - Each T is a point in time within each constant bin size via [`Timestamped`].
pub struct FlexBinnedTimePointData<
	'instrument_data,
	'aggregated_data,
	IS: InstrumentSpec,
	T: TradeTimestamped
		+ Aggregator<'instrument_data, 'aggregated_data, T, AggregatorData, IS>
		+ Ord
		+ 'aggregated_data,
	AggregatorData,
	const SECTOR_STRIDE_NS: u64,
> {
	flex_binned_data: FlexBinnedData<T>,
	_instrument_data: PhantomData<&'instrument_data ()>,
	_aggregated_data: PhantomData<&'aggregated_data ()>,
	_is: PhantomData<IS>,
	_aggregator_data: PhantomData<AggregatorData>,
}

impl<
	'instrument_data,
	'aggregated_data,
	IS: InstrumentSpec,
	T: TradeTimestamped
		+ Aggregator<'instrument_data, 'aggregated_data, T, AggregatorData, IS>
		+ Ord
		+ 'aggregated_data,
	AggregatorData,
	const SECTOR_STRIDE_NS: u64,
> BinnedPoint<T> for FlexBinnedTimePointData<
	'instrument_data,
	'aggregated_data,
	IS,
	T,
	AggregatorData,
	SECTOR_STRIDE_NS,
> {
	fn insert(
		&mut self,
		data: impl Iterator<Item = T>,
	) {
		for data in data {
			let sector_idx = *data.trade_timestamp().as_timestamp_type() as i128 /
				SECTOR_STRIDE_NS as i128;

			let sector_idx = sector_idx.cast_unsigned() as u64;

			self.flex_binned_data
				.insert_in_sector(
					sector_idx,
					[data].into_iter(),
				).unwrap();
		}
	}

	fn get<'a>(
		&'a self,
		timestamp: &Timestamp,
	) -> Result<impl Iterator<Item = &'a T>, BinnedDataError>
	where
		T: 'a,
	{
		let sector_idx = *timestamp.as_timestamp_type() as i128 /
			SECTOR_STRIDE_NS as i128;

		let sector_idx = sector_idx.cast_unsigned() as u64;
		let sector_data = self.flex_binned_data.get_sector(sector_idx)?;

		Ok(sector_data.iter().filter(move |t| {
			t.trade_timestamp().timestamp() == *timestamp
		}))
	}

	fn get_first(
		&self,
		timestamp: &Timestamp,
	) -> Result<Option<&T>, BinnedDataError> {
		let sector_idx = *timestamp.as_timestamp_type() as i128 /
			SECTOR_STRIDE_NS as i128;

		let sector_idx = sector_idx.cast_unsigned() as u64;
		let sector_data = self.flex_binned_data.get_sector(sector_idx)?;

		Ok(sector_data.iter().find(|t| t.trade_timestamp().timestamp() == *timestamp))
	}

	fn iter<'a>(
		&'a self,
		range: Range<&Timestamp>,
	) -> Result<impl Iterator<Item = &'a T>, BinnedDataError>
	where
		T: 'a,
	{
		let start_sector_idx = *range.start.as_timestamp_type() as i128 /
			SECTOR_STRIDE_NS as i128;

		let last_sector_idx = *range.end.as_timestamp_type() as i128 /
			SECTOR_STRIDE_NS as i128;

		debug_assert!(start_sector_idx <= last_sector_idx);

		let start_sector_idx = start_sector_idx.cast_unsigned() as u64;
		let last_sector_idx = last_sector_idx.cast_unsigned() as u64;

		self.flex_binned_data
			.iter(
				start_sector_idx,
				last_sector_idx,
				|t: &T| t.trade_timestamp().timestamp() >= *range.start,
				|t: &T| t.trade_timestamp().timestamp() < *range.end,
			)
			.map_err(|_| BinnedDataError::InternalError)
	}
}

impl<
	'instrument_data,
	'aggregated_data,
	IS: InstrumentSpec,
	T: TradeTimestamped
		+ Aggregator<'instrument_data, 'aggregated_data, T, AggregatorData, IS>
		+ Ord
		+ 'aggregated_data,
	AggregatorData,
	const SECTOR_STRIDE_NS: u64,
> Default for FlexBinnedTimePointData<
	'instrument_data,
	'aggregated_data,
	IS,
	T,
	AggregatorData,
	SECTOR_STRIDE_NS,
> {
	fn default() -> Self {
		Self {
			flex_binned_data: FlexBinnedData::default(),
			_instrument_data: PhantomData::default(),
			_aggregated_data: PhantomData::default(),
			_is: PhantomData::default(),
			_aggregator_data: PhantomData::default(),
		}
	}
}