use nautilus_model::{
enums::{OrderSide, OrderType, TimeInForce, TriggerType},
identifiers::{ClientOrderId, InstrumentId, StrategyId},
orders::{Order, OrderAny},
types::{Price, Quantity},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrderIdentity {
pub client_order_id: ClientOrderId,
pub strategy_id: StrategyId,
pub instrument_id: InstrumentId,
pub order_side: OrderSide,
pub order_type: OrderType,
}
impl From<&OrderAny> for OrderIdentity {
fn from(order: &OrderAny) -> Self {
Self {
client_order_id: order.client_order_id(),
strategy_id: order.strategy_id(),
instrument_id: order.instrument_id(),
order_side: order.order_side(),
order_type: order.order_type(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrderContext {
pub identity: OrderIdentity,
pub quantity: Quantity,
pub price: Option<Price>,
pub trigger_price: Option<Price>,
pub trigger_type: Option<TriggerType>,
pub time_in_force: TimeInForce,
pub is_post_only: bool,
pub is_reduce_only: bool,
pub is_quote_quantity: bool,
}
impl From<&OrderAny> for OrderContext {
fn from(order: &OrderAny) -> Self {
Self {
identity: OrderIdentity::from(order),
quantity: order.quantity(),
price: order.price(),
trigger_price: order.trigger_price(),
trigger_type: order.trigger_type(),
time_in_force: order.time_in_force(),
is_post_only: order.is_post_only(),
is_reduce_only: order.is_reduce_only(),
is_quote_quantity: order.is_quote_quantity(),
}
}
}
#[cfg(test)]
mod tests {
use nautilus_model::{
enums::{OrderSide, OrderType, TimeInForce, TriggerType},
identifiers::{ClientOrderId, InstrumentId, StrategyId},
orders::{OrderAny, OrderTestBuilder},
types::{Price, Quantity},
};
use rstest::rstest;
use super::{OrderContext, OrderIdentity};
#[rstest]
fn test_order_identity_from_order() {
let order = test_order(false, false, false);
let identity = OrderIdentity::from(&order);
assert_eq!(
identity,
OrderIdentity {
client_order_id: ClientOrderId::from("O-CONTEXT-001"),
strategy_id: StrategyId::from("S-CONTEXT-002"),
instrument_id: InstrumentId::from("ETH-USDT-PERP.TEST"),
order_side: OrderSide::Sell,
order_type: OrderType::StopLimit,
}
);
}
#[rstest]
#[case(true, false, false)]
#[case(false, true, false)]
#[case(false, false, true)]
fn test_order_context_from_order(
#[case] is_post_only: bool,
#[case] is_reduce_only: bool,
#[case] is_quote_quantity: bool,
) {
let order = test_order(is_post_only, is_reduce_only, is_quote_quantity);
let context = OrderContext::from(&order);
assert_eq!(
context,
OrderContext {
identity: OrderIdentity {
client_order_id: ClientOrderId::from("O-CONTEXT-001"),
strategy_id: StrategyId::from("S-CONTEXT-002"),
instrument_id: InstrumentId::from("ETH-USDT-PERP.TEST"),
order_side: OrderSide::Sell,
order_type: OrderType::StopLimit,
},
quantity: Quantity::from("12.345"),
price: Some(Price::from("2345.67")),
trigger_price: Some(Price::from("2301.23")),
trigger_type: Some(TriggerType::MarkPrice),
time_in_force: TimeInForce::Day,
is_post_only,
is_reduce_only,
is_quote_quantity,
}
);
}
fn test_order(is_post_only: bool, is_reduce_only: bool, is_quote_quantity: bool) -> OrderAny {
OrderTestBuilder::new(OrderType::StopLimit)
.client_order_id(ClientOrderId::from("O-CONTEXT-001"))
.strategy_id(StrategyId::from("S-CONTEXT-002"))
.instrument_id(InstrumentId::from("ETH-USDT-PERP.TEST"))
.side(OrderSide::Sell)
.quantity(Quantity::from("12.345"))
.price(Price::from("2345.67"))
.trigger_price(Price::from("2301.23"))
.trigger_type(TriggerType::MarkPrice)
.time_in_force(TimeInForce::Day)
.post_only(is_post_only)
.reduce_only(is_reduce_only)
.quote_quantity(is_quote_quantity)
.build()
}
}