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}