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