use smallvec::SmallVec;
use thiserror::Error;
use crate::{
backend::{LocalOrderId, OrderId, OrderIdError, OrdersBackend, RemoteOrderId},
instrument::InstrumentSpec,
order::{
DeferredOrderActions, DesiredVolumeOrderError, OrderGoal, PartialOrderFill,
RemoteTimingCondition, dependency::remote::RemoteOrderAction,
},
price::{AbsolutePrice, BidAskPriceSpread},
timestamp::{TickTimestamp, Timestamp},
volume::{
DirectionalExposure, DirectionalIntentVolume, DirectionlessVolume,
ZeroableDirectionalIntentVolume,
},
};
use super::{CompletedRemoteOrders, OrdersCapacitySpec, PendingRemoteOrder};
#[derive(Debug, Error)]
pub enum WorkingRemoteOrderSubmitError {
#[error("{0:?}")]
DesiredVolumeOrder(#[from] DesiredVolumeOrderError),
#[error("{0:?}")]
OrderId(#[from] OrderIdError),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WorkingRemoteOrder<IS: InstrumentSpec, CS: OrdersCapacitySpec> {
pub(crate) local_order_id: LocalOrderId,
pub(crate) remote_order_id: RemoteOrderId,
pub(crate) dependencies: SmallVec<
[(
RemoteTimingCondition,
RemoteOrderAction<IS>,
); CS::DEPENDENCY],
>,
pub(crate) order_goal: OrderGoal<IS>,
pub(crate) desired_directional_intent_volume: DirectionalIntentVolume<IS>,
pub(crate) booking_timestamp: Timestamp,
pub(crate) partial_order_fills: SmallVec<[PartialOrderFill<IS>; CS::PARTIAL_FILL]>,
pub(crate) armed_directional_exposure: ZeroableDirectionalIntentVolume<IS>,
pub(crate) effective_directional_exposure: ZeroableDirectionalIntentVolume<IS>,
pub(crate) rest_at: Option<AbsolutePrice<IS>>,
}
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> WorkingRemoteOrder<IS, CS> {
pub(crate) fn get_fully_filled(&self) -> Option<BidAskPriceSpread<IS>> {
let mut filled_volume = ZeroableDirectionalIntentVolume::ZERO;
let mut iter_partial_order_fills = self
.partial_order_fills
.iter();
let Some(mut bid_ask_price_spread) = iter_partial_order_fills
.next()
.map(|partial_order_fill| {
filled_volume += partial_order_fill
.directional_intent_volume
.as_zeroable();
BidAskPriceSpread {
ask_price: partial_order_fill.price,
bid_price: partial_order_fill.price,
}
})
else {
return None;
};
for partial_order_fill in iter_partial_order_fills {
filled_volume += partial_order_fill
.directional_intent_volume
.as_zeroable();
if partial_order_fill.price > bid_ask_price_spread.ask_price {
bid_ask_price_spread.ask_price = partial_order_fill.price;
}
if partial_order_fill.price < bid_ask_price_spread.bid_price {
bid_ask_price_spread.bid_price = partial_order_fill.price;
}
}
if filled_volume
< self
.desired_directional_intent_volume
.as_zeroable()
{
return None;
}
Some(bid_ask_price_spread)
}
pub(crate) fn modify_volume(
&mut self,
directional_exposure: &mut DirectionalExposure<IS>,
volume: &DirectionlessVolume<IS>,
) {
let Some(desired_volume_delta) = (self.desired_directional_intent_volume
- DirectionalIntentVolume {
directional_intent: self
.desired_directional_intent_volume
.directional_intent,
directionless_volume: *volume,
})
else {
return;
};
let desired_volume_delta = desired_volume_delta
.as_zeroable()
.as_flipped();
directional_exposure.change_armed_directional_exposure(&desired_volume_delta);
self.desired_directional_intent_volume
.directionless_volume = *volume;
self.armed_directional_exposure += desired_volume_delta;
if let Some(directional_intent_volume) = self
.armed_directional_exposure
.directional_intent_volume()
{
if directional_intent_volume.directional_intent
!= self
.desired_directional_intent_volume
.directional_intent
{
unimplemented!()
}
} else {
unimplemented!()
}
}
}
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> WorkingRemoteOrder<IS, CS> {
pub(crate) fn new(
local_order_id: LocalOrderId,
remote_order_id: RemoteOrderId,
dependencies: impl IntoIterator<
Item = (
RemoteTimingCondition,
RemoteOrderAction<IS>,
),
>,
order_goal: OrderGoal<IS>,
desired_directional_intent_volume: DirectionalIntentVolume<IS>,
booking_timestamp: Timestamp,
rest_at: Option<AbsolutePrice<IS>>,
) -> Self {
Self {
local_order_id,
remote_order_id,
dependencies: dependencies
.into_iter()
.collect(),
order_goal,
desired_directional_intent_volume,
booking_timestamp,
partial_order_fills: SmallVec::default(),
armed_directional_exposure: desired_directional_intent_volume.as_zeroable(),
effective_directional_exposure: ZeroableDirectionalIntentVolume::ZERO,
rest_at,
}
}
}
#[derive(Debug)]
pub struct WorkingRemoteOrders<IS: InstrumentSpec, CS: OrdersCapacitySpec>(
SmallVec<[WorkingRemoteOrder<IS, CS>; CS::WORKING_REMOTE]>,
);
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> WorkingRemoteOrders<IS, CS> {
pub(crate) fn submit<OB: OrdersBackend<IS>>(
&mut self,
directional_exposure: &mut DirectionalExposure<IS>,
tick_timestamp: &TickTimestamp,
pending_remote_order: PendingRemoteOrder<IS, CS>,
remote_order_id: RemoteOrderId,
) -> Result<(), WorkingRemoteOrderSubmitError>
where
IS: Send,
{
let PendingRemoteOrder {
submission_timestamp: _,
local_order_id,
dependencies,
order_goal,
desired_directional_intent_volume,
rest_at,
} = pending_remote_order;
let booking_timestamp = tick_timestamp.timestamp();
let working_remote_order = WorkingRemoteOrder::new(
local_order_id,
remote_order_id,
dependencies,
order_goal,
desired_directional_intent_volume,
booking_timestamp,
rest_at,
);
directional_exposure
.change_armed_directional_exposure(&working_remote_order.armed_directional_exposure);
self.0
.push(working_remote_order);
Ok(())
}
pub fn get(
&self,
order_id: impl Into<OrderId>,
) -> Result<&WorkingRemoteOrder<IS, CS>, OrderIdError> {
match &order_id.into() {
OrderId::Local(local_order_id) => self.get_with_local(local_order_id),
OrderId::Remote(remote_order_id) => self.get_with_remote(remote_order_id),
}
}
pub fn get_with_local(
&self,
local_order_id: &LocalOrderId,
) -> Result<&WorkingRemoteOrder<IS, CS>, OrderIdError> {
let Some(working_remote_order) = self
.0
.iter()
.find(|working_remote_order| &working_remote_order.local_order_id == local_order_id)
else {
return local_order_id.err_invalid();
};
Ok(working_remote_order)
}
pub fn get_with_remote(
&self,
remote_order_id: &RemoteOrderId,
) -> Result<&WorkingRemoteOrder<IS, CS>, OrderIdError> {
let Some(working_remote_order) = self
.0
.iter()
.find(|working_remote_order| &working_remote_order.remote_order_id == remote_order_id)
else {
return remote_order_id.err_invalid();
};
Ok(working_remote_order)
}
pub(crate) fn get_mut(
&mut self,
order_id: impl Into<OrderId>,
) -> Result<&mut WorkingRemoteOrder<IS, CS>, OrderIdError> {
match &order_id.into() {
OrderId::Local(local_order_id) => self.get_mut_with_local(local_order_id),
OrderId::Remote(remote_order_id) => self.get_mut_with_remote(remote_order_id),
}
}
pub(crate) fn get_mut_with_local(
&mut self,
local_order_id: &LocalOrderId,
) -> Result<&mut WorkingRemoteOrder<IS, CS>, OrderIdError> {
let Some(working_remote_order) = self
.0
.iter_mut()
.find(|working_remote_order| &working_remote_order.local_order_id == local_order_id)
else {
return local_order_id.err_invalid();
};
Ok(working_remote_order)
}
pub(crate) fn get_mut_with_remote(
&mut self,
remote_order_id: &RemoteOrderId,
) -> Result<&mut WorkingRemoteOrder<IS, CS>, OrderIdError> {
let Some(working_remote_order) = self
.0
.iter_mut()
.find(|working_remote_order| &working_remote_order.remote_order_id == remote_order_id)
else {
return remote_order_id.err_invalid();
};
Ok(working_remote_order)
}
pub(crate) fn remove(
&mut self,
directional_exposure: &mut DirectionalExposure<IS>,
order_id: impl Into<OrderId>,
) -> Result<WorkingRemoteOrder<IS, CS>, OrderIdError>
where
IS: Send,
{
let order_id = order_id.into();
let idx = match order_id {
OrderId::Local(local_order_id) => self
.0
.iter()
.position(|working_remote_order| {
working_remote_order.local_order_id == local_order_id
}),
OrderId::Remote(remote_order_id) => self
.0
.iter()
.position(|working_remote_order| {
working_remote_order.remote_order_id == remote_order_id
}),
};
let Some(idx) = idx else {
return order_id.err_invalid();
};
let mut working_remote_order = self.0.swap_remove(idx);
directional_exposure.change_armed_directional_exposure(
&working_remote_order
.armed_directional_exposure
.as_flipped(),
);
working_remote_order.armed_directional_exposure = ZeroableDirectionalIntentVolume::ZERO;
Ok(working_remote_order)
}
pub(crate) fn processed<OB: OrdersBackend<IS>>(
&mut self,
remote_order_id: &RemoteOrderId,
) -> Result<(), OrderIdError>
where
IS: Send,
{
let working_remote_order = self.get_mut_with_remote(remote_order_id)?;
let Some(rest_at) = &working_remote_order.rest_at else {
return Ok(());
};
let bid_ask_price_spread = BidAskPriceSpread {
ask_price: *rest_at,
bid_price: *rest_at,
};
for (_, remote_order_action) in working_remote_order
.dependencies
.iter_mut()
{
remote_order_action.parent_processed(&bid_ask_price_spread);
}
Ok(())
}
pub(crate) fn partial_fill<OB: OrdersBackend<IS>>(
&mut self,
tick_timestamp: &TickTimestamp,
completed_remote_orders: &mut CompletedRemoteOrders<IS, CS>,
deferred_order_actions: &mut DeferredOrderActions<IS>,
directional_exposure: &mut DirectionalExposure<IS>,
partial_order_fill: PartialOrderFill<IS>,
remote_order_id: &RemoteOrderId,
) -> Result<(), OrderIdError>
where
IS: Send,
{
let working_remote_order = self.get_mut_with_remote(remote_order_id)?;
working_remote_order.armed_directional_exposure -= partial_order_fill
.directional_intent_volume
.as_zeroable();
directional_exposure.change_armed_directional_exposure(
&partial_order_fill
.directional_intent_volume
.as_zeroable()
.as_flipped(),
);
working_remote_order.effective_directional_exposure += partial_order_fill
.directional_intent_volume
.as_zeroable();
directional_exposure.change_effective_directional_exposure(
&partial_order_fill
.directional_intent_volume
.as_zeroable(),
);
working_remote_order
.partial_order_fills
.push(partial_order_fill);
for (remote_timing_condition, remote_order_action) in working_remote_order
.dependencies
.iter()
{
if remote_timing_condition != &RemoteTimingCondition::PartialFill {
continue;
}
deferred_order_actions.push(
remote_order_action
.clone()
.into_order_action(),
);
}
let Some(bid_ask_price_spread) = working_remote_order.get_fully_filled() else {
return Ok(());
};
let mut working_remote_order = self.remove(
directional_exposure,
remote_order_id,
)?;
if working_remote_order
.rest_at
.is_none()
{
for (_, remote_order_action) in working_remote_order
.dependencies
.iter_mut()
{
remote_order_action.parent_processed(&bid_ask_price_spread);
}
}
for (remote_timing_condition, remote_order_action) in working_remote_order
.dependencies
.iter()
{
if remote_timing_condition != &RemoteTimingCondition::FullyFilled {
continue;
}
deferred_order_actions.push(
remote_order_action
.clone()
.into_order_action(),
);
}
completed_remote_orders.submit::<OB>(
tick_timestamp,
working_remote_order,
);
Ok(())
}
pub(crate) async fn modify_volume<OB: OrdersBackend<IS>>(
&mut self,
orders_backend: &mut OB,
directional_exposure: &mut DirectionalExposure<IS>,
local_order_id: &LocalOrderId,
volume: &DirectionlessVolume<IS>,
) -> Result<(), OrderIdError>
where
IS: Send,
{
let working_remote_order = self.get_mut_with_local(local_order_id)?;
working_remote_order.modify_volume(directional_exposure, volume);
orders_backend
.modify_order_volume(
&working_remote_order.remote_order_id,
volume,
)
.await;
Ok(())
}
}
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> Default for WorkingRemoteOrders<IS, CS> {
fn default() -> Self {
Self(SmallVec::default())
}
}