apple-quant-algorithmic 0.1.0

Apple Quant's algorithmic trading api
Documentation
use std::ops::{Add, AddAssign, Sub};

use bevy::prelude::Deref;
use num_traits::{Signed, Zero};
use rust_decimal::Decimal;
use thiserror::Error;

use crate::instrument::{AsDecimal, InstrumentSpec};

#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DirectionlessVolume<IS: InstrumentSpec>(IS::VolumeType);

impl<IS: InstrumentSpec> DirectionlessVolume<IS> {
	pub fn new_unchecked(volume: IS::VolumeType) -> Self {
		Self(volume)
	}

	pub fn new_checked(volume: IS::VolumeType) -> Result<Self, ()> {
		if volume.is_negative() || volume.is_zero() {
			return Err(());
		}

		Ok(Self(volume))
	}
}

impl<IS: InstrumentSpec> Add for DirectionlessVolume<IS> {
	type Output = Self;

	fn add(
		self,
		rhs: Self,
	) -> Self::Output {
		Self(self.0 + rhs.0)
	}
}

impl<IS: InstrumentSpec> Add for &DirectionlessVolume<IS> {
	type Output = DirectionlessVolume<IS>;

	fn add(
		self,
		rhs: Self,
	) -> Self::Output {
		DirectionlessVolume::<IS>(self.0 + rhs.0)
	}
}

impl<IS: InstrumentSpec> AddAssign for DirectionlessVolume<IS> {
	fn add_assign(
		&mut self,
		rhs: Self,
	) {
		self.0 += rhs.0;
	}
}

#[derive(Debug, Error)]
pub enum DirectionlessVolumeSubError {
	#[error("Can not have negative directionless volume. Attemped to subtract: {lhs} - {rhs}.")]
	NegativeVolume { lhs: Decimal, rhs: Decimal },
}

impl<IS: InstrumentSpec> Sub for DirectionlessVolume<IS> {
	type Output = Result<Option<Self>, DirectionlessVolumeSubError>;

	fn sub(
		self,
		rhs: Self,
	) -> Self::Output {
		if self.0 == rhs.0 {
			return Ok(None);
		}

		if self.0 < rhs.0 {
			return Err(
				DirectionlessVolumeSubError::NegativeVolume {
					lhs: self.as_decimal(),
					rhs: rhs.as_decimal(),
				},
			);
		}

		Ok(Some(Self(self.0 - rhs.0)))
	}
}