use smallvec::SmallVec;
use thiserror::Error;
use crate::{
backend::{
LocalOrderId, OrderIdError, OrdersBackend, OrdersBackendSubmitRemoteOrderError,
RemoteOrderId,
},
instrument::InstrumentSpec,
order::{
DeferredOrderActions, DesiredVolumeOrder, DesiredVolumeOrderError, OrderGoal, RemoteOrder,
RemoteOrderTracker, RemoteTimingCondition, TriggerError,
dependency::remote::RemoteOrderAction,
},
price::AbsolutePrice,
timestamp::{TickTimestamp, Timestamp},
volume::{DirectionalExposure, DirectionalIntentVolume},
};
use super::{
OrdersCapacitySpec, PendingClientCancelError, WorkingRemoteOrderSubmitError,
WorkingRemoteOrders,
};
#[derive(Debug, Error)]
pub enum PendingRemoteSubmitError {
#[error("{0:?}")]
DesiredVolumeOrder(#[from] DesiredVolumeOrderError),
#[error("{0:?}")]
OrdersBackendSubmitRemoteOrder(#[from] OrdersBackendSubmitRemoteOrderError),
}
#[derive(Debug, Error)]
pub enum PendingRemoteProcessedError {
#[error("{0:?}")]
OrderId(#[from] OrderIdError),
#[error("{0:?}")]
PendingClientCancel(#[from] PendingClientCancelError),
#[error("{0:?}")]
WorkingRemoteOrderSubmit(#[from] WorkingRemoteOrderSubmitError),
#[error("{0:?}")]
Trigger(#[from] TriggerError),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PendingRemoteOrder<IS: InstrumentSpec, CS: OrdersCapacitySpec> {
pub(crate) submission_timestamp: Timestamp,
pub(crate) local_order_id: LocalOrderId,
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) rest_at: Option<AbsolutePrice<IS>>,
}
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> PendingRemoteOrder<IS, CS> {
pub(crate) fn new(
submission_timestamp: Timestamp,
local_order_id: LocalOrderId,
dependencies: impl IntoIterator<
Item = (
RemoteTimingCondition,
RemoteOrderAction<IS>,
),
>,
order_goal: OrderGoal<IS>,
desired_directional_intent_volume: DirectionalIntentVolume<IS>,
rest_at: Option<AbsolutePrice<IS>>,
) -> Self {
Self {
submission_timestamp,
local_order_id,
dependencies: dependencies
.into_iter()
.collect(),
order_goal,
desired_directional_intent_volume,
rest_at,
}
}
}
#[derive(Debug)]
pub struct PendingRemoteOrders<IS: InstrumentSpec, CS: OrdersCapacitySpec>(
SmallVec<[PendingRemoteOrder<IS, CS>; CS::PENDING_REMOTE]>,
);
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> PendingRemoteOrders<IS, CS> {
pub async fn submit<OB: OrdersBackend<IS>>(
&mut self,
directional_exposure: &mut DirectionalExposure<IS>,
orders_backend: &mut OB,
tick_timestamp: &TickTimestamp,
remote_order_tracker: RemoteOrderTracker<IS>,
remote_order: RemoteOrder<IS>,
dependencies: impl IntoIterator<
Item = (
RemoteTimingCondition,
RemoteOrderAction<IS>,
),
>,
) -> Result<(), PendingRemoteSubmitError>
where
IS: Send,
{
let submission_timestamp = tick_timestamp.timestamp();
let local_order_id = *remote_order_tracker.as_local_order_id();
let order_goal = *remote_order_tracker.as_order_goal();
let desired_directional_intent_volume = remote_order.desired_directional_intent_volume()?;
let rest_at = if let RemoteOrder::Limit(limit_order) = &remote_order {
Some(
limit_order
.price
.into_absolute()
.unwrap(),
)
} else {
None
};
orders_backend
.submit_order(
&local_order_id,
&submission_timestamp,
remote_order,
)
.await?;
let pending_remote_order = PendingRemoteOrder::new(
submission_timestamp,
local_order_id,
dependencies,
order_goal,
desired_directional_intent_volume,
rest_at,
);
self.0
.push(pending_remote_order);
directional_exposure
.change_armed_directional_exposure(&desired_directional_intent_volume.as_zeroable());
Ok(())
}
pub fn get(
&self,
local_order_id: &LocalOrderId,
) -> Result<&PendingRemoteOrder<IS, CS>, OrderIdError> {
let Some(pending_remote_order) = self
.0
.iter()
.find(|pending_remote_order| &pending_remote_order.local_order_id == local_order_id)
else {
return local_order_id.err_invalid();
};
Ok(pending_remote_order)
}
pub(crate) fn get_mut(
&mut self,
local_order_id: &LocalOrderId,
) -> Result<&mut PendingRemoteOrder<IS, CS>, OrderIdError> {
let Some(pending_remote_order) = self
.0
.iter_mut()
.find(|pending_remote_order| &pending_remote_order.local_order_id == local_order_id)
else {
return local_order_id.err_invalid();
};
Ok(pending_remote_order)
}
pub(crate) fn remove(
&mut self,
directional_exposure: &mut DirectionalExposure<IS>,
local_order_id: &LocalOrderId,
) -> Result<PendingRemoteOrder<IS, CS>, PendingClientCancelError> {
let Some(idx) = self
.0
.iter()
.position(|pending_remote_order| {
&pending_remote_order.local_order_id == local_order_id
})
else {
return local_order_id.err_invalid();
};
let pending_remote_order = self.0.swap_remove(idx);
let desired_directional_intent_volume =
&pending_remote_order.desired_directional_intent_volume;
directional_exposure.change_armed_directional_exposure(
&desired_directional_intent_volume
.as_zeroable()
.as_flipped(),
);
Ok(pending_remote_order)
}
pub(crate) async fn acknowledged<OB: OrdersBackend<IS>>(
&mut self,
tick_timestamp: &TickTimestamp,
working_remote_orders: &mut WorkingRemoteOrders<IS, CS>,
directional_exposure: &mut DirectionalExposure<IS>,
deferred_order_actions: &mut DeferredOrderActions<IS>,
local_order_id: &LocalOrderId,
remote_order_id: RemoteOrderId,
) -> Result<(), PendingRemoteProcessedError>
where
IS: Send,
{
let mut pending_remote_order = self.remove(
directional_exposure,
local_order_id,
)?;
for (remote_timing_condition, remote_order_action) in pending_remote_order
.dependencies
.iter_mut()
{
if remote_timing_condition != &RemoteTimingCondition::Acknowledged {
continue;
}
deferred_order_actions.push(
remote_order_action
.clone()
.into_order_action(),
);
}
working_remote_orders.submit::<OB>(
directional_exposure,
tick_timestamp,
pending_remote_order,
remote_order_id,
)?;
Ok(())
}
}
impl<IS: InstrumentSpec, CS: OrdersCapacitySpec> Default for PendingRemoteOrders<IS, CS> {
fn default() -> Self {
Self(SmallVec::default())
}
}