1#![allow(dead_code)]
18#![allow(unused_variables)]
19
20use std::str::FromStr;
21
22use nautilus_core::UnixNanos;
23use nautilus_model::{
24 enums::{AssetClass, OptionKind},
25 identifiers::{InstrumentId, Symbol},
26 instruments::{
27 BettingInstrument, BinaryOption, Cfd, Commodity, CryptoFuture, CryptoOption,
28 CryptoPerpetual, CurrencyPair, Equity, FuturesContract, FuturesSpread, IndexInstrument,
29 InstrumentAny, OptionContract, OptionSpread, PerpetualContract, TokenizedAsset,
30 },
31 types::{Currency, Money, Price, Quantity},
32};
33use rust_decimal::Decimal;
34use sqlx::{FromRow, Row, postgres::PgRow};
35use ustr::Ustr;
36
37use crate::sql::models::enums::AssetClassModel;
38
39#[derive(Debug)]
40pub struct InstrumentAnyModel(pub InstrumentAny);
41
42#[derive(Debug)]
43pub struct BettingInstrumentModel(pub BettingInstrument);
44
45#[derive(Debug)]
46pub struct BinaryOptionModel(pub BinaryOption);
47
48#[derive(Debug)]
49pub struct CryptoFutureModel(pub CryptoFuture);
50
51#[derive(Debug)]
52pub struct CryptoOptionModel(pub CryptoOption);
53
54#[derive(Debug)]
55pub struct CryptoPerpetualModel(pub CryptoPerpetual);
56
57#[derive(Debug)]
58pub struct CurrencyPairModel(pub CurrencyPair);
59
60#[derive(Debug)]
61pub struct EquityModel(pub Equity);
62
63#[derive(Debug)]
64pub struct FuturesContractModel(pub FuturesContract);
65
66#[derive(Debug)]
67pub struct FuturesSpreadModel(pub FuturesSpread);
68
69#[derive(Debug)]
70pub struct OptionContractModel(pub OptionContract);
71
72#[derive(Debug)]
73pub struct CommodityModel(pub Commodity);
74
75#[derive(Debug)]
76pub struct IndexInstrumentModel(pub IndexInstrument);
77
78#[derive(Debug)]
79pub struct CfdModel(pub Cfd);
80
81#[derive(Debug)]
82pub struct PerpetualContractModel(pub PerpetualContract);
83
84#[derive(Debug)]
85pub struct OptionSpreadModel(pub OptionSpread);
86
87#[derive(Debug)]
88pub struct TokenizedAssetModel(pub TokenizedAsset);
89
90impl<'r> FromRow<'r, PgRow> for InstrumentAnyModel {
91 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
92 let kind = row.get::<String, _>("kind");
93 if kind == "BETTING" {
94 Ok(Self(InstrumentAny::Betting(
95 BettingInstrumentModel::from_row(row).unwrap().0,
96 )))
97 } else if kind == "BINARY_OPTION" {
98 Ok(Self(InstrumentAny::BinaryOption(
99 BinaryOptionModel::from_row(row).unwrap().0,
100 )))
101 } else if kind == "CRYPTO_FUTURE" {
102 Ok(Self(InstrumentAny::CryptoFuture(
103 CryptoFutureModel::from_row(row).unwrap().0,
104 )))
105 } else if kind == "CRYPTO_OPTION" {
106 Ok(Self(InstrumentAny::CryptoOption(
107 CryptoOptionModel::from_row(row).unwrap().0,
108 )))
109 } else if kind == "CRYPTO_PERPETUAL" {
110 Ok(Self(InstrumentAny::CryptoPerpetual(
111 CryptoPerpetualModel::from_row(row).unwrap().0,
112 )))
113 } else if kind == "CURRENCY_PAIR" {
114 Ok(Self(InstrumentAny::CurrencyPair(
115 CurrencyPairModel::from_row(row).unwrap().0,
116 )))
117 } else if kind == "EQUITY" {
118 Ok(Self(InstrumentAny::Equity(
119 EquityModel::from_row(row).unwrap().0,
120 )))
121 } else if kind == "FUTURES_CONTRACT" {
122 Ok(Self(InstrumentAny::FuturesContract(
123 FuturesContractModel::from_row(row).unwrap().0,
124 )))
125 } else if kind == "FUTURES_SPREAD" {
126 Ok(Self(InstrumentAny::FuturesSpread(
127 FuturesSpreadModel::from_row(row).unwrap().0,
128 )))
129 } else if kind == "OPTION_CONTRACT" {
130 Ok(Self(InstrumentAny::OptionContract(
131 OptionContractModel::from_row(row).unwrap().0,
132 )))
133 } else if kind == "COMMODITY" {
134 Ok(Self(InstrumentAny::Commodity(
135 CommodityModel::from_row(row).unwrap().0,
136 )))
137 } else if kind == "INDEX_INSTRUMENT" {
138 Ok(Self(InstrumentAny::IndexInstrument(
139 IndexInstrumentModel::from_row(row).unwrap().0,
140 )))
141 } else if kind == "CFD" {
142 Ok(Self(InstrumentAny::Cfd(CfdModel::from_row(row).unwrap().0)))
143 } else if kind == "OPTION_SPREAD" {
144 Ok(Self(InstrumentAny::OptionSpread(
145 OptionSpreadModel::from_row(row).unwrap().0,
146 )))
147 } else if kind == "PERPETUAL_CONTRACT" {
148 Ok(Self(InstrumentAny::PerpetualContract(
149 PerpetualContractModel::from_row(row).unwrap().0,
150 )))
151 } else if kind == "TOKENIZED_ASSET" {
152 Ok(Self(InstrumentAny::TokenizedAsset(
153 TokenizedAssetModel::from_row(row).unwrap().0,
154 )))
155 } else {
156 Err(sqlx::Error::Decode(
157 format!("Unknown instrument type: {kind}").into(),
158 ))
159 }
160 }
161}
162
163impl<'r> FromRow<'r, PgRow> for BettingInstrumentModel {
165 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
166 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
167 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
168 let event_type_id = row.try_get::<i64, _>("event_type_id")? as u64;
169 let event_type_name = row
170 .try_get::<String, _>("event_type_name")
171 .map(|res| Ustr::from(res.as_str()))?;
172 let competition_id = row.try_get::<i64, _>("competition_id")? as u64;
173 let competition_name = row
174 .try_get::<String, _>("competition_name")
175 .map(|res| Ustr::from(res.as_str()))?;
176 let event_id = row.try_get::<i64, _>("event_id")? as u64;
177 let event_name = row
178 .try_get::<String, _>("event_name")
179 .map(|res| Ustr::from(res.as_str()))?;
180 let event_country_code = row
181 .try_get::<String, _>("event_country_code")
182 .map(|res| Ustr::from(res.as_str()))?;
183 let event_open_date = row
184 .try_get::<String, _>("event_open_date")
185 .map(UnixNanos::from)?;
186 let betting_type = row
187 .try_get::<String, _>("betting_type")
188 .map(|res| Ustr::from(res.as_str()))?;
189 let market_id = row
190 .try_get::<String, _>("market_id")
191 .map(|res| Ustr::from(res.as_str()))?;
192 let market_name = row
193 .try_get::<String, _>("market_name")
194 .map(|res| Ustr::from(res.as_str()))?;
195 let market_type = row
196 .try_get::<String, _>("market_type")
197 .map(|res| Ustr::from(res.as_str()))?;
198 let market_start_time = row
199 .try_get::<String, _>("market_start_time")
200 .map(UnixNanos::from)?;
201 let selection_id = row.try_get::<i64, _>("selection_id")? as u64;
202 let selection_name = row
203 .try_get::<String, _>("selection_name")
204 .map(|res| Ustr::from(res.as_str()))?;
205 let selection_handicap = row.try_get::<f64, _>("selection_handicap")?;
206 let currency = row
207 .try_get::<String, _>("quote_currency")
208 .map(Currency::from)?;
209 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
210 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
211 let price_increment = row
212 .try_get::<String, _>("price_increment")
213 .map(Price::from)?;
214 let size_increment = row
215 .try_get::<String, _>("size_increment")
216 .map(Quantity::from)?;
217 let max_quantity = row
218 .try_get::<Option<String>, _>("max_quantity")
219 .ok()
220 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
221 let min_quantity = row
222 .try_get::<Option<String>, _>("min_quantity")
223 .ok()
224 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
225 let max_notional = row
226 .try_get::<Option<String>, _>("max_notional")
227 .ok()
228 .and_then(|res| res.map(|value| Money::from(value.as_str())));
229 let min_notional = row
230 .try_get::<Option<String>, _>("min_notional")
231 .ok()
232 .and_then(|res| res.map(|value| Money::from(value.as_str())));
233 let max_price = row
234 .try_get::<Option<String>, _>("max_price")
235 .ok()
236 .and_then(|res| res.map(|value| Price::from(value.as_str())));
237 let min_price = row
238 .try_get::<Option<String>, _>("min_price")
239 .ok()
240 .and_then(|res| res.map(|value| Price::from(value.as_str())));
241 let margin_init = row
242 .try_get::<String, _>("margin_init")
243 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
244 let margin_maint = row
245 .try_get::<String, _>("margin_maint")
246 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
247 let maker_fee = row
248 .try_get::<String, _>("maker_fee")
249 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
250 let taker_fee = row
251 .try_get::<String, _>("taker_fee")
252 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
253 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
254 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
255
256 let inst = BettingInstrument::new(
257 id,
258 raw_symbol,
259 event_type_id,
260 event_type_name,
261 competition_id,
262 competition_name,
263 event_id,
264 event_name,
265 event_country_code,
266 event_open_date,
267 betting_type,
268 market_id,
269 market_name,
270 market_type,
271 market_start_time,
272 selection_id,
273 selection_name,
274 selection_handicap,
275 currency,
276 price_precision,
277 size_precision,
278 price_increment,
279 size_increment,
280 max_quantity,
281 min_quantity,
282 max_notional,
283 min_notional,
284 max_price,
285 min_price,
286 margin_init,
287 margin_maint,
288 maker_fee,
289 taker_fee,
290 None,
291 ts_event,
292 ts_init,
293 );
294 Ok(Self(inst))
295 }
296}
297
298impl<'r> FromRow<'r, PgRow> for BinaryOptionModel {
299 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
300 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
301 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
302 let asset_class = row
303 .try_get::<AssetClassModel, _>("asset_class")
304 .map(|res| res.0)?;
305 let currency = row
306 .try_get::<String, _>("quote_currency")
307 .map(Currency::from)?;
308 let activation_ns = row
309 .try_get::<String, _>("activation_ns")
310 .map(UnixNanos::from)?;
311 let expiration_ns = row
312 .try_get::<String, _>("expiration_ns")
313 .map(UnixNanos::from)?;
314 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
315 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
316 let price_increment = row
317 .try_get::<String, _>("price_increment")
318 .map(|res| Price::from_str(res.as_str()).unwrap())?;
319 let size_increment = row
320 .try_get::<String, _>("size_increment")
321 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
322 let outcome = row
323 .try_get::<Option<String>, _>("outcome")
324 .ok()
325 .and_then(|res| res.map(|value| Ustr::from(value.as_str())));
326 let description = row
327 .try_get::<Option<String>, _>("description")
328 .ok()
329 .and_then(|res| res.map(|value| Ustr::from(value.as_str())));
330 let max_quantity = row
331 .try_get::<Option<String>, _>("max_quantity")
332 .ok()
333 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
334 let min_quantity = row
335 .try_get::<Option<String>, _>("min_quantity")
336 .ok()
337 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
338 let max_notional = row
339 .try_get::<Option<String>, _>("max_notional")
340 .ok()
341 .and_then(|res| res.map(|value| Money::from(value.as_str())));
342 let min_notional = row
343 .try_get::<Option<String>, _>("min_notional")
344 .ok()
345 .and_then(|res| res.map(|value| Money::from(value.as_str())));
346 let max_price = row
347 .try_get::<Option<String>, _>("max_price")
348 .ok()
349 .and_then(|res| res.map(|value| Price::from(value.as_str())));
350 let min_price = row
351 .try_get::<Option<String>, _>("min_price")
352 .ok()
353 .and_then(|res| res.map(|value| Price::from(value.as_str())));
354 let margin_init = row
355 .try_get::<String, _>("margin_init")
356 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
357 let margin_maint = row
358 .try_get::<String, _>("margin_maint")
359 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
360 let maker_fee = row
361 .try_get::<String, _>("maker_fee")
362 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
363 let taker_fee = row
364 .try_get::<String, _>("taker_fee")
365 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
366 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
367 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
368
369 let inst = BinaryOption::new(
370 id,
371 raw_symbol,
372 asset_class,
373 currency,
374 activation_ns,
375 expiration_ns,
376 price_precision,
377 size_precision,
378 price_increment,
379 size_increment,
380 outcome,
381 description,
382 max_quantity,
383 min_quantity,
384 max_notional,
385 min_notional,
386 max_price,
387 min_price,
388 margin_init,
389 margin_maint,
390 maker_fee,
391 taker_fee,
392 None,
393 ts_event,
394 ts_init,
395 );
396 Ok(Self(inst))
397 }
398}
399
400impl<'r> FromRow<'r, PgRow> for CryptoFutureModel {
401 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
402 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
403 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
404 let underlying = row.try_get::<String, _>("underlying").map(Currency::from)?;
405 let quote_currency = row
406 .try_get::<String, _>("quote_currency")
407 .map(Currency::from)?;
408 let settlement_currency = row
409 .try_get::<String, _>("settlement_currency")
410 .map(Currency::from)?;
411 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
412 let activation_ns = row
413 .try_get::<String, _>("activation_ns")
414 .map(UnixNanos::from)?;
415 let expiration_ns = row
416 .try_get::<String, _>("expiration_ns")
417 .map(UnixNanos::from)?;
418 let price_precision = row.try_get::<i32, _>("price_precision")?;
419 let size_precision = row.try_get::<i32, _>("size_precision")?;
420 let price_increment = row
421 .try_get::<String, _>("price_increment")
422 .map(|res| Price::from_str(res.as_str()).unwrap())?;
423 let size_increment = row
424 .try_get::<String, _>("size_increment")
425 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
426 let multiplier = row
427 .try_get::<String, _>("multiplier")
428 .map(|res| Quantity::from(res.as_str()))?;
429 let lot_size = row
430 .try_get::<String, _>("lot_size")
431 .map(|res| Quantity::from(res.as_str()))?;
432 let max_quantity = row
433 .try_get::<Option<String>, _>("max_quantity")
434 .ok()
435 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
436 let min_quantity = row
437 .try_get::<Option<String>, _>("min_quantity")
438 .ok()
439 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
440 let max_notional = row
441 .try_get::<Option<String>, _>("max_notional")
442 .ok()
443 .and_then(|res| res.map(|value| Money::from(value.as_str())));
444 let min_notional = row
445 .try_get::<Option<String>, _>("min_notional")
446 .ok()
447 .and_then(|res| res.map(|value| Money::from(value.as_str())));
448 let max_price = row
449 .try_get::<Option<String>, _>("max_price")
450 .ok()
451 .and_then(|res| res.map(|value| Price::from(value.as_str())));
452 let min_price = row
453 .try_get::<Option<String>, _>("min_price")
454 .ok()
455 .and_then(|res| res.map(|value| Price::from(value.as_str())));
456 let margin_init = row
457 .try_get::<String, _>("margin_init")
458 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
459 let margin_maint = row
460 .try_get::<String, _>("margin_maint")
461 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
462 let maker_fee = row
463 .try_get::<String, _>("maker_fee")
464 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
465 let taker_fee = row
466 .try_get::<String, _>("taker_fee")
467 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
468 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
469 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
470
471 let inst = CryptoFuture::new(
472 id,
473 raw_symbol,
474 underlying,
475 quote_currency,
476 settlement_currency,
477 is_inverse,
478 activation_ns,
479 expiration_ns,
480 price_precision as u8,
481 size_precision as u8,
482 price_increment,
483 size_increment,
484 Some(multiplier),
485 Some(lot_size),
486 max_quantity,
487 min_quantity,
488 max_notional,
489 min_notional,
490 max_price,
491 min_price,
492 margin_init,
493 margin_maint,
494 maker_fee,
495 taker_fee,
496 None,
497 ts_event,
498 ts_init,
499 );
500 Ok(Self(inst))
501 }
502}
503
504impl<'r> FromRow<'r, PgRow> for CryptoOptionModel {
505 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
506 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
507 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
508 let underlying = row.try_get::<String, _>("underlying").map(Currency::from)?;
509 let quote_currency = row
510 .try_get::<String, _>("quote_currency")
511 .map(Currency::from)?;
512 let settlement_currency = row
513 .try_get::<String, _>("settlement_currency")
514 .map(Currency::from)?;
515 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
516 let option_kind = row
517 .try_get::<String, _>("option_kind")
518 .map(|res| OptionKind::from_str(res.as_str()).unwrap())?;
519 let strike_price = row
520 .try_get::<String, _>("strike_price")
521 .map(|res| Price::from_str(res.as_str()).unwrap())?;
522 let activation_ns = row
523 .try_get::<String, _>("activation_ns")
524 .map(UnixNanos::from)?;
525 let expiration_ns = row
526 .try_get::<String, _>("expiration_ns")
527 .map(UnixNanos::from)?;
528 let price_precision = row.try_get::<i32, _>("price_precision")?;
529 let size_precision = row.try_get::<i32, _>("size_precision")?;
530 let price_increment = row
531 .try_get::<String, _>("price_increment")
532 .map(|res| Price::from_str(res.as_str()).unwrap())?;
533 let size_increment = row
534 .try_get::<String, _>("size_increment")
535 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
536 let multiplier = row
537 .try_get::<String, _>("multiplier")
538 .map(|res| Quantity::from(res.as_str()))?;
539 let lot_size = row
540 .try_get::<String, _>("lot_size")
541 .map(|res| Quantity::from(res.as_str()))?;
542 let max_quantity = row
543 .try_get::<Option<String>, _>("max_quantity")
544 .ok()
545 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
546 let min_quantity = row
547 .try_get::<Option<String>, _>("min_quantity")
548 .ok()
549 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
550 let max_notional = row
551 .try_get::<Option<String>, _>("max_notional")
552 .ok()
553 .and_then(|res| res.map(|value| Money::from(value.as_str())));
554 let min_notional = row
555 .try_get::<Option<String>, _>("min_notional")
556 .ok()
557 .and_then(|res| res.map(|value| Money::from(value.as_str())));
558 let max_price = row
559 .try_get::<Option<String>, _>("max_price")
560 .ok()
561 .and_then(|res| res.map(|value| Price::from(value.as_str())));
562 let min_price = row
563 .try_get::<Option<String>, _>("min_price")
564 .ok()
565 .and_then(|res| res.map(|value| Price::from(value.as_str())));
566 let margin_init = row
567 .try_get::<String, _>("margin_init")
568 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
569 let margin_maint = row
570 .try_get::<String, _>("margin_maint")
571 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
572 let maker_fee = row
573 .try_get::<String, _>("maker_fee")
574 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
575 let taker_fee = row
576 .try_get::<String, _>("taker_fee")
577 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
578 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
579 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
580
581 let inst = CryptoOption::new(
582 id,
583 raw_symbol,
584 underlying,
585 quote_currency,
586 settlement_currency,
587 is_inverse,
588 option_kind,
589 strike_price,
590 activation_ns,
591 expiration_ns,
592 price_precision as u8,
593 size_precision as u8,
594 price_increment,
595 size_increment,
596 Some(multiplier),
597 Some(lot_size),
598 max_quantity,
599 min_quantity,
600 max_notional,
601 min_notional,
602 max_price,
603 min_price,
604 margin_init,
605 margin_maint,
606 maker_fee,
607 taker_fee,
608 None,
609 ts_event,
610 ts_init,
611 );
612 Ok(Self(inst))
613 }
614}
615
616impl<'r> FromRow<'r, PgRow> for CryptoPerpetualModel {
617 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
618 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
619 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
620 let base_currency = row
621 .try_get::<String, _>("base_currency")
622 .map(Currency::from)?;
623 let quote_currency = row
624 .try_get::<String, _>("quote_currency")
625 .map(Currency::from)?;
626 let settlement_currency = row
627 .try_get::<String, _>("settlement_currency")
628 .map(Currency::from)?;
629 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
630 let price_precision = row.try_get::<i32, _>("price_precision")?;
631 let size_precision = row.try_get::<i32, _>("size_precision")?;
632 let price_increment = row
633 .try_get::<String, _>("price_increment")
634 .map(|res| Price::from_str(res.as_str()).unwrap())?;
635 let size_increment = row
636 .try_get::<String, _>("size_increment")
637 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
638 let multiplier = row
639 .try_get::<String, _>("multiplier")
640 .map(|res| Quantity::from(res.as_str()))?;
641 let lot_size = row
642 .try_get::<String, _>("lot_size")
643 .map(|res| Quantity::from(res.as_str()))?;
644 let max_quantity = row
645 .try_get::<Option<String>, _>("max_quantity")
646 .ok()
647 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
648 let min_quantity = row
649 .try_get::<Option<String>, _>("min_quantity")
650 .ok()
651 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
652 let max_notional = row
653 .try_get::<Option<String>, _>("max_notional")
654 .ok()
655 .and_then(|res| res.map(|res| Money::from(res.as_str())));
656 let min_notional = row
657 .try_get::<Option<String>, _>("min_notional")
658 .ok()
659 .and_then(|res| res.map(|res| Money::from(res.as_str())));
660 let max_price = row
661 .try_get::<Option<String>, _>("max_price")
662 .ok()
663 .and_then(|res| res.map(|res| Price::from(res.as_str())));
664 let min_price = row
665 .try_get::<Option<String>, _>("min_price")
666 .ok()
667 .and_then(|res| res.map(|res| Price::from(res.as_str())));
668 let margin_init = row
669 .try_get::<String, _>("margin_init")
670 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
671 let margin_maint = row
672 .try_get::<String, _>("margin_maint")
673 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
674 let maker_fee = row
675 .try_get::<String, _>("maker_fee")
676 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
677 let taker_fee = row
678 .try_get::<String, _>("taker_fee")
679 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
680 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
681 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
682 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
683
684 let inst = CryptoPerpetual::new(
685 id,
686 raw_symbol,
687 base_currency,
688 quote_currency,
689 settlement_currency,
690 is_inverse,
691 price_precision as u8,
692 size_precision as u8,
693 price_increment,
694 size_increment,
695 Some(multiplier),
696 Some(lot_size),
697 max_quantity,
698 min_quantity,
699 max_notional,
700 min_notional,
701 max_price,
702 min_price,
703 margin_init,
704 margin_maint,
705 maker_fee,
706 taker_fee,
707 None,
708 ts_event,
709 ts_init,
710 );
711 Ok(Self(inst))
712 }
713}
714
715impl<'r> FromRow<'r, PgRow> for CurrencyPairModel {
716 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
717 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
718 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
719 let base_currency = row
720 .try_get::<String, _>("base_currency")
721 .map(Currency::from)?;
722 let quote_currency = row
723 .try_get::<String, _>("quote_currency")
724 .map(Currency::from)?;
725 let price_precision = row.try_get::<i32, _>("price_precision")?;
726 let size_precision = row.try_get::<i32, _>("size_precision")?;
727 let price_increment = row
728 .try_get::<String, _>("price_increment")
729 .map(|res| Price::from(res.as_str()))?;
730 let size_increment = row
731 .try_get::<String, _>("size_increment")
732 .map(|res| Quantity::from(res.as_str()))?;
733 let multiplier = row
734 .try_get::<Option<String>, _>("multiplier")
735 .ok()
736 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
737 let lot_size = row
738 .try_get::<Option<String>, _>("lot_size")
739 .ok()
740 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
741 let max_quantity = row
742 .try_get::<Option<String>, _>("max_quantity")
743 .ok()
744 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
745 let min_quantity = row
746 .try_get::<Option<String>, _>("min_quantity")
747 .ok()
748 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
749 let max_notional = row
750 .try_get::<Option<String>, _>("max_notional")
751 .ok()
752 .and_then(|res| res.map(|res| Money::from(res.as_str())));
753 let min_notional = row
754 .try_get::<Option<String>, _>("min_notional")
755 .ok()
756 .and_then(|res| res.map(|res| Money::from(res.as_str())));
757 let max_price = row
758 .try_get::<Option<String>, _>("max_price")
759 .ok()
760 .and_then(|res| res.map(|res| Price::from(res.as_str())));
761 let min_price = row
762 .try_get::<Option<String>, _>("min_price")
763 .ok()
764 .and_then(|res| res.map(|res| Price::from(res.as_str())));
765 let margin_init = row
766 .try_get::<String, _>("margin_init")
767 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
768 let margin_maint = row
769 .try_get::<String, _>("margin_maint")
770 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
771 let maker_fee = row
772 .try_get::<String, _>("maker_fee")
773 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
774 let taker_fee = row
775 .try_get::<String, _>("taker_fee")
776 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
777 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
778 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
779
780 let inst = CurrencyPair::new(
781 id,
782 raw_symbol,
783 base_currency,
784 quote_currency,
785 price_precision as u8,
786 size_precision as u8,
787 price_increment,
788 size_increment,
789 multiplier,
790 lot_size,
791 max_quantity,
792 min_quantity,
793 max_notional,
794 min_notional,
795 max_price,
796 min_price,
797 margin_init,
798 margin_maint,
799 maker_fee,
800 taker_fee,
801 None,
802 ts_event,
803 ts_init,
804 );
805 Ok(Self(inst))
806 }
807}
808
809impl<'r> FromRow<'r, PgRow> for EquityModel {
810 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
811 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
812 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
813 let isin = row
814 .try_get::<Option<String>, _>("isin")
815 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
816 let currency = row
817 .try_get::<String, _>("quote_currency")
818 .map(Currency::from)?;
819 let price_precision = row.try_get::<i32, _>("price_precision")?;
820 let price_increment = row
821 .try_get::<String, _>("price_increment")
822 .map(|res| Price::from_str(res.as_str()).unwrap())?;
823 let lot_size = row
824 .try_get::<Option<String>, _>("lot_size")
825 .map(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()))?;
826 let max_quantity = row
827 .try_get::<Option<String>, _>("max_quantity")
828 .ok()
829 .and_then(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()));
830 let min_quantity = row
831 .try_get::<Option<String>, _>("min_quantity")
832 .ok()
833 .and_then(|res| res.map(|s| Quantity::from_str(s.as_str()).unwrap()));
834 let max_price = row
835 .try_get::<Option<String>, _>("max_price")
836 .ok()
837 .and_then(|res| res.map(|s| Price::from(s.as_str())));
838 let min_price = row
839 .try_get::<Option<String>, _>("min_price")
840 .ok()
841 .and_then(|res| res.map(|s| Price::from(s.as_str())));
842 let margin_init = row
843 .try_get::<String, _>("margin_init")
844 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
845 let margin_maint = row
846 .try_get::<String, _>("margin_maint")
847 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
848 let maker_fee = row
849 .try_get::<String, _>("maker_fee")
850 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
851 let taker_fee = row
852 .try_get::<String, _>("taker_fee")
853 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
854 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
855 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
856
857 let inst = Equity::new(
858 id,
859 raw_symbol,
860 isin,
861 currency,
862 price_precision as u8,
863 price_increment,
864 lot_size,
865 max_quantity,
866 min_quantity,
867 max_price,
868 min_price,
869 margin_init,
870 margin_maint,
871 maker_fee,
872 taker_fee,
873 None,
874 ts_event,
875 ts_init,
876 );
877 Ok(Self(inst))
878 }
879}
880
881impl<'r> FromRow<'r, PgRow> for FuturesContractModel {
882 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
883 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
884 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::new)?;
885 let asset_class = row
886 .try_get::<AssetClassModel, _>("asset_class")
887 .map(|res| res.0)?;
888 let exchange = row
889 .try_get::<Option<String>, _>("exchange")
890 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
891 let underlying = row
892 .try_get::<String, _>("underlying")
893 .map(|res| Ustr::from(res.as_str()))?;
894 let currency = row
895 .try_get::<String, _>("quote_currency")
896 .map(Currency::from)?;
897 let activation_ns = row
898 .try_get::<String, _>("activation_ns")
899 .map(UnixNanos::from)?;
900 let expiration_ns = row
901 .try_get::<String, _>("expiration_ns")
902 .map(UnixNanos::from)?;
903 let price_precision = row.try_get::<i32, _>("price_precision")?;
904 let price_increment = row
905 .try_get::<String, _>("price_increment")
906 .map(|res| Price::from(res.as_str()))?;
907 let multiplier = row
908 .try_get::<String, _>("multiplier")
909 .map(|res| Quantity::from(res.as_str()))?;
910 let lot_size = row
911 .try_get::<String, _>("lot_size")
912 .map(|res| Quantity::from(res.as_str()))?;
913 let max_quantity = row
914 .try_get::<Option<String>, _>("max_quantity")
915 .ok()
916 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
917 let min_quantity = row
918 .try_get::<Option<String>, _>("min_quantity")
919 .ok()
920 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
921 let max_price = row
922 .try_get::<Option<String>, _>("max_price")
923 .ok()
924 .and_then(|res| res.map(|s| Price::from(s.as_str())));
925 let min_price = row
926 .try_get::<Option<String>, _>("min_price")
927 .ok()
928 .and_then(|res| res.map(|s| Price::from(s.as_str())));
929 let margin_init = row
930 .try_get::<String, _>("margin_init")
931 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
932 let margin_maint = row
933 .try_get::<String, _>("margin_maint")
934 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
935 let maker_fee = row
936 .try_get::<String, _>("maker_fee")
937 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
938 let taker_fee = row
939 .try_get::<String, _>("taker_fee")
940 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
941 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
942 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
943
944 let inst = FuturesContract::new(
945 id,
946 raw_symbol,
947 asset_class,
948 exchange,
949 underlying,
950 activation_ns,
951 expiration_ns,
952 currency,
953 price_precision as u8,
954 price_increment,
955 multiplier,
956 lot_size,
957 max_quantity,
958 min_quantity,
959 max_price,
960 min_price,
961 margin_init,
962 margin_maint,
963 maker_fee,
964 taker_fee,
965 None,
966 ts_event,
967 ts_init,
968 );
969 Ok(Self(inst))
970 }
971}
972
973impl<'r> FromRow<'r, PgRow> for FuturesSpreadModel {
974 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
975 todo!("Implement FromRow for FuturesSpread")
976 }
977}
978
979impl<'r> FromRow<'r, PgRow> for OptionContractModel {
980 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
981 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
982 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::new)?;
983 let asset_class = row
984 .try_get::<AssetClassModel, _>("asset_class")
985 .map(|res| res.0)?;
986 let exchange = row
987 .try_get::<Option<String>, _>("exchange")
988 .map(|res| res.map(|s| Ustr::from(s.as_str())))?;
989 let underlying = row
990 .try_get::<String, _>("underlying")
991 .map(|res| Ustr::from(res.as_str()))?;
992 let option_kind = row
993 .try_get::<String, _>("option_kind")
994 .map(|res| OptionKind::from_str(res.as_str()).unwrap())?;
995 let activation_ns = row
996 .try_get::<String, _>("activation_ns")
997 .map(UnixNanos::from)?;
998 let expiration_ns = row
999 .try_get::<String, _>("expiration_ns")
1000 .map(UnixNanos::from)?;
1001 let strike_price = row
1002 .try_get::<String, _>("strike_price")
1003 .map(|res| Price::from_str(res.as_str()).unwrap())?;
1004 let currency = row
1005 .try_get::<String, _>("quote_currency")
1006 .map(Currency::from)?;
1007 let price_precision = row.try_get::<i32, _>("price_precision").unwrap();
1008 let price_increment = row
1009 .try_get::<String, _>("price_increment")
1010 .map(|res| Price::from_str(res.as_str()).unwrap())?;
1011 let multiplier = row
1012 .try_get::<String, _>("multiplier")
1013 .map(|res| Quantity::from(res.as_str()))?;
1014 let lot_size = row
1015 .try_get::<String, _>("lot_size")
1016 .map(|res| Quantity::from(res.as_str()))
1017 .unwrap();
1018 let max_quantity = row
1019 .try_get::<Option<String>, _>("max_quantity")
1020 .ok()
1021 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
1022 let min_quantity = row
1023 .try_get::<Option<String>, _>("min_quantity")
1024 .ok()
1025 .and_then(|res| res.map(|s| Quantity::from(s.as_str())));
1026 let max_price = row
1027 .try_get::<Option<String>, _>("max_price")
1028 .ok()
1029 .and_then(|res| res.map(|s| Price::from(s.as_str())));
1030 let min_price = row
1031 .try_get::<Option<String>, _>("min_price")
1032 .ok()
1033 .and_then(|res| res.map(|s| Price::from(s.as_str())));
1034 let margin_init = row
1035 .try_get::<String, _>("margin_init")
1036 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1037 let margin_maint = row
1038 .try_get::<String, _>("margin_maint")
1039 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1040 let maker_fee = row
1041 .try_get::<String, _>("maker_fee")
1042 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1043 let taker_fee = row
1044 .try_get::<String, _>("taker_fee")
1045 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1046 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1047 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1048
1049 let inst = OptionContract::new(
1050 id,
1051 raw_symbol,
1052 asset_class,
1053 exchange,
1054 underlying,
1055 option_kind,
1056 strike_price,
1057 currency,
1058 activation_ns,
1059 expiration_ns,
1060 price_precision as u8,
1061 price_increment,
1062 multiplier,
1063 lot_size,
1064 max_quantity,
1065 min_quantity,
1066 max_price,
1067 min_price,
1068 margin_init,
1069 margin_maint,
1070 maker_fee,
1071 taker_fee,
1072 None,
1073 ts_event,
1074 ts_init,
1075 );
1076 Ok(Self(inst))
1077 }
1078}
1079
1080impl<'r> FromRow<'r, PgRow> for CommodityModel {
1081 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
1082 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
1083 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
1084 let asset_class = row
1085 .try_get::<AssetClassModel, _>("asset_class")
1086 .map(|res| res.0)?;
1087 let quote_currency = row
1088 .try_get::<String, _>("quote_currency")
1089 .map(Currency::from)?;
1090 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
1091 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
1092 let price_increment = row
1093 .try_get::<String, _>("price_increment")
1094 .map(|res| Price::from_str(res.as_str()).unwrap())?;
1095 let size_increment = row
1096 .try_get::<String, _>("size_increment")
1097 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
1098 let lot_size = row
1099 .try_get::<Option<String>, _>("lot_size")
1100 .ok()
1101 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1102 let max_quantity = row
1103 .try_get::<Option<String>, _>("max_quantity")
1104 .ok()
1105 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1106 let min_quantity = row
1107 .try_get::<Option<String>, _>("min_quantity")
1108 .ok()
1109 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1110 let max_notional = row
1111 .try_get::<Option<String>, _>("max_notional")
1112 .ok()
1113 .and_then(|res| res.map(|value| Money::from(value.as_str())));
1114 let min_notional = row
1115 .try_get::<Option<String>, _>("min_notional")
1116 .ok()
1117 .and_then(|res| res.map(|value| Money::from(value.as_str())));
1118 let max_price = row
1119 .try_get::<Option<String>, _>("max_price")
1120 .ok()
1121 .and_then(|res| res.map(|value| Price::from(value.as_str())));
1122 let min_price = row
1123 .try_get::<Option<String>, _>("min_price")
1124 .ok()
1125 .and_then(|res| res.map(|value| Price::from(value.as_str())));
1126 let margin_init = row
1127 .try_get::<String, _>("margin_init")
1128 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1129 let margin_maint = row
1130 .try_get::<String, _>("margin_maint")
1131 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1132 let maker_fee = row
1133 .try_get::<String, _>("maker_fee")
1134 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1135 let taker_fee = row
1136 .try_get::<String, _>("taker_fee")
1137 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1138 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1139 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1140
1141 let inst = Commodity::new(
1142 id,
1143 raw_symbol,
1144 asset_class,
1145 quote_currency,
1146 price_precision,
1147 size_precision,
1148 price_increment,
1149 size_increment,
1150 lot_size,
1151 max_quantity,
1152 min_quantity,
1153 max_notional,
1154 min_notional,
1155 max_price,
1156 min_price,
1157 margin_init,
1158 margin_maint,
1159 maker_fee,
1160 taker_fee,
1161 None,
1162 ts_event,
1163 ts_init,
1164 );
1165 Ok(Self(inst))
1166 }
1167}
1168
1169impl<'r> FromRow<'r, PgRow> for IndexInstrumentModel {
1170 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
1171 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
1172 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
1173 let currency = row
1174 .try_get::<String, _>("quote_currency")
1175 .map(Currency::from)?;
1176 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
1177 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
1178 let price_increment = row
1179 .try_get::<String, _>("price_increment")
1180 .map(|res| Price::from_str(res.as_str()).unwrap())?;
1181 let size_increment = row
1182 .try_get::<String, _>("size_increment")
1183 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
1184 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1185 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1186
1187 let inst = IndexInstrument::new(
1188 id,
1189 raw_symbol,
1190 currency,
1191 price_precision,
1192 size_precision,
1193 price_increment,
1194 size_increment,
1195 None,
1196 ts_event,
1197 ts_init,
1198 );
1199 Ok(Self(inst))
1200 }
1201}
1202
1203impl<'r> FromRow<'r, PgRow> for CfdModel {
1204 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
1205 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
1206 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
1207 let asset_class = row
1208 .try_get::<AssetClassModel, _>("asset_class")
1209 .map(|res| res.0)?;
1210 let base_currency = row
1211 .try_get::<Option<String>, _>("base_currency")
1212 .ok()
1213 .and_then(|res| res.map(Currency::from));
1214 let quote_currency = row
1215 .try_get::<String, _>("quote_currency")
1216 .map(Currency::from)?;
1217 let price_precision = row.try_get::<i32, _>("price_precision")? as u8;
1218 let size_precision = row.try_get::<i32, _>("size_precision")? as u8;
1219 let price_increment = row
1220 .try_get::<String, _>("price_increment")
1221 .map(|res| Price::from_str(res.as_str()).unwrap())?;
1222 let size_increment = row
1223 .try_get::<String, _>("size_increment")
1224 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
1225 let lot_size = row
1226 .try_get::<Option<String>, _>("lot_size")
1227 .ok()
1228 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1229 let max_quantity = row
1230 .try_get::<Option<String>, _>("max_quantity")
1231 .ok()
1232 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1233 let min_quantity = row
1234 .try_get::<Option<String>, _>("min_quantity")
1235 .ok()
1236 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1237 let max_notional = row
1238 .try_get::<Option<String>, _>("max_notional")
1239 .ok()
1240 .and_then(|res| res.map(|value| Money::from(value.as_str())));
1241 let min_notional = row
1242 .try_get::<Option<String>, _>("min_notional")
1243 .ok()
1244 .and_then(|res| res.map(|value| Money::from(value.as_str())));
1245 let max_price = row
1246 .try_get::<Option<String>, _>("max_price")
1247 .ok()
1248 .and_then(|res| res.map(|value| Price::from(value.as_str())));
1249 let min_price = row
1250 .try_get::<Option<String>, _>("min_price")
1251 .ok()
1252 .and_then(|res| res.map(|value| Price::from(value.as_str())));
1253 let margin_init = row
1254 .try_get::<String, _>("margin_init")
1255 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1256 let margin_maint = row
1257 .try_get::<String, _>("margin_maint")
1258 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1259 let maker_fee = row
1260 .try_get::<String, _>("maker_fee")
1261 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1262 let taker_fee = row
1263 .try_get::<String, _>("taker_fee")
1264 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1265 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1266 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1267
1268 let inst = Cfd::new(
1269 id,
1270 raw_symbol,
1271 asset_class,
1272 base_currency,
1273 quote_currency,
1274 price_precision,
1275 size_precision,
1276 price_increment,
1277 size_increment,
1278 lot_size,
1279 max_quantity,
1280 min_quantity,
1281 max_notional,
1282 min_notional,
1283 max_price,
1284 min_price,
1285 margin_init,
1286 margin_maint,
1287 maker_fee,
1288 taker_fee,
1289 None,
1290 ts_event,
1291 ts_init,
1292 );
1293 Ok(Self(inst))
1294 }
1295}
1296
1297impl<'r> FromRow<'r, PgRow> for PerpetualContractModel {
1298 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
1299 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
1300 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
1301 let underlying = row
1302 .try_get::<String, _>("underlying")
1303 .map(|res| Ustr::from(res.as_str()))?;
1304 let asset_class = row
1305 .try_get::<AssetClassModel, _>("asset_class")
1306 .map(|res| res.0)?;
1307 let base_currency = row
1308 .try_get::<Option<String>, _>("base_currency")
1309 .ok()
1310 .and_then(|res| res.map(Currency::from));
1311 let quote_currency = row
1312 .try_get::<String, _>("quote_currency")
1313 .map(Currency::from)?;
1314 let settlement_currency = row
1315 .try_get::<String, _>("settlement_currency")
1316 .map(Currency::from)?;
1317 let is_inverse = row.try_get::<bool, _>("is_inverse")?;
1318 let price_precision = row.try_get::<i32, _>("price_precision")?;
1319 let size_precision = row.try_get::<i32, _>("size_precision")?;
1320 let price_increment = row
1321 .try_get::<String, _>("price_increment")
1322 .map(|res| Price::from_str(res.as_str()).unwrap())?;
1323 let size_increment = row
1324 .try_get::<String, _>("size_increment")
1325 .map(|res| Quantity::from_str(res.as_str()).unwrap())?;
1326 let multiplier = row
1327 .try_get::<String, _>("multiplier")
1328 .map(|res| Quantity::from(res.as_str()))?;
1329 let lot_size = row
1330 .try_get::<String, _>("lot_size")
1331 .map(|res| Quantity::from(res.as_str()))?;
1332 let max_quantity = row
1333 .try_get::<Option<String>, _>("max_quantity")
1334 .ok()
1335 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1336 let min_quantity = row
1337 .try_get::<Option<String>, _>("min_quantity")
1338 .ok()
1339 .and_then(|res| res.map(|value| Quantity::from(value.as_str())));
1340 let max_notional = row
1341 .try_get::<Option<String>, _>("max_notional")
1342 .ok()
1343 .and_then(|res| res.map(|value| Money::from(value.as_str())));
1344 let min_notional = row
1345 .try_get::<Option<String>, _>("min_notional")
1346 .ok()
1347 .and_then(|res| res.map(|value| Money::from(value.as_str())));
1348 let max_price = row
1349 .try_get::<Option<String>, _>("max_price")
1350 .ok()
1351 .and_then(|res| res.map(|value| Price::from(value.as_str())));
1352 let min_price = row
1353 .try_get::<Option<String>, _>("min_price")
1354 .ok()
1355 .and_then(|res| res.map(|value| Price::from(value.as_str())));
1356 let margin_init = row
1357 .try_get::<String, _>("margin_init")
1358 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1359 let margin_maint = row
1360 .try_get::<String, _>("margin_maint")
1361 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1362 let maker_fee = row
1363 .try_get::<String, _>("maker_fee")
1364 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1365 let taker_fee = row
1366 .try_get::<String, _>("taker_fee")
1367 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1368 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1369 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1370
1371 let inst = PerpetualContract::new(
1372 id,
1373 raw_symbol,
1374 underlying,
1375 asset_class,
1376 base_currency,
1377 quote_currency,
1378 settlement_currency,
1379 is_inverse,
1380 price_precision as u8,
1381 size_precision as u8,
1382 price_increment,
1383 size_increment,
1384 Some(multiplier),
1385 Some(lot_size),
1386 max_quantity,
1387 min_quantity,
1388 max_notional,
1389 min_notional,
1390 max_price,
1391 min_price,
1392 margin_init,
1393 margin_maint,
1394 maker_fee,
1395 taker_fee,
1396 None,
1397 ts_event,
1398 ts_init,
1399 );
1400 Ok(Self(inst))
1401 }
1402}
1403
1404impl<'r> FromRow<'r, PgRow> for OptionSpreadModel {
1405 fn from_row(_row: &'r PgRow) -> Result<Self, sqlx::Error> {
1406 todo!("Implement FromRow for OptionSpread")
1407 }
1408}
1409
1410impl<'r> FromRow<'r, PgRow> for TokenizedAssetModel {
1411 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
1412 let id = row.try_get::<String, _>("id").map(InstrumentId::from)?;
1413 let raw_symbol = row.try_get::<String, _>("raw_symbol").map(Symbol::from)?;
1414 let asset_class = row.try_get::<String, _>("asset_class").and_then(|res| {
1415 AssetClass::from_str(res.as_str()).map_err(|e| {
1416 sqlx::Error::Decode(format!("Invalid asset class '{res}': {e}").into())
1417 })
1418 })?;
1419 let base_currency = row
1422 .try_get::<String, _>("base_currency")
1423 .map(|code| Currency::get_or_create_crypto(&code))?;
1424 let quote_currency = row
1425 .try_get::<String, _>("quote_currency")
1426 .map(Currency::from)?;
1427 let isin = row
1428 .try_get::<Option<String>, _>("isin")
1429 .ok()
1430 .and_then(|res| res.map(|s| Ustr::from(s.as_str())));
1431 let price_precision = row.try_get::<i32, _>("price_precision")?;
1432 let size_precision = row.try_get::<i32, _>("size_precision")?;
1433 let price_increment = row
1434 .try_get::<String, _>("price_increment")
1435 .map(|res| Price::from(res.as_str()))?;
1436 let size_increment = row
1437 .try_get::<String, _>("size_increment")
1438 .map(|res| Quantity::from(res.as_str()))?;
1439 let multiplier = row
1440 .try_get::<Option<String>, _>("multiplier")
1441 .ok()
1442 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
1443 let lot_size = row
1444 .try_get::<Option<String>, _>("lot_size")
1445 .ok()
1446 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
1447 let max_quantity = row
1448 .try_get::<Option<String>, _>("max_quantity")
1449 .ok()
1450 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
1451 let min_quantity = row
1452 .try_get::<Option<String>, _>("min_quantity")
1453 .ok()
1454 .and_then(|res| res.map(|res| Quantity::from(res.as_str())));
1455 let max_notional = row
1456 .try_get::<Option<String>, _>("max_notional")
1457 .ok()
1458 .and_then(|res| res.map(|res| Money::from(res.as_str())));
1459 let min_notional = row
1460 .try_get::<Option<String>, _>("min_notional")
1461 .ok()
1462 .and_then(|res| res.map(|res| Money::from(res.as_str())));
1463 let max_price = row
1464 .try_get::<Option<String>, _>("max_price")
1465 .ok()
1466 .and_then(|res| res.map(|res| Price::from(res.as_str())));
1467 let min_price = row
1468 .try_get::<Option<String>, _>("min_price")
1469 .ok()
1470 .and_then(|res| res.map(|res| Price::from(res.as_str())));
1471 let margin_init = row
1472 .try_get::<String, _>("margin_init")
1473 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1474 let margin_maint = row
1475 .try_get::<String, _>("margin_maint")
1476 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1477 let maker_fee = row
1478 .try_get::<String, _>("maker_fee")
1479 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1480 let taker_fee = row
1481 .try_get::<String, _>("taker_fee")
1482 .map(|res| Some(Decimal::from_str(res.as_str()).unwrap()))?;
1483 let ts_event = row.try_get::<String, _>("ts_event").map(UnixNanos::from)?;
1484 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
1485
1486 let inst = TokenizedAsset::new(
1487 id,
1488 raw_symbol,
1489 asset_class,
1490 base_currency,
1491 quote_currency,
1492 isin,
1493 price_precision as u8,
1494 size_precision as u8,
1495 price_increment,
1496 size_increment,
1497 multiplier,
1498 lot_size,
1499 max_quantity,
1500 min_quantity,
1501 max_notional,
1502 min_notional,
1503 max_price,
1504 min_price,
1505 margin_init,
1506 margin_maint,
1507 maker_fee,
1508 taker_fee,
1509 None,
1510 ts_event,
1511 ts_init,
1512 );
1513 Ok(Self(inst))
1514 }
1515}