nautilus_infrastructure/sql/models/
data.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Posei Systems Pty Ltd. All rights reserved.
3//  https://poseitrader.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use nautilus_core::UnixNanos;
17use nautilus_model::{
18    data::{Bar, BarSpecification, BarType, QuoteTick, TradeTick},
19    identifiers::{InstrumentId, TradeId},
20    types::{Price, Quantity},
21};
22use sqlx::{Error, FromRow, Row, postgres::PgRow};
23
24use crate::sql::models::enums::{
25    AggregationSourceModel, AggressorSideModel, BarAggregationModel, PriceTypeModel,
26};
27
28#[derive(Debug)]
29pub struct QuoteTickModel(pub QuoteTick);
30
31#[derive(Debug)]
32pub struct TradeTickModel(pub TradeTick);
33
34#[derive(Debug)]
35pub struct BarModel(pub Bar);
36
37impl<'r> FromRow<'r, PgRow> for QuoteTickModel {
38    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
39        let instrument_id = row
40            .try_get::<&str, _>("instrument_id")
41            .map(InstrumentId::from)?;
42        let bid_price = row.try_get::<&str, _>("bid_price").map(Price::from)?;
43        let ask_price = row.try_get::<&str, _>("ask_price").map(Price::from)?;
44        let bid_size = row.try_get::<&str, _>("bid_size").map(Quantity::from)?;
45        let ask_size = row.try_get::<&str, _>("ask_size").map(Quantity::from)?;
46        let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
47        let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
48        let quote = QuoteTick::new(
49            instrument_id,
50            bid_price,
51            ask_price,
52            bid_size,
53            ask_size,
54            ts_event,
55            ts_init,
56        );
57        Ok(Self(quote))
58    }
59}
60
61impl<'r> FromRow<'r, PgRow> for TradeTickModel {
62    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
63        let instrument_id = row
64            .try_get::<&str, _>("instrument_id")
65            .map(InstrumentId::from)?;
66        let price = row.try_get::<&str, _>("price").map(Price::from)?;
67        let size = row.try_get::<&str, _>("quantity").map(Quantity::from)?;
68        let aggressor_side = row
69            .try_get::<AggressorSideModel, _>("aggressor_side")
70            .map(|x| x.0)?;
71        let trade_id = row
72            .try_get::<&str, _>("venue_trade_id")
73            .map(TradeId::from)?;
74        let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
75        let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
76        let trade = TradeTick::new(
77            instrument_id,
78            price,
79            size,
80            aggressor_side,
81            trade_id,
82            ts_event,
83            ts_init,
84        );
85        Ok(Self(trade))
86    }
87}
88
89impl<'r> FromRow<'r, PgRow> for BarModel {
90    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
91        let instrument_id = row
92            .try_get::<&str, _>("instrument_id")
93            .map(InstrumentId::from)?;
94        let step = row.try_get::<i32, _>("step")?;
95        let price_type = row
96            .try_get::<PriceTypeModel, _>("price_type")
97            .map(|x| x.0)?;
98        let bar_aggregation = row
99            .try_get::<BarAggregationModel, _>("bar_aggregation")
100            .map(|x| x.0)?;
101        let aggregation_source = row
102            .try_get::<AggregationSourceModel, _>("aggregation_source")
103            .map(|x| x.0)?;
104        let bar_type = BarType::new(
105            instrument_id,
106            BarSpecification::new(step as usize, bar_aggregation, price_type),
107            aggregation_source,
108        );
109        let open = row.try_get::<&str, _>("open").map(Price::from)?;
110        let high = row.try_get::<&str, _>("high").map(Price::from)?;
111        let low = row.try_get::<&str, _>("low").map(Price::from)?;
112        let close = row.try_get::<&str, _>("close").map(Price::from)?;
113        let volume = row.try_get::<&str, _>("volume").map(Quantity::from)?;
114        let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
115        let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
116        let bar = Bar::new(bar_type, open, high, low, close, volume, ts_event, ts_init);
117        Ok(Self(bar))
118    }
119}