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