use std::time::{Duration, Instant};
use crate::client::ids::OrderId;
use crate::orders::{OrderData, OrderOutcome, OrderStatus, OrderStatusKind, Orders};
use crate::Error;
pub(crate) const LOOKUP_MIN_WAIT: Duration = Duration::from_secs(1);
pub(crate) fn lookup_wait(deadline: Instant) -> Duration {
deadline.saturating_duration_since(Instant::now()).max(LOOKUP_MIN_WAIT)
}
pub(crate) fn lists_order(rows: &[Orders], order_id: OrderId) -> bool {
rows.iter().any(|row| match row {
Orders::OrderData(data) => data.order.order_id == order_id.value(),
Orders::OrderStatus(status) => status.order_id == order_id.value(),
})
}
pub(crate) fn completed_status(rows: &[Orders], client_id: i32, order_id: OrderId) -> Option<OrderStatus> {
rows.iter().rev().find_map(|row| match row {
Orders::OrderData(data) if data.order.client_id == client_id && data.order.order_id == order_id.value() => Some(status_of_completed(data)),
_ => None,
})
}
fn status_of_completed(data: &OrderData) -> OrderStatus {
let order = &data.order;
OrderStatus {
order_id: order.order_id,
status: data.order_state.status.clone(),
filled: order.filled_quantity,
remaining: order.total_quantity,
average_fill_price: None,
perm_id: order.perm_id,
parent_id: order.parent_id,
last_fill_price: None,
client_id: order.client_id,
why_held: String::new(),
market_cap_price: None,
}
}
#[derive(Debug, Default)]
pub(crate) struct FillTracker {
last: Option<OrderStatus>,
}
impl FillTracker {
pub(crate) fn observe(&mut self, status: OrderStatus) -> Option<OrderOutcome> {
let outcome = status.outcome();
if outcome.is_none() {
self.last = Some(status);
}
outcome
}
pub(crate) fn observe_completed(&mut self, status: OrderStatus) -> Option<OrderOutcome> {
if status.status == OrderStatusKind::Filled {
Some(OrderOutcome::Filled(status))
} else if status.status.is_terminal() {
Some(OrderOutcome::Ended(status))
} else {
self.last = Some(status);
None
}
}
pub(crate) fn error(error: Error) -> Result<OrderOutcome, Error> {
match error {
Error::Notice(notice) => Ok(OrderOutcome::Rejected(notice)),
error => Err(error),
}
}
pub(crate) fn timed_out(&mut self) -> OrderOutcome {
OrderOutcome::TimedOut(self.last.take())
}
}
#[cfg(test)]
#[path = "fill_tests.rs"]
mod tests;