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 lot_size = row
501 .try_get::<String, _>("lot_size")
502 .map(|res| Quantity::from(res.as_str()))?;
503 let max_quantity = row
504 .try_get::<Option<String>, _>("max_quantity")
505 .ok()
506 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
507 let min_quantity = row
508 .try_get::<Option<String>, _>("min_quantity")
509 .ok()
510 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
511 let max_notional = row
512 .try_get::<Option<String>, _>("max_notional")
513 .ok()
514 .and_then(|res| res.map(|value| Money::from(value.as_str())));
515 let min_notional = row
516 .try_get::<Option<String>, _>("min_notional")
517 .ok()
518 .and_then(|res| res.map(|value| Money::from(value.as_str())));
519 let max_price = row
520 .try_get::<Option<String>, _>("max_price")
521 .ok()
522 .and_then(|res| res.map(|value| Price::from(value.as_str())));
523 let min_price = row
524 .try_get::<Option<String>, _>("min_price")
525 .ok()
526 .and_then(|res| res.map(|value| Price::from(value.as_str())));
527 let margin_init = row
528 .try_get::<String, _>("margin_init")
529 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
530 let margin_maint = row
531 .try_get::<String, _>("margin_maint")
532 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
533 let maker_fee = row
534 .try_get::<String, _>("maker_fee")
535 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
536 let taker_fee = row
537 .try_get::<String, _>("taker_fee")
538 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
539 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
540 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
541
542 let inst = CryptoOption::new(
543 id,
544 raw_symbol,
545 underlying,
546 quote_currency,
547 settlement_currency,
548 is_inverse,
549 option_kind,
550 strike_price,
551 activation_ns,
552 expiration_ns,
553 price_precision as u8,
554 size_precision as u8,
555 price_increment,
556 size_increment,
557 Some(multiplier),
558 Some(lot_size),
559 max_quantity,
560 min_quantity,
561 max_notional,
562 min_notional,
563 max_price,
564 min_price,
565 margin_init,
566 margin_maint,
567 maker_fee,
568 taker_fee,
569 ts_event,
570 ts_init,
571 );
572 Ok(Self(inst))
573 }
574}
575
576impl<'r> FromRow<'r, PgRow> for CryptoPerpetualModel {
577 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
578 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
579 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
580 let base_currency = row
581 .try_get::<String, _>("base_currency")
582 .map(Currency::from)?;
583 let quote_currency = row
584 .try_get::<String, _>("quote_currency")
585 .map(Currency::from)?;
586 let settlement_currency = row
587 .try_get::<String, _>("settlement_currency")
588 .map(Currency::from)?;
589 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
590 let price_precision = row.try_get::<i32, _>("price_precision")?;
591 let size_precision = row.try_get::<i32, _>("size_precision")?;
592 let price_increment = row
593 .try_get::<String, _>("price_increment")
594 .map(|res| Price::from_str(res.as_str()).unwrap())?;
595 let size_increment = row
596 .try_get::<String, _>("size_increment")
597 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
598 let multiplier = row
599 .try_get::<String, _>("multiplier")
600 .map(|res| Quantity::from(res.as_str()))?;
601 let lot_size = row
602 .try_get::<String, _>("lot_size")
603 .map(|res| Quantity::from(res.as_str()))?;
604 let max_quantity = row
605 .try_get::<Option<String>, _>("max_quantity")
606 .ok()
607 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
608 let min_quantity = row
609 .try_get::<Option<String>, _>("min_quantity")
610 .ok()
611 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
612 let max_notional = row
613 .try_get::<Option<String>, _>("max_notional")
614 .ok()
615 .and_then(|res| res.map(|res| Money::from(res.as_str())));
616 let min_notional = row
617 .try_get::<Option<String>, _>("min_notional")
618 .ok()
619 .and_then(|res| res.map(|res| Money::from(res.as_str())));
620 let max_price = row
621 .try_get::<Option<String>, _>("max_price")
622 .ok()
623 .and_then(|res| res.map(|res| Price::from(res.as_str())));
624 let min_price = row
625 .try_get::<Option<String>, _>("min_price")
626 .ok()
627 .and_then(|res| res.map(|res| Price::from(res.as_str())));
628 let margin_init = row
629 .try_get::<String, _>("margin_init")
630 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
631 let margin_maint = row
632 .try_get::<String, _>("margin_maint")
633 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
634 let maker_fee = row
635 .try_get::<String, _>("maker_fee")
636 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
637 let taker_fee = row
638 .try_get::<String, _>("taker_fee")
639 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
640 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
641 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
642 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
643
644 let inst = CryptoPerpetual::new(
645 id,
646 raw_symbol,
647 base_currency,
648 quote_currency,
649 settlement_currency,
650 is_inverse,
651 price_precision as u8,
652 size_precision as u8,
653 price_increment,
654 size_increment,
655 Some(multiplier),
656 Some(lot_size),
657 max_quantity,
658 min_quantity,
659 max_notional,
660 min_notional,
661 max_price,
662 min_price,
663 margin_init,
664 margin_maint,
665 maker_fee,
666 taker_fee,
667 ts_event,
668 ts_init,
669 );
670 Ok(Self(inst))
671 }
672}
673
674impl<'r> FromRow<'r, PgRow> for CurrencyPairModel {
675 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
676 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
677 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
678 let base_currency = row
679 .try_get::<String, _>("base_currency")
680 .map(Currency::from)?;
681 let quote_currency = row
682 .try_get::<String, _>("quote_currency")
683 .map(Currency::from)?;
684 let price_precision = row.try_get::<i32, _>("price_precision")?;
685 let size_precision = row.try_get::<i32, _>("size_precision")?;
686 let price_increment = row
687 .try_get::<String, _>("price_increment")
688 .map(|res| Price::from(res.as_str()))?;
689 let size_increment = row
690 .try_get::<String, _>("size_increment")
691 .map(|res| Quantity::from(res.as_str()))?;
692 let multiplier = row
693 .try_get::<Option<String>, _>("multiplier")
694 .ok()
695 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
696 let lot_size = row
697 .try_get::<Option<String>, _>("lot_size")
698 .ok()
699 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
700 let max_quantity = row
701 .try_get::<Option<String>, _>("max_quantity")
702 .ok()
703 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
704 let min_quantity = row
705 .try_get::<Option<String>, _>("min_quantity")
706 .ok()
707 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
708 let max_notional = row
709 .try_get::<Option<String>, _>("max_notional")
710 .ok()
711 .and_then(|res| res.map(|res| Money::from(res.as_str())));
712 let min_notional = row
713 .try_get::<Option<String>, _>("min_notional")
714 .ok()
715 .and_then(|res| res.map(|res| Money::from(res.as_str())));
716 let max_price = row
717 .try_get::<Option<String>, _>("max_price")
718 .ok()
719 .and_then(|res| res.map(|res| Price::from(res.as_str())));
720 let min_price = row
721 .try_get::<Option<String>, _>("min_price")
722 .ok()
723 .and_then(|res| res.map(|res| Price::from(res.as_str())));
724 let margin_init = row
725 .try_get::<String, _>("margin_init")
726 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
727 let margin_maint = row
728 .try_get::<String, _>("margin_maint")
729 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
730 let maker_fee = row
731 .try_get::<String, _>("maker_fee")
732 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
733 let taker_fee = row
734 .try_get::<String, _>("taker_fee")
735 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
736 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
737 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
738
739 let inst = CurrencyPair::new(
740 id,
741 raw_symbol,
742 base_currency,
743 quote_currency,
744 price_precision as u8,
745 size_precision as u8,
746 price_increment,
747 size_increment,
748 multiplier,
749 lot_size,
750 max_quantity,
751 min_quantity,
752 max_notional,
753 min_notional,
754 max_price,
755 min_price,
756 margin_init,
757 margin_maint,
758 maker_fee,
759 taker_fee,
760 ts_event,
761 ts_init,
762 );
763 Ok(Self(inst))
764 }
765}
766
767impl<'r> FromRow<'r, PgRow> for EquityModel {
768 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
769 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
770 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
771 let isin = row
772 .try_get::<Option<String>, _>("isin")
773 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
774 let currency = row
775 .try_get::<String, _>("quote_currency")
776 .map(Currency::from)?;
777 let price_precision = row.try_get::<i32, _>("price_precision")?;
778 let price_increment = row
779 .try_get::<String, _>("price_increment")
780 .map(|res| Price::from_str(res.as_str()).unwrap())?;
781 let lot_size = row
782 .try_get::<Option<String>, _>("lot_size")
783 .map(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()))?;
784 let max_quantity = row
785 .try_get::<Option<String>, _>("max_quantity")
786 .ok()
787 .and_then(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()));
788 let min_quantity = row
789 .try_get::<Option<String>, _>("min_quantity")
790 .ok()
791 .and_then(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()));
792 let max_price = row
793 .try_get::<Option<String>, _>("max_price")
794 .ok()
795 .and_then(|res| res.map(|s| Price::from(s.as_str())));
796 let min_price = row
797 .try_get::<Option<String>, _>("min_price")
798 .ok()
799 .and_then(|res| res.map(|s| Price::from(s.as_str())));
800 let margin_init = row
801 .try_get::<String, _>("margin_init")
802 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
803 let margin_maint = row
804 .try_get::<String, _>("margin_maint")
805 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
806 let maker_fee = row
807 .try_get::<String, _>("maker_fee")
808 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
809 let taker_fee = row
810 .try_get::<String, _>("taker_fee")
811 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
812 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
813 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
814
815 let inst = Equity::new(
816 id,
817 raw_symbol,
818 isin,
819 currency,
820 price_precision as u8,
821 price_increment,
822 lot_size,
823 max_quantity,
824 min_quantity,
825 max_price,
826 min_price,
827 margin_init,
828 margin_maint,
829 maker_fee,
830 taker_fee,
831 ts_event,
832 ts_init,
833 );
834 Ok(Self(inst))
835 }
836}
837
838impl<'r> FromRow<'r, PgRow> for FuturesContractModel {
839 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
840 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
841 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::new)?;
842 let asset_class = row
843 .try_get::<AssetClassModel, _>("asset_class")
844 .map(|res| res.0)?;
845 let exchange = row
846 .try_get::<Option<String>, _>("exchange")
847 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
848 let underlying = row
849 .try_get::<String, _>("underlying")
850 .map(|res| Ustr::from(res.as_str()))?;
851 let currency = row
852 .try_get::<String, _>("quote_currency")
853 .map(Currency::from)?;
854 let activation_ns = row
855 .try_get::<String, _>("activation_ns")
856 .map(UnixNanos::from)?;
857 let expiration_ns = row
858 .try_get::<String, _>("expiration_ns")
859 .map(UnixNanos::from)?;
860 let price_precision = row.try_get::<i32, _>("price_precision")?;
861 let price_increment = row
862 .try_get::<String, _>("price_increment")
863 .map(|res| Price::from(res.as_str()))?;
864 let multiplier = row
865 .try_get::<String, _>("multiplier")
866 .map(|res| Quantity::from(res.as_str()))?;
867 let lot_size = row
868 .try_get::<String, _>("lot_size")
869 .map(|res| Quantity::from(res.as_str()))?;
870 let max_quantity = row
871 .try_get::<Option<String>, _>("max_quantity")
872 .ok()
873 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
874 let min_quantity = row
875 .try_get::<Option<String>, _>("min_quantity")
876 .ok()
877 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
878 let max_price = row
879 .try_get::<Option<String>, _>("max_price")
880 .ok()
881 .and_then(|res| res.map(|s| Price::from(s.as_str())));
882 let min_price = row
883 .try_get::<Option<String>, _>("min_price")
884 .ok()
885 .and_then(|res| res.map(|s| Price::from(s.as_str())));
886 let margin_init = row
887 .try_get::<String, _>("margin_init")
888 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
889 let margin_maint = row
890 .try_get::<String, _>("margin_maint")
891 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
892 let maker_fee = row
893 .try_get::<String, _>("maker_fee")
894 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
895 let taker_fee = row
896 .try_get::<String, _>("taker_fee")
897 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
898 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
899 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
900
901 let inst = FuturesContract::new(
902 id,
903 raw_symbol,
904 asset_class,
905 exchange,
906 underlying,
907 activation_ns,
908 expiration_ns,
909 currency,
910 price_precision as u8,
911 price_increment,
912 multiplier,
913 lot_size,
914 max_quantity,
915 min_quantity,
916 max_price,
917 min_price,
918 margin_init,
919 margin_maint,
920 maker_fee,
921 taker_fee,
922 ts_event,
923 ts_init,
924 );
925 Ok(Self(inst))
926 }
927}
928
929impl<'r> FromRow<'r, PgRow> for FuturesSpreadModel {
930 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
931 todo!("Implement FromRow for FuturesSpread")
932 }
933}
934
935impl<'r> FromRow<'r, PgRow> for OptionContractModel {
936 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
937 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
938 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::new)?;
939 let asset_class = row
940 .try_get::<AssetClassModel, _>("asset_class")
941 .map(|res| res.0)?;
942 let exchange = row
943 .try_get::<Option<String>, _>("exchange")
944 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
945 let underlying = row
946 .try_get::<String, _>("underlying")
947 .map(|res| Ustr::from(res.as_str()))?;
948 let option_kind = row
949 .try_get::<String, _>("option_kind")
950 .map(|res| OptionKind::from_str(res.as_str()).unwrap())?;
951 let activation_ns = row
952 .try_get::<String, _>("activation_ns")
953 .map(UnixNanos::from)?;
954 let expiration_ns = row
955 .try_get::<String, _>("expiration_ns")
956 .map(UnixNanos::from)?;
957 let strike_price = row
958 .try_get::<String, _>("strike_price")
959 .map(|res| Price::from_str(res.as_str()).unwrap())?;
960 let currency = row
961 .try_get::<String, _>("quote_currency")
962 .map(Currency::from)?;
963 let price_precision = row.try_get::<i32, _>("price_precision").unwrap();
964 let price_increment = row
965 .try_get::<String, _>("price_increment")
966 .map(|res| Price::from_str(res.as_str()).unwrap())?;
967 let multiplier = row
968 .try_get::<String, _>("multiplier")
969 .map(|res| Quantity::from(res.as_str()))?;
970 let lot_size = row
971 .try_get::<String, _>("lot_size")
972 .map(|res| Quantity::from(res.as_str()))
973 .unwrap();
974 let max_quantity = row
975 .try_get::<Option<String>, _>("max_quantity")
976 .ok()
977 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
978 let min_quantity = row
979 .try_get::<Option<String>, _>("min_quantity")
980 .ok()
981 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
982 let max_price = row
983 .try_get::<Option<String>, _>("max_price")
984 .ok()
985 .and_then(|res| res.map(|s| Price::from(s.as_str())));
986 let min_price = row
987 .try_get::<Option<String>, _>("min_price")
988 .ok()
989 .and_then(|res| res.map(|s| Price::from(s.as_str())));
990 let margin_init = row
991 .try_get::<String, _>("margin_init")
992 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
993 let margin_maint = row
994 .try_get::<String, _>("margin_maint")
995 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
996 let maker_fee = row
997 .try_get::<String, _>("maker_fee")
998 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
999 let taker_fee = row
1000 .try_get::<String, _>("taker_fee")
1001 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1002 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1003 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1004
1005 let inst = OptionContract::new(
1006 id,
1007 raw_symbol,
1008 asset_class,
1009 exchange,
1010 underlying,
1011 option_kind,
1012 strike_price,
1013 currency,
1014 activation_ns,
1015 expiration_ns,
1016 price_precision as u8,
1017 price_increment,
1018 multiplier,
1019 lot_size,
1020 max_quantity,
1021 min_quantity,
1022 max_price,
1023 min_price,
1024 margin_init,
1025 margin_maint,
1026 maker_fee,
1027 taker_fee,
1028 ts_event,
1029 ts_init,
1030 );
1031 Ok(Self(inst))
1032 }
1033}
1034
1035impl<'r> FromRow<'r, PgRow> for OptionSpreadModel {
1036 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
1037 todo!("Implement FromRow for OptionSpread")
1038 }
1039}