use super::OrderBook;
use crate::{OrderId, OrderKind, SequenceNumber, command::*, outcome::*};
impl OrderBook {
pub(super) fn execute_cancel(
&mut self,
sequence_number: SequenceNumber,
cmd: &CancelCmd,
) -> CommandOutcome {
let result = match &cmd.order_kind {
OrderKind::Limit => self.cancel_limit_order(sequence_number, cmd.order_id),
OrderKind::Pegged => self.cancel_pegged_order(cmd.order_id),
OrderKind::PriceConditional => self.cancel_price_conditional_order(cmd.order_id),
};
match result {
Ok(_) => CommandOutcome::Applied(CommandReport::Cancel),
Err(reason) => CommandOutcome::Rejected(reason),
}
}
fn cancel_limit_order(
&mut self,
sequence_number: SequenceNumber,
id: OrderId,
) -> Result<(), CommandFailure> {
self.remove_limit_order(sequence_number, id)
.ok_or(CommandFailure::OrderNotFound)?;
Ok(())
}
fn cancel_pegged_order(&mut self, id: OrderId) -> Result<(), CommandFailure> {
self.remove_pegged_order(id)
.ok_or(CommandFailure::OrderNotFound)?;
Ok(())
}
fn cancel_price_conditional_order(&mut self, id: OrderId) -> Result<(), CommandFailure> {
self.remove_price_conditional_order(id)
.ok_or(CommandFailure::OrderNotFound)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
fn cancel(
book: &mut OrderBook,
sequence_number: SequenceNumber,
order_id: OrderId,
order_kind: OrderKind,
) -> CommandOutcome {
book.execute_cancel(
sequence_number,
&CancelCmd {
order_id,
order_kind,
},
)
}
#[test]
fn cancel_limit_order_success() {
let mut book = OrderBook::new("TEST");
book.add_limit_order(
SequenceNumber(0),
OrderId(0),
LimitOrder::new(
Price(100),
QuantityPolicy::Standard {
quantity: Quantity(10),
},
OrderFlags::new(Side::Buy, false, TimeInForce::Gtc),
),
);
let outcome = cancel(&mut book, SequenceNumber(1), OrderId(0), OrderKind::Limit);
match outcome {
CommandOutcome::Applied(CommandReport::Cancel) => {}
other => panic!("expected applied cancel, got: {other:?}"),
}
assert!(!book.limit.orders.contains_key(&OrderId(0)));
assert!(!book.limit.bids.contains_key(&Price(100)));
}
#[test]
fn cancel_limit_order_not_found() {
let mut book = OrderBook::new("TEST");
let outcome = cancel(
&mut book,
SequenceNumber(1000),
OrderId(999),
OrderKind::Limit,
);
match outcome {
CommandOutcome::Rejected(CommandFailure::OrderNotFound) => {}
other => panic!("expected order not found, got: {other:?}"),
}
}
#[test]
fn cancel_pegged_order_success() {
let mut book = OrderBook::new("TEST");
book.add_pegged_order(
SequenceNumber(0),
OrderId(0),
PeggedOrder::new(
PegReference::Primary,
Quantity(10),
OrderFlags::new(Side::Buy, false, TimeInForce::Gtc),
),
);
let outcome = cancel(&mut book, SequenceNumber(1), OrderId(0), OrderKind::Pegged);
match outcome {
CommandOutcome::Applied(CommandReport::Cancel) => {}
other => panic!("expected applied cancel, got: {other:?}"),
}
assert!(!book.pegged.orders.contains_key(&OrderId(0)));
}
#[test]
fn cancel_pegged_order_not_found() {
let mut book = OrderBook::new("TEST");
let outcome = cancel(
&mut book,
SequenceNumber(1000),
OrderId(999),
OrderKind::Pegged,
);
match outcome {
CommandOutcome::Rejected(CommandFailure::OrderNotFound) => {}
other => panic!("expected order not found, got: {other:?}"),
}
}
#[test]
fn cancel_price_conditional_order_success() {
let mut book = OrderBook::new("TEST");
book.add_price_conditional_order(
SequenceNumber(0),
OrderId(0),
PriceConditionalOrder::new(
PriceCondition::new(Price(100), TriggerDirection::AtOrAbove),
TriggerOrder::Market(MarketOrder::new(Quantity(10), Side::Buy, false)),
),
);
let outcome = cancel(
&mut book,
SequenceNumber(1),
OrderId(0),
OrderKind::PriceConditional,
);
match outcome {
CommandOutcome::Applied(CommandReport::Cancel) => {}
other => panic!("expected applied cancel, got: {other:?}"),
}
assert!(!book.price_conditional.orders.contains_key(&OrderId(0)));
}
#[test]
fn cancel_price_conditional_order_not_found() {
let mut book = OrderBook::new("TEST");
let outcome = cancel(
&mut book,
SequenceNumber(1000),
OrderId(999),
OrderKind::PriceConditional,
);
match outcome {
CommandOutcome::Rejected(CommandFailure::OrderNotFound) => {}
other => panic!("expected order not found, got: {other:?}"),
}
}
#[test]
fn cancel_limit_order_with_wrong_kind_returns_not_found() {
let mut book = OrderBook::new("TEST");
book.add_limit_order(
SequenceNumber(0),
OrderId(0),
LimitOrder::new(
Price(100),
QuantityPolicy::Standard {
quantity: Quantity(10),
},
OrderFlags::new(Side::Buy, false, TimeInForce::Gtc),
),
);
let outcome = cancel(&mut book, SequenceNumber(1), OrderId(0), OrderKind::Pegged);
match outcome {
CommandOutcome::Rejected(CommandFailure::OrderNotFound) => {}
other => panic!("expected order not found, got: {other:?}"),
}
assert!(book.limit.orders.contains_key(&OrderId(0)));
}
}