nautilus_infrastructure/sql/models/
positions.rs1use std::str::FromStr;
17
18use nautilus_core::UnixNanos;
19use nautilus_model::{
20 enums::{OrderSide, PositionSide},
21 events::PositionSnapshot,
22 identifiers::{AccountId, ClientOrderId, InstrumentId, PositionId, StrategyId, TraderId},
23 types::{Currency, Money, Quantity},
24};
25use sqlx::{FromRow, Row, postgres::PgRow};
26
27#[derive(Debug)]
28pub struct PositionSnapshotModel(pub PositionSnapshot);
29
30impl<'r> FromRow<'r, PgRow> for PositionSnapshotModel {
31 fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
32 let id = row.try_get::<&str, _>("id").map(PositionId::from)?;
33 let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
34 let strategy_id = row
35 .try_get::<&str, _>("strategy_id")
36 .map(StrategyId::from)?;
37 let instrument_id = row
38 .try_get::<&str, _>("instrument_id")
39 .map(InstrumentId::from)?;
40 let account_id = row.try_get::<&str, _>("account_id").map(AccountId::from)?;
41 let opening_order_id = row
42 .try_get::<&str, _>("opening_order_id")
43 .map(ClientOrderId::from)?;
44 let closing_order_id = row
45 .try_get::<Option<&str>, _>("closing_order_id")
46 .ok()
47 .and_then(|x| x.map(ClientOrderId::from));
48 let entry = row
49 .try_get::<&str, _>("entry")
50 .map(OrderSide::from_str)?
51 .expect("Invalid `OrderSide`");
52 let side = row
53 .try_get::<&str, _>("side")
54 .map(PositionSide::from_str)?
55 .expect("Invalid `PositionSide`");
56 let signed_qty = row.try_get::<f64, _>("signed_qty")?;
57 let quantity = row.try_get::<&str, _>("quantity").map(Quantity::from)?;
58 let peak_qty = row.try_get::<&str, _>("peak_qty").map(Quantity::from)?;
59 let quote_currency = row
60 .try_get::<&str, _>("quote_currency")
61 .map(Currency::from)?;
62 let base_currency = row
63 .try_get::<Option<&str>, _>("base_currency")
64 .ok()
65 .and_then(|x| x.map(Currency::from));
66 let settlement_currency = row
67 .try_get::<&str, _>("settlement_currency")
68 .map(Currency::from)?;
69 let avg_px_open = row.try_get::<f64, _>("avg_px_open")?;
70 let avg_px_close = row.try_get::<Option<f64>, _>("avg_px_close")?;
71 let realized_return = row.try_get::<Option<f64>, _>("realized_return")?;
72 let realized_pnl = row.try_get::<&str, _>("realized_pnl").map(Money::from)?;
73 let unrealized_pnl = row
74 .try_get::<Option<&str>, _>("unrealized_pnl")
75 .ok()
76 .and_then(|x| x.map(Money::from));
77 let commissions = row
78 .try_get::<Option<Vec<String>>, _>("commissions")?
79 .map_or_else(Vec::new, |c| {
80 c.into_iter().map(|s| Money::from(&s)).collect()
81 });
82 let duration_ns: Option<u64> = row
83 .try_get::<Option<i64>, _>("duration_ns")?
84 .map(|value| value as u64);
85 let ts_opened = row.try_get::<String, _>("ts_opened").map(UnixNanos::from)?;
86 let ts_closed: Option<UnixNanos> = row
87 .try_get::<Option<String>, _>("ts_closed")?
88 .map(UnixNanos::from);
89 let ts_init = row.try_get::<String, _>("ts_init").map(UnixNanos::from)?;
90 let ts_last = row.try_get::<String, _>("ts_last").map(UnixNanos::from)?;
91
92 let snapshot = PositionSnapshot {
93 trader_id,
94 strategy_id,
95 instrument_id,
96 position_id: id,
97 account_id,
98 opening_order_id,
99 closing_order_id,
100 entry,
101 side,
102 signed_qty,
103 quantity,
104 peak_qty,
105 quote_currency,
106 base_currency,
107 settlement_currency,
108 avg_px_open,
109 avg_px_close,
110 realized_return,
111 realized_pnl: Some(realized_pnl), unrealized_pnl,
113 commissions,
114 duration_ns,
115 ts_opened,
116 ts_closed,
117 ts_last,
118 ts_init,
119 };
120
121 Ok(Self(snapshot))
122 }
123}