nautilus_model/events/position/snapshot.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::UnixNanos;
17use serde::{Deserialize, Serialize};
18
19use crate::{
20 enums::{OrderSide, PositionSide},
21 identifiers::{AccountId, ClientOrderId, InstrumentId, PositionId, StrategyId, TraderId},
22 position::Position,
23 types::{Currency, Money, Quantity},
24};
25
26/// Represents a position state snapshot as a certain instant.
27#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
28#[cfg_attr(
29 feature = "python",
30 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
31)]
32pub struct PositionSnapshot {
33 /// The trader ID associated with the snapshot.
34 pub trader_id: TraderId,
35 /// The strategy ID associated with the snapshot.
36 pub strategy_id: StrategyId,
37 /// The instrument ID associated with the snapshot.
38 pub instrument_id: InstrumentId,
39 /// The position ID associated with the snapshot.
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 entry direction from open.
48 pub entry: OrderSide,
49 /// The position side.
50 pub side: PositionSide,
51 /// The position signed quantity (positive for LONG, negative for SHOT).
52 pub signed_qty: f64,
53 /// The position open quantity.
54 pub quantity: Quantity,
55 /// The peak directional quantity reached by the position.
56 pub peak_qty: Quantity,
57 /// The position quote currency.
58 pub quote_currency: Currency,
59 /// The position base currency.
60 pub base_currency: Option<Currency>,
61 /// The position settlement currency.
62 pub settlement_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: Option<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: Option<Money>,
73 /// The commissions for the position.
74 pub commissions: Vec<Money>,
75 /// The open duration for the position (nanoseconds).
76 pub duration_ns: Option<u64>,
77 /// UNIX timestamp (nanoseconds) when the position opened.
78 pub ts_opened: UnixNanos,
79 /// UNIX timestamp (nanoseconds) when the position closed.
80 pub ts_closed: Option<UnixNanos>,
81 /// UNIX timestamp (nanoseconds) when the snapshot was initialized.
82 pub ts_init: UnixNanos,
83 /// UNIX timestamp (nanoseconds) when the last position event occurred.
84 pub ts_last: UnixNanos,
85}
86
87impl PositionSnapshot {
88 pub fn from(position: &Position, unrealized_pnl: Option<Money>) -> Self {
89 Self {
90 trader_id: position.trader_id,
91 strategy_id: position.strategy_id,
92 instrument_id: position.instrument_id,
93 position_id: position.id,
94 account_id: position.account_id,
95 opening_order_id: position.opening_order_id,
96 closing_order_id: position.closing_order_id,
97 entry: position.entry,
98 side: position.side,
99 signed_qty: position.signed_qty,
100 quantity: position.quantity,
101 peak_qty: position.peak_qty,
102 quote_currency: position.quote_currency,
103 base_currency: position.base_currency,
104 settlement_currency: position.settlement_currency,
105 avg_px_open: position.avg_px_open,
106 avg_px_close: position.avg_px_close,
107 realized_return: Some(position.realized_return), // TODO: Standardize
108 realized_pnl: position.realized_pnl,
109 unrealized_pnl,
110 commissions: position.commissions.values().cloned().collect(), // TODO: Optimize
111 duration_ns: Some(position.duration_ns), // TODO: Standardize
112 ts_opened: position.ts_opened,
113 ts_closed: position.ts_closed,
114 ts_init: position.ts_init,
115 ts_last: position.ts_last,
116 }
117 }
118}