Skip to main content

nautilus_model/python/events/position/
changed.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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::{UUID4, python::IntoPyObjectNautilusExt};
17use pyo3::{basic::CompareOp, prelude::*};
18use rust_decimal::Decimal;
19
20use crate::{
21    enums::{OrderSide, PositionSide},
22    events::{OrderFilled, PositionChanged},
23    identifiers::{AccountId, ClientOrderId, InstrumentId, PositionId, StrategyId, TraderId},
24    position::Position,
25    types::{Currency, Money, Price, Quantity},
26};
27
28#[pyo3_stub_gen::derive::gen_stub_pymethods]
29#[pymethods]
30impl PositionChanged {
31    #[staticmethod]
32    #[pyo3(name = "create")]
33    fn py_create(position: &Position, fill: &OrderFilled, event_id: UUID4, ts_init: u64) -> Self {
34        Self::create(position, fill, event_id, ts_init.into())
35    }
36
37    fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
38        match op {
39            CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
40            CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
41            _ => py.NotImplemented(),
42        }
43    }
44
45    fn __repr__(&self) -> String {
46        format!("{self:?}")
47    }
48
49    #[getter]
50    #[pyo3(name = "trader_id")]
51    fn py_trader_id(&self) -> TraderId {
52        self.trader_id
53    }
54
55    #[getter]
56    #[pyo3(name = "strategy_id")]
57    fn py_strategy_id(&self) -> StrategyId {
58        self.strategy_id
59    }
60
61    #[getter]
62    #[pyo3(name = "instrument_id")]
63    fn py_instrument_id(&self) -> InstrumentId {
64        self.instrument_id
65    }
66
67    #[getter]
68    #[pyo3(name = "position_id")]
69    fn py_position_id(&self) -> PositionId {
70        self.position_id
71    }
72
73    #[getter]
74    #[pyo3(name = "account_id")]
75    fn py_account_id(&self) -> AccountId {
76        self.account_id
77    }
78
79    #[getter]
80    #[pyo3(name = "opening_order_id")]
81    fn py_opening_order_id(&self) -> ClientOrderId {
82        self.opening_order_id
83    }
84
85    #[getter]
86    #[pyo3(name = "entry")]
87    fn py_entry(&self) -> OrderSide {
88        self.entry
89    }
90
91    #[getter]
92    #[pyo3(name = "side")]
93    fn py_side(&self) -> PositionSide {
94        self.side
95    }
96
97    #[getter]
98    #[pyo3(name = "signed_qty")]
99    fn py_signed_qty(&self) -> Decimal {
100        self.signed_qty
101    }
102
103    #[getter]
104    #[pyo3(name = "quantity")]
105    fn py_quantity(&self) -> Quantity {
106        self.quantity
107    }
108
109    #[getter]
110    #[pyo3(name = "peak_quantity")]
111    fn py_peak_quantity(&self) -> Quantity {
112        self.peak_quantity
113    }
114
115    #[getter]
116    #[pyo3(name = "peak_qty")]
117    fn py_peak_qty(&self) -> Quantity {
118        self.peak_quantity
119    }
120
121    #[getter]
122    #[pyo3(name = "last_qty")]
123    fn py_last_qty(&self) -> Quantity {
124        self.last_qty
125    }
126
127    #[getter]
128    #[pyo3(name = "last_px")]
129    fn py_last_px(&self) -> Price {
130        self.last_px
131    }
132
133    #[getter]
134    #[pyo3(name = "currency")]
135    fn py_currency(&self) -> Currency {
136        self.currency
137    }
138
139    #[getter]
140    #[pyo3(name = "avg_px_open")]
141    fn py_avg_px_open(&self) -> Decimal {
142        self.avg_px_open
143    }
144
145    #[getter]
146    #[pyo3(name = "avg_px_close")]
147    fn py_avg_px_close(&self) -> Option<Decimal> {
148        self.avg_px_close
149    }
150
151    #[getter]
152    #[pyo3(name = "realized_return")]
153    fn py_realized_return(&self) -> f64 {
154        self.realized_return
155    }
156
157    #[getter]
158    #[pyo3(name = "realized_pnl")]
159    fn py_realized_pnl(&self) -> Option<Money> {
160        self.realized_pnl
161    }
162
163    #[getter]
164    #[pyo3(name = "unrealized_pnl")]
165    fn py_unrealized_pnl(&self) -> Money {
166        self.unrealized_pnl
167    }
168
169    #[getter]
170    #[pyo3(name = "event_id")]
171    fn py_event_id(&self) -> UUID4 {
172        self.event_id
173    }
174
175    #[getter]
176    #[pyo3(name = "ts_opened")]
177    fn py_ts_opened(&self) -> u64 {
178        self.ts_opened.as_u64()
179    }
180
181    #[getter]
182    #[pyo3(name = "ts_event")]
183    fn py_ts_event(&self) -> u64 {
184        self.ts_event.as_u64()
185    }
186
187    #[getter]
188    #[pyo3(name = "ts_init")]
189    fn py_ts_init(&self) -> u64 {
190        self.ts_init.as_u64()
191    }
192}