nautilus_plugin/surfaces/commands/
close.rs1#![allow(unsafe_code)]
29
30use std::ops::Deref;
31
32use nautilus_model::{
33 enums::{PositionSide, TimeInForce},
34 identifiers::{ClientId, InstrumentId, PositionId},
35};
36use ustr::Ustr;
37
38#[repr(C)]
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct ClosePositionCommand {
45 pub position_id: PositionId,
47
48 pub client_id: Option<ClientId>,
50
51 pub tags: Option<Vec<Ustr>>,
53
54 pub time_in_force: Option<TimeInForce>,
56
57 pub reduce_only: Option<bool>,
59
60 pub quote_quantity: Option<bool>,
62}
63
64impl ClosePositionCommand {
65 #[must_use]
67 pub const fn new(
68 position_id: PositionId,
69 client_id: Option<ClientId>,
70 tags: Option<Vec<Ustr>>,
71 time_in_force: Option<TimeInForce>,
72 reduce_only: Option<bool>,
73 quote_quantity: Option<bool>,
74 ) -> Self {
75 Self {
76 position_id,
77 client_id,
78 tags,
79 time_in_force,
80 reduce_only,
81 quote_quantity,
82 }
83 }
84}
85
86#[repr(C)]
89#[derive(Debug, Clone)]
90pub struct ClosePositionHandle(Box<ClosePositionCommand>);
91
92impl ClosePositionHandle {
93 #[must_use]
95 pub fn new(command: ClosePositionCommand) -> Self {
96 Self(Box::new(command))
97 }
98
99 #[must_use]
101 pub fn command(&self) -> &ClosePositionCommand {
102 &self.0
103 }
104
105 #[must_use]
107 pub fn into_inner(self) -> ClosePositionCommand {
108 *self.0
109 }
110}
111
112impl Deref for ClosePositionHandle {
113 type Target = ClosePositionCommand;
114
115 fn deref(&self) -> &Self::Target {
116 &self.0
117 }
118}
119
120#[repr(C)]
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct CloseAllPositionsCommand {
124 pub instrument_id: InstrumentId,
126
127 pub position_side: Option<PositionSide>,
129
130 pub client_id: Option<ClientId>,
132
133 pub tags: Option<Vec<Ustr>>,
135
136 pub time_in_force: Option<TimeInForce>,
138
139 pub reduce_only: Option<bool>,
141
142 pub quote_quantity: Option<bool>,
144}
145
146impl CloseAllPositionsCommand {
147 #[allow(clippy::too_many_arguments)]
149 #[must_use]
150 pub const fn new(
151 instrument_id: InstrumentId,
152 position_side: Option<PositionSide>,
153 client_id: Option<ClientId>,
154 tags: Option<Vec<Ustr>>,
155 time_in_force: Option<TimeInForce>,
156 reduce_only: Option<bool>,
157 quote_quantity: Option<bool>,
158 ) -> Self {
159 Self {
160 instrument_id,
161 position_side,
162 client_id,
163 tags,
164 time_in_force,
165 reduce_only,
166 quote_quantity,
167 }
168 }
169}
170
171#[repr(C)]
174#[derive(Debug, Clone)]
175pub struct CloseAllPositionsHandle(Box<CloseAllPositionsCommand>);
176
177impl CloseAllPositionsHandle {
178 #[must_use]
180 pub fn new(command: CloseAllPositionsCommand) -> Self {
181 Self(Box::new(command))
182 }
183
184 #[must_use]
186 pub fn command(&self) -> &CloseAllPositionsCommand {
187 &self.0
188 }
189
190 #[must_use]
192 pub fn into_inner(self) -> CloseAllPositionsCommand {
193 *self.0
194 }
195}
196
197impl Deref for CloseAllPositionsHandle {
198 type Target = CloseAllPositionsCommand;
199
200 fn deref(&self) -> &Self::Target {
201 &self.0
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use rstest::rstest;
208
209 use super::*;
210
211 #[rstest]
212 fn close_position_handle_round_trips_command() {
213 let cmd = ClosePositionCommand::new(
214 PositionId::from("P-001"),
215 None,
216 Some(vec![Ustr::from("exit")]),
217 Some(TimeInForce::Ioc),
218 None,
219 None,
220 );
221 let handle = ClosePositionHandle::new(cmd.clone());
222 assert_eq!(handle.command(), &cmd);
223 assert_eq!(&*handle, &cmd);
224 assert_eq!(handle.into_inner(), cmd);
225 }
226
227 #[rstest]
228 fn close_all_positions_handle_round_trips_command() {
229 let cmd = CloseAllPositionsCommand::new(
230 InstrumentId::from("ETH-USDT.BINANCE"),
231 Some(PositionSide::Long),
232 None,
233 None,
234 None,
235 None,
236 None,
237 );
238 let handle = CloseAllPositionsHandle::new(cmd.clone());
239 assert_eq!(handle.command(), &cmd);
240 assert_eq!(&*handle, &cmd);
241 assert_eq!(handle.into_inner(), cmd);
242 }
243}