1#![allow(dead_code)]
18#![allow(unused_variables)]
19
20use std::str::FromStr;
21
22use nautilus_core::UnixNanos;
23use nautilus_model::{
24 enums::OptionKind,
25 identifiers::{InstrumentId, Symbol},
26 instruments::{
27 BettingInstrument, BinaryOption, CryptoFuture, CryptoOption, CryptoPerpetual, CurrencyPair,
28 Equity, FuturesContract, FuturesSpread, InstrumentAny, OptionContract, OptionSpread,
29 },
30 types::{Currency, Money, Price, Quantity},
31};
32use rust_decimal::Decimal;
33use sqlx::{FromRow, Row, postgres::PgRow};
34use ustr::Ustr;
35
36use crate::sql::models::enums::AssetClassModel;
37
38#[derive(Debug)]
39pub struct InstrumentAnyModel(pub InstrumentAny);
40
41#[derive(Debug)]
42pub struct BettingInstrumentModel(pub BettingInstrument);
43
44#[derive(Debug)]
45pub struct BinaryOptionModel(pub BinaryOption);
46
47#[derive(Debug)]
48pub struct CryptoFutureModel(pub CryptoFuture);
49
50#[derive(Debug)]
51pub struct CryptoOptionModel(pub CryptoOption);
52
53#[derive(Debug)]
54pub struct CryptoPerpetualModel(pub CryptoPerpetual);
55
56#[derive(Debug)]
57pub struct CurrencyPairModel(pub CurrencyPair);
58
59#[derive(Debug)]
60pub struct EquityModel(pub Equity);
61
62#[derive(Debug)]
63pub struct FuturesContractModel(pub FuturesContract);
64
65#[derive(Debug)]
66pub struct FuturesSpreadModel(pub FuturesSpread);
67
68#[derive(Debug)]
69pub struct OptionContractModel(pub OptionContract);
70
71#[derive(Debug)]
72pub struct OptionSpreadModel(pub OptionSpread);
73
74impl<'r> FromRow<'r, PgRow> for InstrumentAnyModel {
75 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
76 let kind = row.get::<String, _>("kind");
77 if kind == "BETTING" {
78 Ok(Self(InstrumentAny::Betting(
79 BettingInstrumentModel::from_row(row).unwrap().0,
80 )))
81 } else if kind == "BINARY_OPTION" {
82 Ok(Self(InstrumentAny::BinaryOption(
83 BinaryOptionModel::from_row(row).unwrap().0,
84 )))
85 } else if kind == "CRYPTO_FUTURE" {
86 Ok(Self(InstrumentAny::CryptoFuture(
87 CryptoFutureModel::from_row(row).unwrap().0,
88 )))
89 } else if kind == "CRYPTO_OPTION" {
90 Ok(Self(InstrumentAny::CryptoOption(
91 CryptoOptionModel::from_row(row).unwrap().0,
92 )))
93 } else if kind == "CRYPTO_PERPETUAL" {
94 Ok(Self(InstrumentAny::CryptoPerpetual(
95 CryptoPerpetualModel::from_row(row).unwrap().0,
96 )))
97 } else if kind == "CURRENCY_PAIR" {
98 Ok(Self(InstrumentAny::CurrencyPair(
99 CurrencyPairModel::from_row(row).unwrap().0,
100 )))
101 } else if kind == "EQUITY" {
102 Ok(Self(InstrumentAny::Equity(
103 EquityModel::from_row(row).unwrap().0,
104 )))
105 } else if kind == "FUTURES_CONTRACT" {
106 Ok(Self(InstrumentAny::FuturesContract(
107 FuturesContractModel::from_row(row).unwrap().0,
108 )))
109 } else if kind == "FUTURES_SPREAD" {
110 Ok(Self(InstrumentAny::FuturesSpread(
111 FuturesSpreadModel::from_row(row).unwrap().0,
112 )))
113 } else if kind == "OPTION_CONTRACT" {
114 Ok(Self(InstrumentAny::OptionContract(
115 OptionContractModel::from_row(row).unwrap().0,
116 )))
117 } else if kind == "OPTION_SPREAD" {
118 Ok(Self(InstrumentAny::OptionSpread(
119 OptionSpreadModel::from_row(row).unwrap().0,
120 )))
121 } else {
122 panic!("Unknown instrument type")
123 }
124 }
125}
126
127impl<'r> FromRow<'r, PgRow> for BettingInstrumentModel {
129 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
130 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
131 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
132 let event_type_id = row.try_get::<i64, _>("event_type_id")? as u64;
133 let event_type_name = row
134 .try_get::<String, _>("event_type_name")
135 .map(|res| Ustr::from(res.as_str()))?;
136 let competition_id = row.try_get::<i64, _>("competition_id")? as u64;
137 let competition_name = row
138 .try_get::<String, _>("competition_name")
139 .map(|res| Ustr::from(res.as_str()))?;
140 let event_id = row.try_get::<i64, _>("event_id")? as u64;
141 let event_name = row
142 .try_get::<String, _>("event_name")
143 .map(|res| Ustr::from(res.as_str()))?;
144 let event_country_code = row
145 .try_get::<String, _>("event_country_code")
146 .map(|res| Ustr::from(res.as_str()))?;
147 let event_open_date = row
148 .try_get::<String, _>("event_open_date")
149 .map(UnixNanos::from)?;
150 let betting_type = row
151 .try_get::<String, _>("betting_type")
152 .map(|res| Ustr::from(res.as_str()))?;
153 let market_id = row
154 .try_get::<String, _>("market_id")
155 .map(|res| Ustr::from(res.as_str()))?;
156 let market_name = row
157 .try_get::<String, _>("market_name")
158 .map(|res| Ustr::from(res.as_str()))?;
159 let market_type = row
160 .try_get::<String, _>("market_type")
161 .map(|res| Ustr::from(res.as_str()))?;
162 let market_start_time = row
163 .try_get::<String, _>("market_start_time")
164 .map(UnixNanos::from)?;
165 let selection_id = row.try_get::<i64, _>("selection_id")? as u64;
166 let selection_name = row
167 .try_get::<String, _>("selection_name")
168 .map(|res| Ustr::from(res.as_str()))?;
169 let selection_handicap = row.try_get::<f64, _>("selection_handicap")?;
170 let currency = row
171 .try_get::<String, _>("quote_currency")
172 .map(Currency::from)?;
173 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
174 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
175 let price_increment = row
176 .try_get::<String, _>("price_increment")
177 .map(Price::from)?;
178 let size_increment = row
179 .try_get::<String, _>("size_increment")
180 .map(Quantity::from)?;
181 let max_quantity = row
182 .try_get::<Option<String>, _>("max_quantity")
183 .ok()
184 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
185 let min_quantity = row
186 .try_get::<Option<String>, _>("min_quantity")
187 .ok()
188 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
189 let max_notional = row
190 .try_get::<Option<String>, _>("max_notional")
191 .ok()
192 .and_then(|res| res.map(|value| Money::from(value.as_str())));
193 let min_notional = row
194 .try_get::<Option<String>, _>("min_notional")
195 .ok()
196 .and_then(|res| res.map(|value| Money::from(value.as_str())));
197 let max_price = row
198 .try_get::<Option<String>, _>("max_price")
199 .ok()
200 .and_then(|res| res.map(|value| Price::from(value.as_str())));
201 let min_price = row
202 .try_get::<Option<String>, _>("min_price")
203 .ok()
204 .and_then(|res| res.map(|value| Price::from(value.as_str())));
205 let margin_init = row
206 .try_get::<String, _>("margin_init")
207 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
208 let margin_maint = row
209 .try_get::<String, _>("margin_maint")
210 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
211 let maker_fee = row
212 .try_get::<String, _>("maker_fee")
213 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
214 let taker_fee = row
215 .try_get::<String, _>("taker_fee")
216 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
217 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
218 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
219
220 let inst = BettingInstrument::new(
221 id,
222 raw_symbol,
223 event_type_id,
224 event_type_name,
225 competition_id,
226 competition_name,
227 event_id,
228 event_name,
229 event_country_code,
230 event_open_date,
231 betting_type,
232 market_id,
233 market_name,
234 market_type,
235 market_start_time,
236 selection_id,
237 selection_name,
238 selection_handicap,
239 currency,
240 price_precision,
241 size_precision,
242 price_increment,
243 size_increment,
244 max_quantity,
245 min_quantity,
246 max_notional,
247 min_notional,
248 max_price,
249 min_price,
250 margin_init,
251 margin_maint,
252 maker_fee,
253 taker_fee,
254 ts_event,
255 ts_init,
256 );
257 Ok(Self(inst))
258 }
259}
260
261impl<'r> FromRow<'r, PgRow> for BinaryOptionModel {
262 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
263 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
264 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
265 let asset_class = row
266 .try_get::<AssetClassModel, _>("asset_class")
267 .map(|res| res.0)?;
268 let currency = row
269 .try_get::<String, _>("quote_currency")
270 .map(Currency::from)?;
271 let activation_ns = row
272 .try_get::<String, _>("activation_ns")
273 .map(UnixNanos::from)?;
274 let expiration_ns = row
275 .try_get::<String, _>("expiration_ns")
276 .map(UnixNanos::from)?;
277 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
278 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
279 let price_increment = row
280 .try_get::<String, _>("price_increment")
281 .map(|res| Price::from_str(res.as_str()).unwrap())?;
282 let size_increment = row
283 .try_get::<String, _>("size_increment")
284 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
285 let outcome = row
286 .try_get::<Option<String>, _>("outcome")
287 .ok()
288 .and_then(|res| res.map(|value| Ustr::from(value.as_str())));
289 let description = row
290 .try_get::<Option<String>, _>("description")
291 .ok()
292 .and_then(|res| res.map(|value| Ustr::from(value.as_str())));
293 let max_quantity = row
294 .try_get::<Option<String>, _>("max_quantity")
295 .ok()
296 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
297 let min_quantity = row
298 .try_get::<Option<String>, _>("min_quantity")
299 .ok()
300 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
301 let max_notional = row
302 .try_get::<Option<String>, _>("max_notional")
303 .ok()
304 .and_then(|res| res.map(|value| Money::from(value.as_str())));
305 let min_notional = row
306 .try_get::<Option<String>, _>("min_notional")
307 .ok()
308 .and_then(|res| res.map(|value| Money::from(value.as_str())));
309 let max_price = row
310 .try_get::<Option<String>, _>("max_price")
311 .ok()
312 .and_then(|res| res.map(|value| Price::from(value.as_str())));
313 let min_price = row
314 .try_get::<Option<String>, _>("min_price")
315 .ok()
316 .and_then(|res| res.map(|value| Price::from(value.as_str())));
317 let margin_init = row
318 .try_get::<String, _>("margin_init")
319 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
320 let margin_maint = row
321 .try_get::<String, _>("margin_maint")
322 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
323 let maker_fee = row
324 .try_get::<String, _>("maker_fee")
325 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
326 let taker_fee = row
327 .try_get::<String, _>("taker_fee")
328 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
329 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
330 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
331
332 let inst = BinaryOption::new(
333 id,
334 raw_symbol,
335 asset_class,
336 currency,
337 activation_ns,
338 expiration_ns,
339 price_precision,
340 size_precision,
341 price_increment,
342 size_increment,
343 outcome,
344 description,
345 max_quantity,
346 min_quantity,
347 max_notional,
348 min_notional,
349 max_price,
350 min_price,
351 margin_init,
352 margin_maint,
353 maker_fee,
354 taker_fee,
355 ts_event,
356 ts_init,
357 );
358 Ok(Self(inst))
359 }
360}
361
362impl<'r> FromRow<'r, PgRow> for CryptoFutureModel {
363 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
364 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
365 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
366 let underlying = row.try_get::<String, _>("underlying").map(Currency::from)?;
367 let quote_currency = row
368 .try_get::<String, _>("quote_currency")
369 .map(Currency::from)?;
370 let settlement_currency = row
371 .try_get::<String, _>("settlement_currency")
372 .map(Currency::from)?;
373 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
374 let activation_ns = row
375 .try_get::<String, _>("activation_ns")
376 .map(UnixNanos::from)?;
377 let expiration_ns = row
378 .try_get::<String, _>("expiration_ns")
379 .map(UnixNanos::from)?;
380 let price_precision = row.try_get::<i32, _>("price_precision")?;
381 let size_precision = row.try_get::<i32, _>("size_precision")?;
382 let price_increment = row
383 .try_get::<String, _>("price_increment")
384 .map(|res| Price::from_str(res.as_str()).unwrap())?;
385 let size_increment = row
386 .try_get::<String, _>("size_increment")
387 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
388 let multiplier = row
389 .try_get::<String, _>("multiplier")
390 .map(|res| Quantity::from(res.as_str()))?;
391 let lot_size = row
392 .try_get::<String, _>("lot_size")
393 .map(|res| Quantity::from(res.as_str()))?;
394 let max_quantity = row
395 .try_get::<Option<String>, _>("max_quantity")
396 .ok()
397 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
398 let min_quantity = row
399 .try_get::<Option<String>, _>("min_quantity")
400 .ok()
401 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
402 let max_notional = row
403 .try_get::<Option<String>, _>("max_notional")
404 .ok()
405 .and_then(|res| res.map(|value| Money::from(value.as_str())));
406 let min_notional = row
407 .try_get::<Option<String>, _>("min_notional")
408 .ok()
409 .and_then(|res| res.map(|value| Money::from(value.as_str())));
410 let max_price = row
411 .try_get::<Option<String>, _>("max_price")
412 .ok()
413 .and_then(|res| res.map(|value| Price::from(value.as_str())));
414 let min_price = row
415 .try_get::<Option<String>, _>("min_price")
416 .ok()
417 .and_then(|res| res.map(|value| Price::from(value.as_str())));
418 let margin_init = row
419 .try_get::<String, _>("margin_init")
420 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
421 let margin_maint = row
422 .try_get::<String, _>("margin_maint")
423 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
424 let maker_fee = row
425 .try_get::<String, _>("maker_fee")
426 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
427 let taker_fee = row
428 .try_get::<String, _>("taker_fee")
429 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
430 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
431 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
432
433 let inst = CryptoFuture::new(
434 id,
435 raw_symbol,
436 underlying,
437 quote_currency,
438 settlement_currency,
439 is_inverse,
440 activation_ns,
441 expiration_ns,
442 price_precision as u8,
443 size_precision as u8,
444 price_increment,
445 size_increment,
446 Some(multiplier),
447 Some(lot_size),
448 max_quantity,
449 min_quantity,
450 max_notional,
451 min_notional,
452 max_price,
453 min_price,
454 margin_init,
455 margin_maint,
456 maker_fee,
457 taker_fee,
458 ts_event,
459 ts_init,
460 );
461 Ok(Self(inst))
462 }
463}
464
465impl<'r> FromRow<'r, PgRow> for CryptoOptionModel {
466 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
467 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
468 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
469 let underlying = row.try_get::<String, _>("underlying").map(Currency::from)?;
470 let quote_currency = row
471 .try_get::<String, _>("quote_currency")
472 .map(Currency::from)?;
473 let settlement_currency = row
474 .try_get::<String, _>("settlement_currency")
475 .map(Currency::from)?;
476 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
477 let option_kind = row
478 .try_get::<String, _>("option_kind")
479 .map(|res| OptionKind::from_str(res.as_str()).unwrap())?;
480 let strike_price = row
481 .try_get::<String, _>("strike_price")
482 .map(|res| Price::from_str(res.as_str()).unwrap())?;
483 let activation_ns = row
484 .try_get::<String, _>("activation_ns")
485 .map(UnixNanos::from)?;
486 let expiration_ns = row
487 .try_get::<String, _>("expiration_ns")
488 .map(UnixNanos::from)?;
489 let price_precision = row.try_get::<i32, _>("price_precision")?;
490 let size_precision = row.try_get::<i32, _>("size_precision")?;
491 let price_increment = row
492 .try_get::<String, _>("price_increment")
493 .map(|res| Price::from_str(res.as_str()).unwrap())?;
494 let size_increment = row
495 .try_get::<String, _>("size_increment")
496 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
497 let multiplier = row
498 .try_get::<String, _>("multiplier")
499 .map(|res| Quantity::from(res.as_str()))?;
500 let max_quantity = row
501 .try_get::<Option<String>, _>("max_quantity")
502 .ok()
503 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
504 let min_quantity = row
505 .try_get::<Option<String>, _>("min_quantity")
506 .ok()
507 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
508 let max_notional = row
509 .try_get::<Option<String>, _>("max_notional")
510 .ok()
511 .and_then(|res| res.map(|value| Money::from(value.as_str())));
512 let min_notional = row
513 .try_get::<Option<String>, _>("min_notional")
514 .ok()
515 .and_then(|res| res.map(|value| Money::from(value.as_str())));
516 let max_price = row
517 .try_get::<Option<String>, _>("max_price")
518 .ok()
519 .and_then(|res| res.map(|value| Price::from(value.as_str())));
520 let min_price = row
521 .try_get::<Option<String>, _>("min_price")
522 .ok()
523 .and_then(|res| res.map(|value| Price::from(value.as_str())));
524 let margin_init = row
525 .try_get::<String, _>("margin_init")
526 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
527 let margin_maint = row
528 .try_get::<String, _>("margin_maint")
529 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
530 let maker_fee = row
531 .try_get::<String, _>("maker_fee")
532 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
533 let taker_fee = row
534 .try_get::<String, _>("taker_fee")
535 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
536 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
537 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
538
539 let inst = CryptoOption::new(
540 id,
541 raw_symbol,
542 underlying,
543 quote_currency,
544 settlement_currency,
545 is_inverse,
546 option_kind,
547 strike_price,
548 activation_ns,
549 expiration_ns,
550 price_precision as u8,
551 size_precision as u8,
552 price_increment,
553 size_increment,
554 Some(multiplier),
555 max_quantity,
556 min_quantity,
557 max_notional,
558 min_notional,
559 max_price,
560 min_price,
561 margin_init,
562 margin_maint,
563 maker_fee,
564 taker_fee,
565 ts_event,
566 ts_init,
567 );
568 Ok(Self(inst))
569 }
570}
571
572impl<'r> FromRow<'r, PgRow> for CryptoPerpetualModel {
573 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
574 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
575 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
576 let base_currency = row
577 .try_get::<String, _>("base_currency")
578 .map(Currency::from)?;
579 let quote_currency = row
580 .try_get::<String, _>("quote_currency")
581 .map(Currency::from)?;
582 let settlement_currency = row
583 .try_get::<String, _>("settlement_currency")
584 .map(Currency::from)?;
585 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
586 let price_precision = row.try_get::<i32, _>("price_precision")?;
587 let size_precision = row.try_get::<i32, _>("size_precision")?;
588 let price_increment = row
589 .try_get::<String, _>("price_increment")
590 .map(|res| Price::from_str(res.as_str()).unwrap())?;
591 let size_increment = row
592 .try_get::<String, _>("size_increment")
593 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
594 let multiplier = row
595 .try_get::<String, _>("multiplier")
596 .map(|res| Quantity::from(res.as_str()))?;
597 let lot_size = row
598 .try_get::<String, _>("lot_size")
599 .map(|res| Quantity::from(res.as_str()))?;
600 let max_quantity = row
601 .try_get::<Option<String>, _>("max_quantity")
602 .ok()
603 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
604 let min_quantity = row
605 .try_get::<Option<String>, _>("min_quantity")
606 .ok()
607 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
608 let max_notional = row
609 .try_get::<Option<String>, _>("max_notional")
610 .ok()
611 .and_then(|res| res.map(|res| Money::from(res.as_str())));
612 let min_notional = row
613 .try_get::<Option<String>, _>("min_notional")
614 .ok()
615 .and_then(|res| res.map(|res| Money::from(res.as_str())));
616 let max_price = row
617 .try_get::<Option<String>, _>("max_price")
618 .ok()
619 .and_then(|res| res.map(|res| Price::from(res.as_str())));
620 let min_price = row
621 .try_get::<Option<String>, _>("min_price")
622 .ok()
623 .and_then(|res| res.map(|res| Price::from(res.as_str())));
624 let margin_init = row
625 .try_get::<String, _>("margin_init")
626 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
627 let margin_maint = row
628 .try_get::<String, _>("margin_maint")
629 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
630 let maker_fee = row
631 .try_get::<String, _>("maker_fee")
632 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
633 let taker_fee = row
634 .try_get::<String, _>("taker_fee")
635 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
636 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
637 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
638 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
639
640 let inst = CryptoPerpetual::new(
641 id,
642 raw_symbol,
643 base_currency,
644 quote_currency,
645 settlement_currency,
646 is_inverse,
647 price_precision as u8,
648 size_precision as u8,
649 price_increment,
650 size_increment,
651 Some(multiplier),
652 Some(lot_size),
653 max_quantity,
654 min_quantity,
655 max_notional,
656 min_notional,
657 max_price,
658 min_price,
659 margin_init,
660 margin_maint,
661 maker_fee,
662 taker_fee,
663 ts_event,
664 ts_init,
665 );
666 Ok(Self(inst))
667 }
668}
669
670impl<'r> FromRow<'r, PgRow> for CurrencyPairModel {
671 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
672 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
673 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
674 let base_currency = row
675 .try_get::<String, _>("base_currency")
676 .map(Currency::from)?;
677 let quote_currency = row
678 .try_get::<String, _>("quote_currency")
679 .map(Currency::from)?;
680 let price_precision = row.try_get::<i32, _>("price_precision")?;
681 let size_precision = row.try_get::<i32, _>("size_precision")?;
682 let price_increment = row
683 .try_get::<String, _>("price_increment")
684 .map(|res| Price::from(res.as_str()))?;
685 let size_increment = row
686 .try_get::<String, _>("size_increment")
687 .map(|res| Quantity::from(res.as_str()))?;
688 let lot_size = row
689 .try_get::<Option<String>, _>("lot_size")
690 .ok()
691 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
692 let max_quantity = row
693 .try_get::<Option<String>, _>("max_quantity")
694 .ok()
695 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
696 let min_quantity = row
697 .try_get::<Option<String>, _>("min_quantity")
698 .ok()
699 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
700 let max_notional = row
701 .try_get::<Option<String>, _>("max_notional")
702 .ok()
703 .and_then(|res| res.map(|res| Money::from(res.as_str())));
704 let min_notional = row
705 .try_get::<Option<String>, _>("min_notional")
706 .ok()
707 .and_then(|res| res.map(|res| Money::from(res.as_str())));
708 let max_price = row
709 .try_get::<Option<String>, _>("max_price")
710 .ok()
711 .and_then(|res| res.map(|res| Price::from(res.as_str())));
712 let min_price = row
713 .try_get::<Option<String>, _>("min_price")
714 .ok()
715 .and_then(|res| res.map(|res| Price::from(res.as_str())));
716 let margin_init = row
717 .try_get::<String, _>("margin_init")
718 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
719 let margin_maint = row
720 .try_get::<String, _>("margin_maint")
721 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
722 let maker_fee = row
723 .try_get::<String, _>("maker_fee")
724 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
725 let taker_fee = row
726 .try_get::<String, _>("taker_fee")
727 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
728 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
729 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
730
731 let inst = CurrencyPair::new(
732 id,
733 raw_symbol,
734 base_currency,
735 quote_currency,
736 price_precision as u8,
737 size_precision as u8,
738 price_increment,
739 size_increment,
740 lot_size,
741 max_quantity,
742 min_quantity,
743 max_notional,
744 min_notional,
745 max_price,
746 min_price,
747 margin_init,
748 margin_maint,
749 maker_fee,
750 taker_fee,
751 ts_event,
752 ts_init,
753 );
754 Ok(Self(inst))
755 }
756}
757
758impl<'r> FromRow<'r, PgRow> for EquityModel {
759 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
760 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
761 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
762 let isin = row
763 .try_get::<Option<String>, _>("isin")
764 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
765 let currency = row
766 .try_get::<String, _>("quote_currency")
767 .map(Currency::from)?;
768 let price_precision = row.try_get::<i32, _>("price_precision")?;
769 let price_increment = row
770 .try_get::<String, _>("price_increment")
771 .map(|res| Price::from_str(res.as_str()).unwrap())?;
772 let lot_size = row
773 .try_get::<Option<String>, _>("lot_size")
774 .map(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()))?;
775 let max_quantity = row
776 .try_get::<Option<String>, _>("max_quantity")
777 .ok()
778 .and_then(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()));
779 let min_quantity = row
780 .try_get::<Option<String>, _>("min_quantity")
781 .ok()
782 .and_then(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()));
783 let max_price = row
784 .try_get::<Option<String>, _>("max_price")
785 .ok()
786 .and_then(|res| res.map(|s| Price::from(s.as_str())));
787 let min_price = row
788 .try_get::<Option<String>, _>("min_price")
789 .ok()
790 .and_then(|res| res.map(|s| Price::from(s.as_str())));
791 let margin_init = row
792 .try_get::<String, _>("margin_init")
793 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
794 let margin_maint = row
795 .try_get::<String, _>("margin_maint")
796 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
797 let maker_fee = row
798 .try_get::<String, _>("maker_fee")
799 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
800 let taker_fee = row
801 .try_get::<String, _>("taker_fee")
802 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
803 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
804 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
805
806 let inst = Equity::new(
807 id,
808 raw_symbol,
809 isin,
810 currency,
811 price_precision as u8,
812 price_increment,
813 lot_size,
814 max_quantity,
815 min_quantity,
816 max_price,
817 min_price,
818 margin_init,
819 margin_maint,
820 maker_fee,
821 taker_fee,
822 ts_event,
823 ts_init,
824 );
825 Ok(Self(inst))
826 }
827}
828
829impl<'r> FromRow<'r, PgRow> for FuturesContractModel {
830 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
831 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
832 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::new)?;
833 let asset_class = row
834 .try_get::<AssetClassModel, _>("asset_class")
835 .map(|res| res.0)?;
836 let exchange = row
837 .try_get::<Option<String>, _>("exchange")
838 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
839 let underlying = row
840 .try_get::<String, _>("underlying")
841 .map(|res| Ustr::from(res.as_str()))?;
842 let currency = row
843 .try_get::<String, _>("quote_currency")
844 .map(Currency::from)?;
845 let activation_ns = row
846 .try_get::<String, _>("activation_ns")
847 .map(UnixNanos::from)?;
848 let expiration_ns = row
849 .try_get::<String, _>("expiration_ns")
850 .map(UnixNanos::from)?;
851 let price_precision = row.try_get::<i32, _>("price_precision")?;
852 let price_increment = row
853 .try_get::<String, _>("price_increment")
854 .map(|res| Price::from(res.as_str()))?;
855 let multiplier = row
856 .try_get::<String, _>("multiplier")
857 .map(|res| Quantity::from(res.as_str()))?;
858 let lot_size = row
859 .try_get::<String, _>("lot_size")
860 .map(|res| Quantity::from(res.as_str()))?;
861 let max_quantity = row
862 .try_get::<Option<String>, _>("max_quantity")
863 .ok()
864 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
865 let min_quantity = row
866 .try_get::<Option<String>, _>("min_quantity")
867 .ok()
868 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
869 let max_price = row
870 .try_get::<Option<String>, _>("max_price")
871 .ok()
872 .and_then(|res| res.map(|s| Price::from(s.as_str())));
873 let min_price = row
874 .try_get::<Option<String>, _>("min_price")
875 .ok()
876 .and_then(|res| res.map(|s| Price::from(s.as_str())));
877 let margin_init = row
878 .try_get::<String, _>("margin_init")
879 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
880 let margin_maint = row
881 .try_get::<String, _>("margin_maint")
882 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
883 let maker_fee = row
884 .try_get::<String, _>("maker_fee")
885 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
886 let taker_fee = row
887 .try_get::<String, _>("taker_fee")
888 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
889 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
890 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
891
892 let inst = FuturesContract::new(
893 id,
894 raw_symbol,
895 asset_class,
896 exchange,
897 underlying,
898 activation_ns,
899 expiration_ns,
900 currency,
901 price_precision as u8,
902 price_increment,
903 multiplier,
904 lot_size,
905 max_quantity,
906 min_quantity,
907 max_price,
908 min_price,
909 margin_init,
910 margin_maint,
911 maker_fee,
912 taker_fee,
913 ts_event,
914 ts_init,
915 );
916 Ok(Self(inst))
917 }
918}
919
920impl<'r> FromRow<'r, PgRow> for FuturesSpreadModel {
921 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
922 todo!("Implement FromRow for FuturesSpread")
923 }
924}
925
926impl<'r> FromRow<'r, PgRow> for OptionContractModel {
927 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
928 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
929 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::new)?;
930 let asset_class = row
931 .try_get::<AssetClassModel, _>("asset_class")
932 .map(|res| res.0)?;
933 let exchange = row
934 .try_get::<Option<String>, _>("exchange")
935 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
936 let underlying = row
937 .try_get::<String, _>("underlying")
938 .map(|res| Ustr::from(res.as_str()))?;
939 let option_kind = row
940 .try_get::<String, _>("option_kind")
941 .map(|res| OptionKind::from_str(res.as_str()).unwrap())?;
942 let activation_ns = row
943 .try_get::<String, _>("activation_ns")
944 .map(UnixNanos::from)?;
945 let expiration_ns = row
946 .try_get::<String, _>("expiration_ns")
947 .map(UnixNanos::from)?;
948 let strike_price = row
949 .try_get::<String, _>("strike_price")
950 .map(|res| Price::from_str(res.as_str()).unwrap())?;
951 let currency = row
952 .try_get::<String, _>("quote_currency")
953 .map(Currency::from)?;
954 let price_precision = row.try_get::<i32, _>("price_precision").unwrap();
955 let price_increment = row
956 .try_get::<String, _>("price_increment")
957 .map(|res| Price::from_str(res.as_str()).unwrap())?;
958 let multiplier = row
959 .try_get::<String, _>("multiplier")
960 .map(|res| Quantity::from(res.as_str()))?;
961 let lot_size = row
962 .try_get::<String, _>("lot_size")
963 .map(|res| Quantity::from(res.as_str()))
964 .unwrap();
965 let max_quantity = row
966 .try_get::<Option<String>, _>("max_quantity")
967 .ok()
968 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
969 let min_quantity = row
970 .try_get::<Option<String>, _>("min_quantity")
971 .ok()
972 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
973 let max_price = row
974 .try_get::<Option<String>, _>("max_price")
975 .ok()
976 .and_then(|res| res.map(|s| Price::from(s.as_str())));
977 let min_price = row
978 .try_get::<Option<String>, _>("min_price")
979 .ok()
980 .and_then(|res| res.map(|s| Price::from(s.as_str())));
981 let margin_init = row
982 .try_get::<String, _>("margin_init")
983 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
984 let margin_maint = row
985 .try_get::<String, _>("margin_maint")
986 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
987 let maker_fee = row
988 .try_get::<String, _>("maker_fee")
989 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
990 let taker_fee = row
991 .try_get::<String, _>("taker_fee")
992 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
993 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
994 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
995
996 let inst = OptionContract::new(
997 id,
998 raw_symbol,
999 asset_class,
1000 exchange,
1001 underlying,
1002 option_kind,
1003 strike_price,
1004 currency,
1005 activation_ns,
1006 expiration_ns,
1007 price_precision as u8,
1008 price_increment,
1009 multiplier,
1010 lot_size,
1011 max_quantity,
1012 min_quantity,
1013 max_price,
1014 min_price,
1015 margin_init,
1016 margin_maint,
1017 maker_fee,
1018 taker_fee,
1019 ts_event,
1020 ts_init,
1021 );
1022 Ok(Self(inst))
1023 }
1024}
1025
1026impl<'r> FromRow<'r, PgRow> for OptionSpreadModel {
1027 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
1028 todo!("Implement FromRow for OptionSpread")
1029 }
1030}