nautilus_model/orders/
list.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::fmt::Display;
17
18use nautilus_core::{UnixNanos, correctness::check_slice_not_empty};
19use serde::{Deserialize, Serialize};
20
21use super::any::OrderAny;
22use crate::identifiers::{InstrumentId, OrderListId, StrategyId};
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25#[cfg_attr(
26    feature = "python",
27    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
28)]
29pub struct OrderList {
30    pub id: OrderListId,
31    pub instrument_id: InstrumentId,
32    pub strategy_id: StrategyId,
33    pub orders: Vec<OrderAny>,
34    pub ts_init: UnixNanos,
35}
36
37impl OrderList {
38    /// Creates a new [`OrderList`] instance.
39    pub fn new(
40        order_list_id: OrderListId,
41        instrument_id: InstrumentId,
42        strategy_id: StrategyId,
43        orders: Vec<OrderAny>,
44        ts_init: UnixNanos,
45    ) -> Self {
46        check_slice_not_empty(orders.as_slice(), stringify!(orders)).unwrap();
47        for order in &orders {
48            assert_eq!(instrument_id, order.instrument_id());
49            assert_eq!(strategy_id, order.strategy_id());
50        }
51        Self {
52            id: order_list_id,
53            instrument_id,
54            strategy_id,
55            orders,
56            ts_init,
57        }
58    }
59}
60
61impl PartialEq for OrderList {
62    fn eq(&self, other: &Self) -> bool {
63        self.id == other.id
64    }
65}
66
67impl Display for OrderList {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(
70            f,
71            "OrderList(\
72            id={}, \
73            instrument_id={}, \
74            strategy_id={}, \
75            orders={:?}, \
76            ts_init={}\
77            )",
78            self.id, self.instrument_id, self.strategy_id, self.orders, self.ts_init,
79        )
80    }
81}
82
83////////////////////////////////////////////////////////////////////////////////
84// Tests
85////////////////////////////////////////////////////////////////////////////////
86#[cfg(test)]
87mod tests {
88    use rstest::rstest;
89
90    use super::*;
91    use crate::{
92        enums::{OrderSide, OrderType},
93        identifiers::{OrderListId, StrategyId},
94        instruments::{CurrencyPair, stubs::*},
95        orders::OrderTestBuilder,
96        types::{Price, Quantity},
97    };
98
99    #[rstest]
100    fn test_new_and_display(audusd_sim: CurrencyPair) {
101        let order1 = OrderTestBuilder::new(OrderType::Limit)
102            .instrument_id(audusd_sim.id)
103            .side(OrderSide::Buy)
104            .price(Price::from("1.00000"))
105            .quantity(Quantity::from(100_000))
106            .build();
107        let order2 = OrderTestBuilder::new(OrderType::Limit)
108            .instrument_id(audusd_sim.id)
109            .side(OrderSide::Buy)
110            .price(Price::from("1.00000"))
111            .quantity(Quantity::from(100_000))
112            .build();
113        let order3 = OrderTestBuilder::new(OrderType::Limit)
114            .instrument_id(audusd_sim.id)
115            .side(OrderSide::Buy)
116            .price(Price::from("1.00000"))
117            .quantity(Quantity::from(100_000))
118            .build();
119
120        let orders = vec![order1, order2, order3];
121
122        let order_list = OrderList::new(
123            OrderListId::from("OL-001"),
124            audusd_sim.id,
125            StrategyId::default(),
126            orders,
127            UnixNanos::default(),
128        );
129
130        assert!(order_list.to_string().starts_with(
131            "OrderList(id=OL-001, instrument_id=AUD/USD.SIM, strategy_id=S-001, orders="
132        ));
133    }
134}