nautilus_execution/reports/
order.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, UUID4};
19use nautilus_model::{
20    enums::{
21        ContingencyType, OrderSide, OrderStatus, OrderType, TimeInForce, TrailingOffsetType,
22        TriggerType,
23    },
24    identifiers::{AccountId, ClientOrderId, InstrumentId, OrderListId, PositionId, VenueOrderId},
25    types::{Price, Quantity},
26};
27use serde::{Deserialize, Serialize};
28
29/// Represents an order status at a point in time.
30#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
31#[serde(tag = "type")]
32#[cfg_attr(
33    feature = "python",
34    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.execution")
35)]
36pub struct OrderStatusReport {
37    /// The account ID associated with the position.
38    pub account_id: AccountId,
39    /// The instrument ID associated with the event.
40    pub instrument_id: InstrumentId,
41    /// The client order ID.
42    pub client_order_id: Option<ClientOrderId>,
43    /// The venue assigned order ID.
44    pub venue_order_id: VenueOrderId,
45    /// The order side.
46    pub order_side: OrderSide,
47    /// The order type.
48    pub order_type: OrderType,
49    /// The order time in force.
50    pub time_in_force: TimeInForce,
51    /// The order status.
52    pub order_status: OrderStatus,
53    /// The order quantity.
54    pub quantity: Quantity,
55    /// The order total filled quantity.
56    pub filled_qty: Quantity,
57    /// The unique identifier for the event.
58    pub report_id: UUID4,
59    /// UNIX timestamp (nanoseconds) when the order was accepted.
60    pub ts_accepted: UnixNanos,
61    /// UNIX timestamp (nanoseconds) when the last event occurred.
62    pub ts_last: UnixNanos,
63    /// UNIX timestamp (nanoseconds) when the event was initialized.
64    pub ts_init: UnixNanos,
65    /// The order list ID associated with the order.
66    pub order_list_id: Option<OrderListId>,
67    /// The position ID associated with the order (assigned by the venue).
68    pub venue_position_id: Option<PositionId>,
69    /// The orders contingency type.
70    pub contingency_type: ContingencyType,
71    /// The order expiration (UNIX epoch nanoseconds), zero for no expiration.
72    pub expire_time: Option<UnixNanos>,
73    /// The order price (LIMIT).
74    pub price: Option<Price>,
75    /// The order trigger price (STOP).
76    pub trigger_price: Option<Price>,
77    /// The trigger type for the order.
78    pub trigger_type: Option<TriggerType>,
79    /// The trailing offset for the orders limit price.
80    pub limit_offset: Option<Price>,
81    /// The trailing offset for the orders trigger price (STOP).
82    pub trailing_offset: Option<Price>,
83    /// The trailing offset type.
84    pub trailing_offset_type: TrailingOffsetType,
85    /// The order average fill price.
86    pub avg_px: Option<f64>,
87    /// The quantity of the `LIMIT` order to display on the public book (iceberg).
88    pub display_qty: Option<Quantity>,
89    /// If the order will only provide liquidity (make a market).
90    pub post_only: bool,
91    /// If the order carries the 'reduce-only' execution instruction.
92    pub reduce_only: bool,
93    /// The reason for order cancellation.
94    pub cancel_reason: Option<String>,
95    /// UNIX timestamp (nanoseconds) when the order was triggered.
96    pub ts_triggered: Option<UnixNanos>,
97}
98
99impl OrderStatusReport {
100    /// Creates a new [`OrderStatusReport`] instance with required fields.
101    #[allow(clippy::too_many_arguments)]
102    #[must_use]
103    pub fn new(
104        account_id: AccountId,
105        instrument_id: InstrumentId,
106        client_order_id: Option<ClientOrderId>,
107        venue_order_id: VenueOrderId,
108        order_side: OrderSide,
109        order_type: OrderType,
110        time_in_force: TimeInForce,
111        order_status: OrderStatus,
112        quantity: Quantity,
113        filled_qty: Quantity,
114        ts_accepted: UnixNanos,
115        ts_last: UnixNanos,
116        ts_init: UnixNanos,
117        report_id: Option<UUID4>,
118    ) -> Self {
119        Self {
120            account_id,
121            instrument_id,
122            client_order_id,
123            venue_order_id,
124            order_side,
125            order_type,
126            time_in_force,
127            order_status,
128            quantity,
129            filled_qty,
130            report_id: report_id.unwrap_or_default(),
131            ts_accepted,
132            ts_last,
133            ts_init,
134            order_list_id: None,
135            venue_position_id: None,
136            contingency_type: ContingencyType::default(),
137            expire_time: None,
138            price: None,
139            trigger_price: None,
140            trigger_type: None,
141            limit_offset: None,
142            trailing_offset: None,
143            trailing_offset_type: TrailingOffsetType::default(),
144            avg_px: None,
145            display_qty: None,
146            post_only: false,
147            reduce_only: false,
148            cancel_reason: None,
149            ts_triggered: None,
150        }
151    }
152
153    /// Sets the client order ID.
154    #[must_use]
155    pub const fn with_client_order_id(mut self, client_order_id: ClientOrderId) -> Self {
156        self.client_order_id = Some(client_order_id);
157        self
158    }
159
160    /// Sets the order list ID.
161    #[must_use]
162    pub const fn with_order_list_id(mut self, order_list_id: OrderListId) -> Self {
163        self.order_list_id = Some(order_list_id);
164        self
165    }
166
167    /// Sets the venue position ID.
168    #[must_use]
169    pub const fn with_venue_position_id(mut self, venue_position_id: PositionId) -> Self {
170        self.venue_position_id = Some(venue_position_id);
171        self
172    }
173
174    /// Sets the price.
175    #[must_use]
176    pub const fn with_price(mut self, price: Price) -> Self {
177        self.price = Some(price);
178        self
179    }
180
181    /// Sets the average price.
182    #[must_use]
183    pub const fn with_avg_px(mut self, avg_px: f64) -> Self {
184        self.avg_px = Some(avg_px);
185        self
186    }
187
188    /// Sets the trigger price.
189    #[must_use]
190    pub const fn with_trigger_price(mut self, trigger_price: Price) -> Self {
191        self.trigger_price = Some(trigger_price);
192        self
193    }
194
195    /// Sets the trigger type.
196    #[must_use]
197    pub const fn with_trigger_type(mut self, trigger_type: TriggerType) -> Self {
198        self.trigger_type = Some(trigger_type);
199        self
200    }
201
202    /// Sets the limit offset.
203    #[must_use]
204    pub const fn with_limit_offset(mut self, limit_offset: Price) -> Self {
205        self.limit_offset = Some(limit_offset);
206        self
207    }
208
209    /// Sets the trailing offset.
210    #[must_use]
211    pub const fn with_trailing_offset(mut self, trailing_offset: Price) -> Self {
212        self.trailing_offset = Some(trailing_offset);
213        self
214    }
215
216    /// Sets the trailing offset type.
217    #[must_use]
218    pub const fn with_trailing_offset_type(
219        mut self,
220        trailing_offset_type: TrailingOffsetType,
221    ) -> Self {
222        self.trailing_offset_type = trailing_offset_type;
223        self
224    }
225
226    /// Sets the display quantity.
227    #[must_use]
228    pub const fn with_display_qty(mut self, display_qty: Quantity) -> Self {
229        self.display_qty = Some(display_qty);
230        self
231    }
232
233    /// Sets the expire time.
234    #[must_use]
235    pub const fn with_expire_time(mut self, expire_time: UnixNanos) -> Self {
236        self.expire_time = Some(expire_time);
237        self
238    }
239
240    /// Sets `post_only` flag.
241    #[must_use]
242    pub const fn with_post_only(mut self, post_only: bool) -> Self {
243        self.post_only = post_only;
244        self
245    }
246
247    /// Sets `reduce_only` flag.
248    #[must_use]
249    pub const fn with_reduce_only(mut self, reduce_only: bool) -> Self {
250        self.reduce_only = reduce_only;
251        self
252    }
253
254    /// Sets cancel reason.
255    #[must_use]
256    pub fn with_cancel_reason(mut self, cancel_reason: &str) -> Self {
257        self.cancel_reason = Some(cancel_reason.to_string());
258        self
259    }
260
261    /// Sets the triggered timestamp.
262    #[must_use]
263    pub const fn with_ts_triggered(mut self, ts_triggered: UnixNanos) -> Self {
264        self.ts_triggered = Some(ts_triggered);
265        self
266    }
267
268    /// Sets the contingency type.
269    #[must_use]
270    pub const fn with_contingency_type(mut self, contingency_type: ContingencyType) -> Self {
271        self.contingency_type = contingency_type;
272        self
273    }
274}
275
276impl Display for OrderStatusReport {
277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278        write!(
279            f,
280            "OrderStatusReport(\
281                account_id={}, \
282                instrument_id={}, \
283                venue_order_id={}, \
284                order_side={}, \
285                order_type={}, \
286                time_in_force={}, \
287                order_status={}, \
288                quantity={}, \
289                filled_qty={}, \
290                report_id={}, \
291                ts_accepted={}, \
292                ts_last={}, \
293                ts_init={}, \
294                client_order_id={:?}, \
295                order_list_id={:?}, \
296                venue_position_id={:?}, \
297                contingency_type={}, \
298                expire_time={:?}, \
299                price={:?}, \
300                trigger_price={:?}, \
301                trigger_type={:?}, \
302                limit_offset={:?}, \
303                trailing_offset={:?}, \
304                trailing_offset_type={}, \
305                avg_px={:?}, \
306                display_qty={:?}, \
307                post_only={}, \
308                reduce_only={}, \
309                cancel_reason={:?}, \
310                ts_triggered={:?}\
311            )",
312            self.account_id,
313            self.instrument_id,
314            self.venue_order_id,
315            self.order_side,
316            self.order_type,
317            self.time_in_force,
318            self.order_status,
319            self.quantity,
320            self.filled_qty,
321            self.report_id,
322            self.ts_accepted,
323            self.ts_last,
324            self.ts_init,
325            self.client_order_id,
326            self.order_list_id,
327            self.venue_position_id,
328            self.contingency_type,
329            self.expire_time,
330            self.price,
331            self.trigger_price,
332            self.trigger_type,
333            self.limit_offset,
334            self.trailing_offset,
335            self.trailing_offset_type,
336            self.avg_px,
337            self.display_qty,
338            self.post_only,
339            self.reduce_only,
340            self.cancel_reason,
341            self.ts_triggered,
342        )
343    }
344}