Skip to main content

nautilus_architect_ax/http/
query.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
16//! Request parameter structures for the Ax REST API.
17//!
18//! Each struct corresponds to an Ax REST endpoint and is annotated
19//! using `serde` so that it can be serialized directly into the query string
20//! or request body expected by the exchange.
21//!
22//! Parameter structs are built using the builder pattern and then passed to
23//! `AxRawHttpClient` methods where they are automatically serialized.
24
25use serde::{Deserialize, Serialize};
26use ustr::Ustr;
27
28use crate::common::enums::{AxCandleWidth, AxOrderStatus};
29
30/// Parameters for the GET /ticker endpoint.
31///
32/// # References
33/// - <https://docs.architect.exchange/api-reference/marketdata/get-ticker>
34#[derive(Clone, Debug, Deserialize, Serialize)]
35pub struct GetTickerParams {
36    /// Instrument symbol, e.g. "GBPUSD-PERP", "EURUSD-PERP".
37    pub symbol: Ustr,
38}
39
40impl GetTickerParams {
41    /// Creates a new [`GetTickerParams`] with the given symbol.
42    #[must_use]
43    pub fn new(symbol: Ustr) -> Self {
44        Self { symbol }
45    }
46}
47
48/// Parameters for the GET /instrument endpoint.
49///
50/// # References
51/// - <https://docs.architect.exchange/api-reference/symbols-instruments/get-instrument>
52#[derive(Clone, Debug, Deserialize, Serialize)]
53pub struct GetInstrumentParams {
54    /// Instrument symbol, e.g. "GBPUSD-PERP", "EURUSD-PERP".
55    pub symbol: Ustr,
56}
57
58impl GetInstrumentParams {
59    /// Creates a new [`GetInstrumentParams`] with the given symbol.
60    #[must_use]
61    pub fn new(symbol: Ustr) -> Self {
62        Self { symbol }
63    }
64}
65
66/// Parameters for the GET /candles endpoint.
67///
68/// # References
69/// - <https://docs.architect.exchange/api-reference/marketdata/get-candles>
70#[derive(Clone, Debug, Deserialize, Serialize)]
71pub struct GetCandlesParams {
72    /// Instrument symbol.
73    pub symbol: Ustr,
74    /// Start timestamp in nanoseconds.
75    pub start_timestamp_ns: i64,
76    /// End timestamp in nanoseconds.
77    pub end_timestamp_ns: i64,
78    /// Candle width/interval.
79    pub candle_width: AxCandleWidth,
80}
81
82impl GetCandlesParams {
83    /// Creates a new [`GetCandlesParams`].
84    #[must_use]
85    pub fn new(
86        symbol: Ustr,
87        start_timestamp_ns: i64,
88        end_timestamp_ns: i64,
89        candle_width: AxCandleWidth,
90    ) -> Self {
91        Self {
92            symbol,
93            start_timestamp_ns,
94            end_timestamp_ns,
95            candle_width,
96        }
97    }
98}
99
100/// Parameters for the GET /candles/current and GET /candles/last endpoints.
101///
102/// # References
103/// - <https://docs.architect.exchange/api-reference/marketdata/get-current-candle>
104/// - <https://docs.architect.exchange/api-reference/marketdata/get-last-candle>
105#[derive(Clone, Debug, Deserialize, Serialize)]
106pub struct GetCandleParams {
107    /// Instrument symbol.
108    pub symbol: Ustr,
109    /// Candle width/interval.
110    pub candle_width: AxCandleWidth,
111}
112
113impl GetCandleParams {
114    /// Creates a new [`GetCandleParams`].
115    #[must_use]
116    pub fn new(symbol: Ustr, candle_width: AxCandleWidth) -> Self {
117        Self {
118            symbol,
119            candle_width,
120        }
121    }
122}
123
124/// Parameters for the GET /funding-rates endpoint.
125///
126/// # References
127/// - <https://docs.architect.exchange/api-reference/marketdata/get-funding-rates>
128#[derive(Clone, Debug, Deserialize, Serialize)]
129pub struct GetFundingRatesParams {
130    /// Instrument symbol.
131    pub symbol: Ustr,
132    /// Start timestamp in nanoseconds.
133    pub start_timestamp_ns: i64,
134    /// End timestamp in nanoseconds.
135    pub end_timestamp_ns: i64,
136}
137
138impl GetFundingRatesParams {
139    /// Creates a new [`GetFundingRatesParams`].
140    #[must_use]
141    pub fn new(symbol: Ustr, start_timestamp_ns: i64, end_timestamp_ns: i64) -> Self {
142        Self {
143            symbol,
144            start_timestamp_ns,
145            end_timestamp_ns,
146        }
147    }
148}
149
150/// Parameters for the GET /transactions endpoint.
151///
152/// # References
153/// - <https://docs.architect.exchange/api-reference/portfolio-management/get-transactions>
154#[derive(Clone, Debug, Deserialize, Serialize)]
155pub struct GetTransactionsParams {
156    /// Transaction types to filter by.
157    pub transaction_types: Vec<String>,
158}
159
160impl GetTransactionsParams {
161    /// Creates a new [`GetTransactionsParams`].
162    #[must_use]
163    pub fn new(transaction_types: Vec<String>) -> Self {
164        Self { transaction_types }
165    }
166}
167
168/// Parameters for the GET /trades endpoint.
169///
170/// # References
171/// - <https://docs.architect.exchange/api-reference/market-data/get-trades>
172#[derive(Clone, Debug, Deserialize, Serialize)]
173pub struct GetTradesParams {
174    /// Instrument symbol, e.g. "BTC-PERP".
175    pub symbol: Ustr,
176    /// Maximum number of trades to return (max 100, default 10).
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub limit: Option<i32>,
179}
180
181impl GetTradesParams {
182    /// Creates a new [`GetTradesParams`].
183    #[must_use]
184    pub fn new(symbol: Ustr, limit: Option<i32>) -> Self {
185        Self { symbol, limit }
186    }
187}
188
189/// Parameters for the GET /book endpoint.
190///
191/// # References
192/// - <https://docs.architect.exchange/api-reference/market-data/get-book>
193#[derive(Clone, Debug, Deserialize, Serialize)]
194pub struct GetBookParams {
195    /// Instrument symbol, e.g. "BTC-PERP".
196    pub symbol: Ustr,
197    /// Book depth level: 2 (aggregated) or 3 (individual orders). Defaults to 2.
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub level: Option<i32>,
200}
201
202impl GetBookParams {
203    /// Creates a new [`GetBookParams`].
204    #[must_use]
205    pub fn new(symbol: Ustr, level: Option<i32>) -> Self {
206        Self { symbol, level }
207    }
208}
209
210/// Parameters for the GET /order-status endpoint.
211///
212/// Exactly one of `order_id` or `client_order_id` must be provided.
213///
214/// # References
215/// - <https://docs.architect.exchange/api-reference/order-management/get-order-status>
216#[derive(Clone, Debug, Deserialize, Serialize)]
217pub struct GetOrderStatusParams {
218    /// Order ID (e.g. "O-01ARZ3NDEKTSV4RRFFQ69G5FAV").
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub order_id: Option<String>,
221    /// Client order ID (64-bit integer).
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub client_order_id: Option<u64>,
224}
225
226impl GetOrderStatusParams {
227    /// Creates params to look up by venue order ID.
228    #[must_use]
229    pub fn by_order_id(order_id: impl Into<String>) -> Self {
230        Self {
231            order_id: Some(order_id.into()),
232            client_order_id: None,
233        }
234    }
235
236    /// Creates params to look up by client order ID.
237    #[must_use]
238    pub fn by_client_order_id(cid: u64) -> Self {
239        Self {
240            order_id: None,
241            client_order_id: Some(cid),
242        }
243    }
244}
245
246/// Parameters for the GET /orders endpoint.
247///
248/// # References
249/// - <https://docs.architect.exchange/api-reference/order-management/get-orders>
250#[derive(Clone, Debug, Default, Deserialize, Serialize)]
251pub struct GetOrdersParams {
252    /// Filter by trading symbol.
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub symbol: Option<Ustr>,
255    /// Beginning of time range (ISO 8601).
256    #[serde(skip_serializing_if = "Option::is_none")]
257    pub start_time: Option<String>,
258    /// End of time range (ISO 8601).
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub end_time: Option<String>,
261    /// Maximum results returned.
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub limit: Option<i32>,
264    /// Pagination offset.
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub offset: Option<i32>,
267    /// Filter by order state.
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub order_state: Option<AxOrderStatus>,
270}
271
272impl GetOrdersParams {
273    /// Creates a new empty [`GetOrdersParams`].
274    #[must_use]
275    pub fn new() -> Self {
276        Self::default()
277    }
278}
279
280#[cfg(test)]
281mod tests {
282    use rstest::rstest;
283    use ustr::Ustr;
284
285    use super::*;
286
287    #[rstest]
288    fn test_get_ticker_params_serialization() {
289        let params = GetTickerParams::new(Ustr::from("GBPUSD-PERP"));
290        let qs = serde_urlencoded::to_string(&params).unwrap();
291        assert_eq!(qs, "symbol=GBPUSD-PERP");
292    }
293
294    #[rstest]
295    fn test_get_instrument_params_serialization() {
296        let params = GetInstrumentParams::new(Ustr::from("EURUSD-PERP"));
297        let qs = serde_urlencoded::to_string(&params).unwrap();
298        assert_eq!(qs, "symbol=EURUSD-PERP");
299    }
300
301    #[rstest]
302    fn test_get_candles_params_serialization() {
303        let params = GetCandlesParams::new(
304            Ustr::from("GBPUSD-PERP"),
305            1000000000,
306            2000000000,
307            AxCandleWidth::Minutes1,
308        );
309        let qs = serde_urlencoded::to_string(&params).unwrap();
310        assert!(qs.contains("symbol=GBPUSD-PERP"));
311        assert!(qs.contains("start_timestamp_ns=1000000000"));
312        assert!(qs.contains("end_timestamp_ns=2000000000"));
313        assert!(qs.contains("candle_width=1m"));
314    }
315
316    #[rstest]
317    fn test_get_candle_params_serialization() {
318        let params = GetCandleParams::new(Ustr::from("GBPUSD-PERP"), AxCandleWidth::Hours1);
319        let qs = serde_urlencoded::to_string(&params).unwrap();
320        assert!(qs.contains("symbol=GBPUSD-PERP"));
321        assert!(qs.contains("candle_width=1h"));
322    }
323
324    #[rstest]
325    fn test_get_funding_rates_params_serialization() {
326        let params = GetFundingRatesParams::new(Ustr::from("GBPUSD-PERP"), 1000000000, 2000000000);
327        let qs = serde_urlencoded::to_string(&params).unwrap();
328        assert!(qs.contains("symbol=GBPUSD-PERP"));
329        assert!(qs.contains("start_timestamp_ns=1000000000"));
330        assert!(qs.contains("end_timestamp_ns=2000000000"));
331    }
332
333    #[rstest]
334    fn test_get_trades_params_serialization() {
335        let params = GetTradesParams::new(Ustr::from("BTC-PERP"), Some(50));
336        let qs = serde_urlencoded::to_string(&params).unwrap();
337        assert!(qs.contains("symbol=BTC-PERP"));
338        assert!(qs.contains("limit=50"));
339    }
340
341    #[rstest]
342    fn test_get_trades_params_serialization_no_limit() {
343        let params = GetTradesParams::new(Ustr::from("BTC-PERP"), None);
344        let qs = serde_urlencoded::to_string(&params).unwrap();
345        assert_eq!(qs, "symbol=BTC-PERP");
346    }
347
348    #[rstest]
349    fn test_get_book_params_serialization() {
350        let params = GetBookParams::new(Ustr::from("EURUSD-PERP"), Some(3));
351        let qs = serde_urlencoded::to_string(&params).unwrap();
352        assert!(qs.contains("symbol=EURUSD-PERP"));
353        assert!(qs.contains("level=3"));
354    }
355
356    #[rstest]
357    fn test_get_order_status_by_order_id_serialization() {
358        let params = GetOrderStatusParams::by_order_id("O-01ARZ3NDEKTSV4RRFFQ69G5FAV");
359        let qs = serde_urlencoded::to_string(&params).unwrap();
360        assert!(qs.contains("order_id=O-01ARZ3NDEKTSV4RRFFQ69G5FAV"));
361        assert!(!qs.contains("client_order_id"));
362    }
363
364    #[rstest]
365    fn test_get_order_status_by_client_order_id_serialization() {
366        let params = GetOrderStatusParams::by_client_order_id(12345);
367        let qs = serde_urlencoded::to_string(&params).unwrap();
368        assert_eq!(qs, "client_order_id=12345");
369    }
370}