apple-quant-algorithmic 0.2.0

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

use bevy::prelude::Deref;

use num_traits::FromPrimitive;
use rust_decimal::Decimal;

use crate::instrument::{AddDecimal, AsDecimal, FromDecimal, InstrumentSpec, SubDecimal, XSpec};

mod corrected;
mod ladder;
mod price_type;

pub use corrected::*;
pub use ladder::*;
pub use price_type::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Price<IS: InstrumentSpec> {
	Absolute(AbsolutePrice<IS>),
	Relative(RelativePrice<IS>),
}

impl<IS: InstrumentSpec> Price<IS> {
	pub fn as_absolute(&self) -> Option<&AbsolutePrice<IS>> {
		self.into()
	}

	pub fn into_absolute(self) -> Option<AbsolutePrice<IS>> {
		self.into()
	}

	pub fn as_relative(&self) -> Option<&RelativePrice<IS>> {
		self.into()
	}

	pub fn into_relative(self) -> Option<RelativePrice<IS>> {
		self.into()
	}
}

impl<IS: InstrumentSpec> From<AbsolutePrice<IS>> for Price<IS> {
	fn from(value: AbsolutePrice<IS>) -> Self {
		Self::Absolute(value)
	}
}

impl<IS: InstrumentSpec> From<&AbsolutePrice<IS>> for Price<IS> {
	fn from(value: &AbsolutePrice<IS>) -> Self {
		(*value).into()
	}
}

impl<IS: InstrumentSpec> From<RelativePrice<IS>> for Price<IS> {
	fn from(value: RelativePrice<IS>) -> Self {
		Self::Relative(value)
	}
}

impl<IS: InstrumentSpec> From<&RelativePrice<IS>> for Price<IS> {
	fn from(value: &RelativePrice<IS>) -> Self {
		(*value).into()
	}
}

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

impl<IS: InstrumentSpec> RelativePrice<IS> {
	pub fn new_from_tick_count(tick_count: i64) -> Self {
		let relative_price_type = Decimal::from_i64(tick_count).unwrap();
		let price_type = IS::PriceType::from_decimal(relative_price_type);

		Self(price_type)
	}

	pub fn as_price(&self) -> Price<IS> {
		self.into()
	}

	pub fn into_price(self) -> Price<IS> {
		self.into()
	}
}

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

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

impl<IS: InstrumentSpec> Sub for RelativePrice<IS> {
	type Output = Result<Self, ()>;

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

impl<IS: InstrumentSpec> From<Price<IS>> for Option<RelativePrice<IS>> {
	fn from(value: Price<IS>) -> Self {
		let Price::Relative(relative_price) = value else {
			return None;
		};

		Some(relative_price)
	}
}

impl<'a, IS: InstrumentSpec> From<&'a Price<IS>> for Option<&'a RelativePrice<IS>> {
	fn from(value: &'a Price<IS>) -> Self {
		let Price::Relative(relative_price) = value else {
			return None;
		};

		Some(relative_price)
	}
}

#[derive(Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct AbsolutePrice<IS: InstrumentSpec>(IS::PriceType);

impl<IS: InstrumentSpec> AbsolutePrice<IS> {
	pub fn new(price: IS::PriceType) -> Self {
		Self(price)
	}

	pub fn as_price(&self) -> Price<IS> {
		self.into()
	}

	pub fn into_price(self) -> Price<IS> {
		self.into()
	}

	pub fn as_decimal(&self) -> Decimal {
		self.0.as_decimal()
	}

	pub fn as_underlying(&self) -> IS::PriceType {
		self.0
	}

	pub fn with_const_level_offset<const TICK_OFFSET: i64>(mut self) -> Self {
		let decimal_offset = IS::PriceSpec::TICK_VALUE
			* Decimal::from_u64(IS::PriceSpec::TICKS_PER_POINT).unwrap()
			* Decimal::from_i64(TICK_OFFSET).unwrap();

		self.add_decimal(&decimal_offset);
		self
	}
}

impl<IS: InstrumentSpec> Display for AbsolutePrice<IS> {
	fn fmt(
		&self,
		f: &mut std::fmt::Formatter<'_>,
	) -> std::fmt::Result {
		let price = self.as_decimal();
		write!(f, "{}", price)
	}
}

impl<IS: InstrumentSpec> Debug for AbsolutePrice<IS> {
	fn fmt(
		&self,
		f: &mut std::fmt::Formatter<'_>,
	) -> std::fmt::Result {
		<Self as Display>::fmt(&self, f)
	}
}

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

	fn add(
		mut self,
		rhs: RelativePrice<IS>,
	) -> Self::Output {
		self.0 += rhs.0;
		self
	}
}

impl<IS: InstrumentSpec> AddDecimal for AbsolutePrice<IS> {
	fn add_decimal(
		&mut self,
		decimal: &Decimal,
	) {
		self.0.add_decimal(decimal);
	}
}

impl<IS: InstrumentSpec> SubDecimal for AbsolutePrice<IS> {
	fn sub_decimal(
		&mut self,
		decimal: &Decimal,
	) {
		self.0.sub_decimal(decimal);
	}
}

impl<IS: InstrumentSpec> From<Price<IS>> for Option<AbsolutePrice<IS>> {
	fn from(value: Price<IS>) -> Self {
		let Price::Absolute(absolute_price) = value else {
			return None;
		};

		Some(absolute_price)
	}
}

impl<'a, IS: InstrumentSpec> From<&'a Price<IS>> for Option<&'a AbsolutePrice<IS>> {
	fn from(value: &'a Price<IS>) -> Self {
		let Price::Absolute(absolute_price) = value else {
			return None;
		};

		Some(absolute_price)
	}
}