Skip to main content

nautilus_infrastructure/sql/models/
data.rs

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