1use std::fmt::Display;
17
18use nautilus_core::{UnixNanos, serialization::Serializable};
19use serde::{Deserialize, Serialize};
20
21use super::GetTsInit;
22use crate::{identifiers::InstrumentId, types::Price};
23
24#[repr(C)]
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
31#[serde(tag = "type")]
32#[cfg_attr(
33 feature = "python",
34 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
35)]
36pub struct MarkPriceUpdate {
37 pub instrument_id: InstrumentId,
39 pub value: Price,
41 pub ts_event: UnixNanos,
43 pub ts_init: UnixNanos,
45}
46
47impl MarkPriceUpdate {
48 #[must_use]
50 pub fn new(
51 instrument_id: InstrumentId,
52 value: Price,
53 ts_event: UnixNanos,
54 ts_init: UnixNanos,
55 ) -> Self {
56 Self {
57 instrument_id,
58 value,
59 ts_event,
60 ts_init,
61 }
62 }
63}
64
65impl Display for MarkPriceUpdate {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(
68 f,
69 "{},{},{},{}",
70 self.instrument_id, self.value, self.ts_event, self.ts_init
71 )
72 }
73}
74
75impl Serializable for MarkPriceUpdate {}
76
77impl GetTsInit for MarkPriceUpdate {
78 fn ts_init(&self) -> UnixNanos {
79 self.ts_init
80 }
81}
82
83#[repr(C)]
85#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
86#[serde(tag = "type")]
87#[cfg_attr(
88 feature = "python",
89 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
90)]
91pub struct IndexPriceUpdate {
92 pub instrument_id: InstrumentId,
94 pub value: Price,
96 pub ts_event: UnixNanos,
98 pub ts_init: UnixNanos,
100}
101
102impl IndexPriceUpdate {
103 #[must_use]
105 pub fn new(
106 instrument_id: InstrumentId,
107 value: Price,
108 ts_event: UnixNanos,
109 ts_init: UnixNanos,
110 ) -> Self {
111 Self {
112 instrument_id,
113 value,
114 ts_event,
115 ts_init,
116 }
117 }
118}
119
120impl Display for IndexPriceUpdate {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(
123 f,
124 "{},{},{},{}",
125 self.instrument_id, self.value, self.ts_event, self.ts_init
126 )
127 }
128}
129
130impl Serializable for IndexPriceUpdate {}
131
132impl GetTsInit for IndexPriceUpdate {
133 fn ts_init(&self) -> UnixNanos {
134 self.ts_init
135 }
136}
137
138#[cfg(test)]
142mod tests {
143 use std::{
144 collections::hash_map::DefaultHasher,
145 hash::{Hash, Hasher},
146 };
147
148 use nautilus_core::serialization::Serializable;
149 use rstest::{fixture, rstest};
150 use serde_json;
151
152 use super::*;
153
154 #[fixture]
155 fn instrument_id() -> InstrumentId {
156 InstrumentId::from("BTC-USDT.OKX")
157 }
158
159 #[fixture]
160 fn price() -> Price {
161 Price::from("150_500.10")
162 }
163
164 #[rstest]
165 fn test_mark_price_update_new(instrument_id: InstrumentId, price: Price) {
166 let ts_event = UnixNanos::from(1);
167 let ts_init = UnixNanos::from(2);
168
169 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
170
171 assert_eq!(mark_price.instrument_id, instrument_id);
172 assert_eq!(mark_price.value, price);
173 assert_eq!(mark_price.ts_event, ts_event);
174 assert_eq!(mark_price.ts_init, ts_init);
175 }
176
177 #[rstest]
178 fn test_mark_price_update_display(instrument_id: InstrumentId, price: Price) {
179 let ts_event = UnixNanos::from(1);
180 let ts_init = UnixNanos::from(2);
181
182 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
183
184 assert_eq!(format!("{mark_price}"), "BTC-USDT.OKX,150500.10,1,2");
185 }
186
187 #[rstest]
188 fn test_mark_price_update_get_ts_init(instrument_id: InstrumentId, price: Price) {
189 let ts_event = UnixNanos::from(1);
190 let ts_init = UnixNanos::from(2);
191
192 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
193
194 assert_eq!(mark_price.ts_init(), ts_init);
195 }
196
197 #[rstest]
198 fn test_mark_price_update_eq_hash(instrument_id: InstrumentId, price: Price) {
199 let ts_event = UnixNanos::from(1);
200 let ts_init = UnixNanos::from(2);
201
202 let mark_price1 = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
203 let mark_price2 = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
204 let mark_price3 =
205 MarkPriceUpdate::new(instrument_id, Price::from("143_500.50"), ts_event, ts_init);
206
207 assert_eq!(mark_price1, mark_price2);
208 assert_ne!(mark_price1, mark_price3);
209
210 use std::{
212 collections::hash_map::DefaultHasher,
213 hash::{Hash, Hasher},
214 };
215
216 let mut hasher1 = DefaultHasher::new();
217 let mut hasher2 = DefaultHasher::new();
218 mark_price1.hash(&mut hasher1);
219 mark_price2.hash(&mut hasher2);
220 assert_eq!(hasher1.finish(), hasher2.finish());
221 }
222
223 #[rstest]
224 fn test_mark_price_update_json_serialization(instrument_id: InstrumentId, price: Price) {
225 let ts_event = UnixNanos::from(1);
226 let ts_init = UnixNanos::from(2);
227
228 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
229
230 let serialized = mark_price.as_json_bytes().unwrap();
231 let deserialized = MarkPriceUpdate::from_json_bytes(&serialized).unwrap();
232
233 assert_eq!(mark_price, deserialized);
234 }
235
236 #[rstest]
237 fn test_mark_price_update_msgpack_serialization(instrument_id: InstrumentId, price: Price) {
238 let ts_event = UnixNanos::from(1);
239 let ts_init = UnixNanos::from(2);
240
241 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
242
243 let serialized = mark_price.as_msgpack_bytes().unwrap();
244 let deserialized = MarkPriceUpdate::from_msgpack_bytes(&serialized).unwrap();
245
246 assert_eq!(mark_price, deserialized);
247 }
248
249 #[rstest]
250 fn test_mark_price_update_clone(instrument_id: InstrumentId, price: Price) {
251 let ts_event = UnixNanos::from(1);
252 let ts_init = UnixNanos::from(2);
253
254 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
255 let cloned = mark_price.clone();
256
257 assert_eq!(mark_price, cloned);
258 }
259
260 #[rstest]
261 fn test_mark_price_update_serde_json(instrument_id: InstrumentId, price: Price) {
262 let ts_event = UnixNanos::from(1);
263 let ts_init = UnixNanos::from(2);
264
265 let mark_price = MarkPriceUpdate::new(instrument_id, price, ts_event, ts_init);
266
267 let json_str = serde_json::to_string(&mark_price).unwrap();
268 let deserialized: MarkPriceUpdate = serde_json::from_str(&json_str).unwrap();
269
270 assert_eq!(mark_price, deserialized);
271 }
272
273 #[rstest]
274 fn test_index_price_update_new(instrument_id: InstrumentId, price: Price) {
275 let ts_event = UnixNanos::from(1);
276 let ts_init = UnixNanos::from(2);
277
278 let index_price = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
279
280 assert_eq!(index_price.instrument_id, instrument_id);
281 assert_eq!(index_price.value, price);
282 assert_eq!(index_price.ts_event, ts_event);
283 assert_eq!(index_price.ts_init, ts_init);
284 }
285
286 #[rstest]
287 fn test_index_price_update_display(instrument_id: InstrumentId, price: Price) {
288 let ts_event = UnixNanos::from(1);
289 let ts_init = UnixNanos::from(2);
290
291 let index_price = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
292
293 assert_eq!(format!("{index_price}"), "BTC-USDT.OKX,150500.10,1,2");
294 }
295
296 #[rstest]
297 fn test_index_price_update_get_ts_init(instrument_id: InstrumentId, price: Price) {
298 let ts_event = UnixNanos::from(1);
299 let ts_init = UnixNanos::from(2);
300
301 let index_price = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
302
303 assert_eq!(index_price.ts_init(), ts_init);
304 }
305
306 #[rstest]
307 fn test_index_price_update_eq_hash(instrument_id: InstrumentId, price: Price) {
308 let ts_event = UnixNanos::from(1);
309 let ts_init = UnixNanos::from(2);
310
311 let index_price1 = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
312 let index_price2 = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
313 let index_price3 = IndexPriceUpdate::new(instrument_id, price, UnixNanos::from(3), ts_init);
314
315 assert_eq!(index_price1, index_price2);
316 assert_ne!(index_price1, index_price3);
317
318 let mut hasher1 = DefaultHasher::new();
319 let mut hasher2 = DefaultHasher::new();
320 index_price1.hash(&mut hasher1);
321 index_price2.hash(&mut hasher2);
322 assert_eq!(hasher1.finish(), hasher2.finish());
323 }
324
325 #[rstest]
326 fn test_index_price_update_json_serialization(instrument_id: InstrumentId, price: Price) {
327 let ts_event = UnixNanos::from(1);
328 let ts_init = UnixNanos::from(2);
329
330 let index_price = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
331
332 let serialized = index_price.as_json_bytes().unwrap();
333 let deserialized = IndexPriceUpdate::from_json_bytes(&serialized).unwrap();
334
335 assert_eq!(index_price, deserialized);
336 }
337
338 #[rstest]
339 fn test_index_price_update_msgpack_serialization(instrument_id: InstrumentId, price: Price) {
340 let ts_event = UnixNanos::from(1);
341 let ts_init = UnixNanos::from(2);
342
343 let index_price = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
344
345 let serialized = index_price.as_msgpack_bytes().unwrap();
346 let deserialized = IndexPriceUpdate::from_msgpack_bytes(&serialized).unwrap();
347
348 assert_eq!(index_price, deserialized);
349 }
350
351 #[rstest]
352 fn test_index_price_update_serde_json(instrument_id: InstrumentId, price: Price) {
353 let ts_event = UnixNanos::from(1);
354 let ts_init = UnixNanos::from(2);
355
356 let index_price = IndexPriceUpdate::new(instrument_id, price, ts_event, ts_init);
357
358 let json_str = serde_json::to_string(&index_price).unwrap();
359 let deserialized: IndexPriceUpdate = serde_json::from_str(&json_str).unwrap();
360
361 assert_eq!(index_price, deserialized);
362 }
363}