nautilus_model/instruments/
equity.rs1use std::hash::{Hash, Hasher};
17
18use nautilus_core::{
19 UnixNanos,
20 correctness::{FAILED, check_equal_u8, check_valid_string_optional},
21};
22use rust_decimal::Decimal;
23use serde::{Deserialize, Serialize};
24use ustr::Ustr;
25
26use super::{Instrument, any::InstrumentAny};
27use crate::{
28 enums::{AssetClass, InstrumentClass, OptionKind},
29 identifiers::{InstrumentId, Symbol},
30 types::{
31 currency::Currency,
32 money::Money,
33 price::{Price, check_positive_price},
34 quantity::Quantity,
35 },
36};
37
38#[repr(C)]
40#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
41#[cfg_attr(
42 feature = "python",
43 pyo3::pyclass(module = "posei_trader.core.nautilus_pyo3.model")
44)]
45pub struct Equity {
46 pub id: InstrumentId,
48 pub raw_symbol: Symbol,
50 pub isin: Option<Ustr>,
52 pub currency: Currency,
54 pub price_precision: u8,
56 pub price_increment: Price,
58 pub margin_init: Decimal,
60 pub margin_maint: Decimal,
62 pub maker_fee: Decimal,
64 pub taker_fee: Decimal,
66 pub lot_size: Option<Quantity>,
68 pub max_quantity: Option<Quantity>,
70 pub min_quantity: Option<Quantity>,
72 pub max_price: Option<Price>,
74 pub min_price: Option<Price>,
76 pub ts_event: UnixNanos,
78 pub ts_init: UnixNanos,
80}
81
82impl Equity {
83 #[allow(clippy::too_many_arguments)]
92 pub fn new_checked(
93 instrument_id: InstrumentId,
94 raw_symbol: Symbol,
95 isin: Option<Ustr>,
96 currency: Currency,
97 price_precision: u8,
98 price_increment: Price,
99 lot_size: Option<Quantity>,
100 max_quantity: Option<Quantity>,
101 min_quantity: Option<Quantity>,
102 max_price: Option<Price>,
103 min_price: Option<Price>,
104 margin_init: Option<Decimal>,
105 margin_maint: Option<Decimal>,
106 maker_fee: Option<Decimal>,
107 taker_fee: Option<Decimal>,
108 ts_event: UnixNanos,
109 ts_init: UnixNanos,
110 ) -> anyhow::Result<Self> {
111 check_valid_string_optional(isin.map(|u| u.as_str()), stringify!(isin))?;
112 check_equal_u8(
113 price_precision,
114 price_increment.precision,
115 stringify!(price_precision),
116 stringify!(price_increment.precision),
117 )?;
118 check_positive_price(price_increment, stringify!(price_increment))?;
119
120 Ok(Self {
121 id: instrument_id,
122 raw_symbol,
123 isin,
124 currency,
125 price_precision,
126 price_increment,
127 lot_size,
128 max_quantity,
129 min_quantity,
130 max_price,
131 min_price,
132 margin_init: margin_init.unwrap_or_default(),
133 margin_maint: margin_maint.unwrap_or_default(),
134 maker_fee: maker_fee.unwrap_or_default(),
135 taker_fee: taker_fee.unwrap_or_default(),
136 ts_event,
137 ts_init,
138 })
139 }
140
141 #[allow(clippy::too_many_arguments)]
147 pub fn new(
148 instrument_id: InstrumentId,
149 raw_symbol: Symbol,
150 isin: Option<Ustr>,
151 currency: Currency,
152 price_precision: u8,
153 price_increment: Price,
154 lot_size: Option<Quantity>,
155 max_quantity: Option<Quantity>,
156 min_quantity: Option<Quantity>,
157 max_price: Option<Price>,
158 min_price: Option<Price>,
159 margin_init: Option<Decimal>,
160 margin_maint: Option<Decimal>,
161 maker_fee: Option<Decimal>,
162 taker_fee: Option<Decimal>,
163 ts_event: UnixNanos,
164 ts_init: UnixNanos,
165 ) -> Self {
166 Self::new_checked(
167 instrument_id,
168 raw_symbol,
169 isin,
170 currency,
171 price_precision,
172 price_increment,
173 lot_size,
174 max_quantity,
175 min_quantity,
176 max_price,
177 min_price,
178 margin_init,
179 margin_maint,
180 maker_fee,
181 taker_fee,
182 ts_event,
183 ts_init,
184 )
185 .expect(FAILED)
186 }
187}
188
189impl PartialEq<Self> for Equity {
190 fn eq(&self, other: &Self) -> bool {
191 self.id == other.id
192 }
193}
194
195impl Eq for Equity {}
196
197impl Hash for Equity {
198 fn hash<H: Hasher>(&self, state: &mut H) {
199 self.id.hash(state);
200 }
201}
202
203impl Instrument for Equity {
204 fn into_any(self) -> InstrumentAny {
205 InstrumentAny::Equity(self)
206 }
207
208 fn id(&self) -> InstrumentId {
209 self.id
210 }
211
212 fn raw_symbol(&self) -> Symbol {
213 self.raw_symbol
214 }
215
216 fn asset_class(&self) -> AssetClass {
217 AssetClass::Equity
218 }
219
220 fn instrument_class(&self) -> InstrumentClass {
221 InstrumentClass::Spot
222 }
223 fn underlying(&self) -> Option<Ustr> {
224 None
225 }
226
227 fn base_currency(&self) -> Option<Currency> {
228 None
229 }
230
231 fn quote_currency(&self) -> Currency {
232 self.currency
233 }
234
235 fn settlement_currency(&self) -> Currency {
236 self.currency
237 }
238
239 fn isin(&self) -> Option<Ustr> {
240 self.isin
241 }
242
243 fn option_kind(&self) -> Option<OptionKind> {
244 None
245 }
246
247 fn exchange(&self) -> Option<Ustr> {
248 None
249 }
250
251 fn strike_price(&self) -> Option<Price> {
252 None
253 }
254
255 fn activation_ns(&self) -> Option<UnixNanos> {
256 None
257 }
258
259 fn expiration_ns(&self) -> Option<UnixNanos> {
260 None
261 }
262
263 fn is_inverse(&self) -> bool {
264 false
265 }
266
267 fn price_precision(&self) -> u8 {
268 self.price_precision
269 }
270
271 fn size_precision(&self) -> u8 {
272 0
273 }
274
275 fn price_increment(&self) -> Price {
276 self.price_increment
277 }
278
279 fn size_increment(&self) -> Quantity {
280 Quantity::from(1)
281 }
282
283 fn multiplier(&self) -> Quantity {
284 Quantity::from(1)
285 }
286
287 fn lot_size(&self) -> Option<Quantity> {
288 self.lot_size
289 }
290
291 fn max_quantity(&self) -> Option<Quantity> {
292 self.max_quantity
293 }
294
295 fn min_quantity(&self) -> Option<Quantity> {
296 self.min_quantity
297 }
298
299 fn max_notional(&self) -> Option<Money> {
300 None
301 }
302
303 fn min_notional(&self) -> Option<Money> {
304 None
305 }
306
307 fn max_price(&self) -> Option<Price> {
308 self.max_price
309 }
310
311 fn min_price(&self) -> Option<Price> {
312 self.min_price
313 }
314
315 fn ts_event(&self) -> UnixNanos {
316 self.ts_event
317 }
318
319 fn ts_init(&self) -> UnixNanos {
320 self.ts_init
321 }
322}
323
324#[cfg(test)]
328mod tests {
329 use rstest::rstest;
330
331 use crate::instruments::{Equity, stubs::*};
332
333 #[rstest]
334 fn test_equality(equity_aapl: Equity) {
335 let cloned = equity_aapl;
336 assert_eq!(equity_aapl, cloned);
337 }
338}