nautilus_model/events/position/closed.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 nautilus_core::{
17 nanos::{DurationNanos, UnixNanos},
18 UUID4,
19};
20
21use crate::{
22 enums::{OrderSide, PositionSide},
23 events::OrderFilled,
24 identifiers::{AccountId, ClientOrderId, InstrumentId, PositionId, StrategyId, TraderId},
25 position::Position,
26 types::{Currency, Money, Price, Quantity},
27};
28
29/// Represents an event where a position has been closed.
30#[repr(C)]
31#[derive(Clone, PartialEq, Debug)]
32pub struct PositionClosed {
33 /// The trader ID associated with the event.
34 pub trader_id: TraderId,
35 /// The strategy ID associated with the event.
36 pub strategy_id: StrategyId,
37 /// The instrument ID associated with the event.
38 pub instrument_id: InstrumentId,
39 /// The position ID associated with the event.
40 pub position_id: PositionId,
41 /// The account ID associated with the position.
42 pub account_id: AccountId,
43 /// The client order ID for the order which opened the position.
44 pub opening_order_id: ClientOrderId,
45 /// The client order ID for the order which closed the position.
46 pub closing_order_id: Option<ClientOrderId>,
47 /// The position entry order side.
48 pub entry: OrderSide,
49 /// The position side.
50 pub side: PositionSide,
51 /// The current signed quantity (positive for position side `LONG`, negative for `SHORT`).
52 pub signed_qty: f64,
53 /// The current open quantity.
54 pub quantity: Quantity,
55 /// The peak directional quantity reached by the position.
56 pub peak_quantity: Quantity,
57 /// The last fill quantity for the position.
58 pub last_qty: Quantity,
59 /// The last fill price for the position.
60 pub last_px: Price,
61 /// The position quote currency.
62 pub currency: Currency,
63 /// The average open price.
64 pub avg_px_open: f64,
65 /// The average closing price.
66 pub avg_px_close: Option<f64>,
67 /// The realized return for the position.
68 pub realized_return: f64,
69 /// The realized PnL for the position (including commissions).
70 pub realized_pnl: Option<Money>,
71 /// The unrealized PnL for the position (including commissions).
72 pub unrealized_pnl: Money,
73 /// The total open duration (nanoseconds).
74 pub duration: DurationNanos,
75 /// The unique identifier for the event.
76 pub event_id: UUID4,
77 /// UNIX timestamp (nanoseconds) when the position was opened.
78 pub ts_opened: UnixNanos,
79 /// UNIX timestamp (nanoseconds) when the position was closed.
80 pub ts_closed: Option<UnixNanos>,
81 /// UNIX timestamp (nanoseconds) when the event occurred.
82 pub ts_event: UnixNanos,
83 /// UNIX timestamp (nanoseconds) when the event was initialized.
84 pub ts_init: UnixNanos,
85}
86
87impl PositionClosed {
88 pub fn create(
89 position: &Position,
90 fill: &OrderFilled,
91 event_id: UUID4,
92 ts_init: UnixNanos,
93 ) -> PositionClosed {
94 PositionClosed {
95 trader_id: position.trader_id,
96 strategy_id: position.strategy_id,
97 instrument_id: position.instrument_id,
98 position_id: position.id,
99 account_id: position.account_id,
100 opening_order_id: position.opening_order_id,
101 closing_order_id: position.closing_order_id,
102 entry: position.entry,
103 side: position.side,
104 signed_qty: position.signed_qty,
105 quantity: position.quantity,
106 peak_quantity: position.peak_qty,
107 last_qty: fill.last_qty,
108 last_px: fill.last_px,
109 currency: position.quote_currency,
110 avg_px_open: position.avg_px_open,
111 avg_px_close: position.avg_px_close,
112 realized_return: position.realized_return,
113 realized_pnl: position.realized_pnl,
114 unrealized_pnl: Money::new(0.0, position.quote_currency),
115 duration: position.duration_ns,
116 event_id,
117 ts_opened: position.ts_opened,
118 ts_closed: position.ts_closed,
119 ts_event: fill.ts_event,
120 ts_init,
121 }
122 }
123}