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