apple-quant-algorithmic 0.1.0

Apple Quant's algorithmic trading api
Documentation
use num_traits::Signed;

use crate::{
	backend::OrderIdGenerator,
	instrument::InstrumentSpec,
	liquidity::LiquidityEstimation,
	price::{AbsolutePrice, BidAskPriceSpread, Price},
	volume::{
		AggressiveVolume, AggressorSide, DirectionalIntentVolume, DirectionlessVolume, RestingSide,
		RestingVolume,
	},
};

use super::{
	DesiredVolumeOrder, DesiredVolumeOrderError, MatchableOrder, OrderExecutionExpectation,
	OrderGoal, RemoteOrderTracker,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RemoteOrder<IS: InstrumentSpec> {
	Market(MarketOrder<IS>),
	Limit(LimitOrder<IS>),
}

impl<IS: InstrumentSpec> RemoteOrder<IS> {
	pub(crate) fn parent_processed(
		&mut self,
		bid_ask_price_spread: &BidAskPriceSpread<IS>,
	) {
		let Self::Limit(limit_order) = self else {
			return;
		};

		limit_order.parent_processed(bid_ask_price_spread);
	}

	pub fn as_order_execution_expectation(&self) -> OrderExecutionExpectation {
		match self {
			Self::Market(_) => OrderExecutionExpectation::Immediate,
			Self::Limit(limit_order) => limit_order.order_execution_expectation,
		}
	}

	pub fn register(
		&self,
		order_id_generator: &mut OrderIdGenerator,
	) -> Result<RemoteOrderTracker<IS>, DesiredVolumeOrderError>
	where
		IS: Send,
	{
		let local_order_id = order_id_generator.next_local_order_id();

		let directional_intent_volume = self.desired_directional_intent_volume()?;
		let order_execution_expectation = self.as_order_execution_expectation();

		let order_goal = OrderGoal::new_submit_remote_with_execution_expectation(
			local_order_id,
			directional_intent_volume,
			order_execution_expectation,
		);

		Ok(RemoteOrderTracker::new(
			order_goal,
		))
	}
}

impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for RemoteOrder<IS> {
	fn desired_directional_intent_volume(
		&self
	) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
		match self {
			Self::Market(market_order) => market_order.desired_directional_intent_volume(),
			Self::Limit(limit_order) => limit_order.desired_directional_intent_volume(),
		}
	}

	fn desired_directionless_volume(
		&self
	) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
		match self {
			Self::Market(market_order) => market_order.desired_directionless_volume(),
			Self::Limit(limit_order) => limit_order.desired_directionless_volume(),
		}
	}
}

impl<IS: InstrumentSpec> MatchableOrder<IS> for RemoteOrder<IS> {
	fn is_liquidable(
		&self,
		liquidity_estimation: &LiquidityEstimation<IS>,
	) -> Option<AbsolutePrice<IS>> {
		match self {
			Self::Market(market_order) => market_order.is_liquidable(liquidity_estimation),
			Self::Limit(limit_order) => limit_order.is_liquidable(liquidity_estimation),
		}
	}
}

impl<IS: InstrumentSpec> From<MarketOrder<IS>> for RemoteOrder<IS> {
	fn from(value: MarketOrder<IS>) -> Self {
		Self::Market(value)
	}
}

impl<IS: InstrumentSpec> From<LimitOrder<IS>> for RemoteOrder<IS> {
	fn from(value: LimitOrder<IS>) -> Self {
		Self::Limit(value)
	}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MarketOrder<IS: InstrumentSpec> {
	pub aggressive_volume: AggressiveVolume<IS>,
}

impl<IS: InstrumentSpec> MarketOrder<IS> {
	pub fn new(aggressive_volume: AggressiveVolume<IS>) -> Self {
		Self { aggressive_volume }
	}

	pub fn new_from_parts(
		directionless_volume: DirectionlessVolume<IS>,
		aggressor_side: AggressorSide,
	) -> Self {
		Self {
			aggressive_volume: AggressiveVolume {
				directionless_volume,
				aggressor_side,
			},
		}
	}

	pub fn into_remote(self) -> RemoteOrder<IS> {
		self.into()
	}
}

impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for MarketOrder<IS> {
	fn desired_directional_intent_volume(
		&self
	) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
		Ok(self
			.aggressive_volume
			.as_directional_intent_volume())
	}

	fn desired_directionless_volume(
		&self
	) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
		Ok(self
			.aggressive_volume
			.as_directionless_volume())
	}
}

impl<IS: InstrumentSpec> MatchableOrder<IS> for MarketOrder<IS> {
	fn is_liquidable(
		&self,
		liquidity_estimation: &LiquidityEstimation<IS>,
	) -> Option<AbsolutePrice<IS>> {
		let Some((bid_level, ask_level)) = liquidity_estimation.furthest_bid_ask() else {
			return None;
		};

		match self
			.aggressive_volume
			.aggressor_side()
		{
			AggressorSide::Bid => Some(bid_level.price),
			AggressorSide::Ask => Some(ask_level.price),
		}
	}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LimitOrder<IS: InstrumentSpec> {
	pub price: Price<IS>,
	pub resting_volume: RestingVolume<IS>,
	pub order_execution_expectation: OrderExecutionExpectation,
}

impl<IS: InstrumentSpec> LimitOrder<IS> {
	pub fn new(
		price: Price<IS>,
		resting_volume: RestingVolume<IS>,
		order_execution_expectation: OrderExecutionExpectation,
	) -> Self {
		Self {
			price,
			resting_volume,
			order_execution_expectation,
		}
	}

	pub(crate) fn parent_processed(
		&mut self,
		bid_ask_price_spread: &BidAskPriceSpread<IS>,
	) {
		let Price::Relative(relative_price) = &mut self.price else {
			return;
		};

		let absolute_price: AbsolutePrice<IS> = if relative_price.is_positive() {
			AbsolutePrice::new(*bid_ask_price_spread.ask_price + **relative_price)
		} else {
			AbsolutePrice::new(*bid_ask_price_spread.bid_price + **relative_price)
		};

		self.price = Price::Absolute(absolute_price);
	}

	pub fn into_remote(self) -> RemoteOrder<IS> {
		self.into()
	}
}

impl<IS: InstrumentSpec> DesiredVolumeOrder<IS> for LimitOrder<IS> {
	fn desired_directional_intent_volume(
		&self
	) -> Result<DirectionalIntentVolume<IS>, DesiredVolumeOrderError> {
		Ok(self
			.resting_volume
			.as_directional_intent_volume())
	}

	fn desired_directionless_volume(
		&self
	) -> Result<&DirectionlessVolume<IS>, DesiredVolumeOrderError> {
		Ok(self
			.resting_volume
			.as_directionless_volume())
	}
}

impl<IS: InstrumentSpec> MatchableOrder<IS> for LimitOrder<IS> {
	fn is_liquidable(
		&self,
		liquidity_estimation: &LiquidityEstimation<IS>,
	) -> Option<AbsolutePrice<IS>> {
		let Some((bid_level, ask_level)) = liquidity_estimation.furthest_bid_ask() else {
			return None;
		};

		match self
			.resting_volume
			.resting_side
		{
			RestingSide::Bid => {
				let Price::Absolute(absolute_price) = self.price else {
					return None;
				};

				if bid_level.price <= absolute_price {
					Some(bid_level.price)
				} else {
					None
				}
			}
			RestingSide::Ask => {
				let Price::Absolute(absolute_price) = self.price else {
					return None;
				};

				if ask_level.price >= absolute_price {
					Some(ask_level.price)
				} else {
					None
				}
			}
		}
	}
}