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
}
}
}
}
}