nautilus_infrastructure/sql/models/
data.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.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
28pub struct QuoteTickModel(pub QuoteTick);
29pub struct TradeTickModel(pub TradeTick);
30pub struct BarModel(pub Bar);
31
32impl<'r> FromRow<'r, PgRow> for QuoteTickModel {
33    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
34        let instrument_id = row
35            .try_get::<&str, _>("instrument_id")
36            .map(InstrumentId::from)?;
37        let bid_price = row.try_get::<&str, _>("bid_price").map(Price::from)?;
38        let ask_price = row.try_get::<&str, _>("ask_price").map(Price::from)?;
39        let bid_size = row.try_get::<&str, _>("bid_size").map(Quantity::from)?;
40        let ask_size = row.try_get::<&str, _>("ask_size").map(Quantity::from)?;
41        let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
42        let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
43        let quote = QuoteTick::new(
44            instrument_id,
45            bid_price,
46            ask_price,
47            bid_size,
48            ask_size,
49            ts_event,
50            ts_init,
51        );
52        Ok(QuoteTickModel(quote))
53    }
54}
55
56impl<'r> FromRow<'r, PgRow> for TradeTickModel {
57    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
58        let instrument_id = row
59            .try_get::<&str, _>("instrument_id")
60            .map(InstrumentId::from)?;
61        let price = row.try_get::<&str, _>("price").map(Price::from)?;
62        let size = row.try_get::<&str, _>("quantity").map(Quantity::from)?;
63        let aggressor_side = row
64            .try_get::<AggressorSideModel, _>("aggressor_side")
65            .map(|x| x.0)?;
66        let trade_id = row
67            .try_get::<&str, _>("venue_trade_id")
68            .map(TradeId::from)?;
69        let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
70        let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
71        let trade = TradeTick::new(
72            instrument_id,
73            price,
74            size,
75            aggressor_side,
76            trade_id,
77            ts_event,
78            ts_init,
79        );
80        Ok(TradeTickModel(trade))
81    }
82}
83
84impl<'r> FromRow<'r, PgRow> for BarModel {
85    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
86        let instrument_id = row
87            .try_get::<&str, _>("instrument_id")
88            .map(InstrumentId::from)?;
89        let step = row.try_get::<i32, _>("step")?;
90        let price_type = row
91            .try_get::<PriceTypeModel, _>("price_type")
92            .map(|x| x.0)?;
93        let bar_aggregation = row
94            .try_get::<BarAggregationModel, _>("bar_aggregation")
95            .map(|x| x.0)?;
96        let aggregation_source = row
97            .try_get::<AggregationSourceModel, _>("aggregation_source")
98            .map(|x| x.0)?;
99        let bar_type = BarType::new(
100            instrument_id,
101            BarSpecification::new(step as usize, bar_aggregation, price_type),
102            aggregation_source,
103        );
104        let open = row.try_get::<&str, _>("open").map(Price::from)?;
105        let high = row.try_get::<&str, _>("high").map(Price::from)?;
106        let low = row.try_get::<&str, _>("low").map(Price::from)?;
107        let close = row.try_get::<&str, _>("close").map(Price::from)?;
108        let volume = row.try_get::<&str, _>("volume").map(Quantity::from)?;
109        let ts_event = row.try_get::<&str, _>("ts_event").map(UnixNanos::from)?;
110        let ts_init = row.try_get::<&str, _>("ts_init").map(UnixNanos::from)?;
111        let bar = Bar::new(bar_type, open, high, low, close, volume, ts_event, ts_init);
112        Ok(BarModel(bar))
113    }
114}