nautilus_binance/futures/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//! Binance Futures HTTP query parameter builders.
17
18use derive_builder::Builder;
19use serde::{Deserialize, Serialize};
20
21use crate::common::enums::BinanceIncomeType;
22
23/// Query parameters for `GET /fapi/v1/depth` or `GET /dapi/v1/depth`.
24#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
25#[builder(setter(into, strip_option), default)]
26pub struct BinanceDepthParams {
27    /// Trading symbol (required).
28    pub symbol: String,
29    /// Depth limit (default 100, max 1000).
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub limit: Option<u32>,
32}
33
34/// Query parameters for `GET /fapi/v1/ticker/24hr` or `GET /dapi/v1/ticker/24hr`.
35#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
36#[builder(default)]
37#[builder(setter(into, strip_option))]
38pub struct BinanceTicker24hrParams {
39    /// Filter by single symbol.
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub symbol: Option<String>,
42}
43
44/// Query parameters for `GET /fapi/v1/ticker/bookTicker` or `GET /dapi/v1/ticker/bookTicker`.
45#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
46#[builder(default)]
47#[builder(setter(into, strip_option))]
48pub struct BinanceBookTickerParams {
49    /// Filter by single symbol.
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub symbol: Option<String>,
52}
53
54/// Query parameters for `GET /fapi/v1/premiumIndex` or `GET /dapi/v1/premiumIndex`.
55#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
56#[builder(default)]
57#[builder(setter(into, strip_option))]
58pub struct BinanceMarkPriceParams {
59    /// Filter by single symbol.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub symbol: Option<String>,
62}
63
64/// Query parameters for `GET /fapi/v1/fundingRate` or `GET /dapi/v1/fundingRate`.
65#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
66#[builder(default)]
67#[builder(setter(into, strip_option))]
68pub struct BinanceFundingRateParams {
69    /// Trading symbol.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub symbol: Option<String>,
72    /// Start time in milliseconds.
73    #[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
74    pub start_time: Option<i64>,
75    /// End time in milliseconds.
76    #[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
77    pub end_time: Option<i64>,
78    /// Number of results (default 100, max 1000).
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub limit: Option<u32>,
81}
82
83/// Query parameters for `GET /fapi/v1/openInterest` or `GET /dapi/v1/openInterest`.
84#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
85#[builder(setter(into))]
86pub struct BinanceOpenInterestParams {
87    /// Trading symbol (required).
88    pub symbol: String,
89}
90
91/// Query parameters for `GET /fapi/v2/balance` or `GET /dapi/v1/balance`.
92#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
93#[builder(default)]
94#[builder(setter(into, strip_option))]
95pub struct BinanceFuturesBalanceParams {
96    /// Filter by asset (e.g., "USDT").
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub asset: Option<String>,
99    /// Recv window override (ms).
100    #[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
101    pub recv_window: Option<u64>,
102}
103
104/// Query parameters for `GET /fapi/v2/positionRisk` or `GET /dapi/v1/positionRisk`.
105#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
106#[builder(default)]
107#[builder(setter(into, strip_option))]
108pub struct BinancePositionRiskParams {
109    /// Filter by symbol.
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub symbol: Option<String>,
112    /// Recv window override (ms).
113    #[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
114    pub recv_window: Option<u64>,
115}
116
117/// Query parameters for `GET /fapi/v1/income` or `GET /dapi/v1/income`.
118#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
119#[builder(default)]
120#[builder(setter(into, strip_option))]
121pub struct BinanceIncomeHistoryParams {
122    /// Filter by symbol.
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub symbol: Option<String>,
125    /// Income type filter (e.g., FUNDING_FEE).
126    #[serde(rename = "incomeType", skip_serializing_if = "Option::is_none")]
127    pub income_type: Option<BinanceIncomeType>,
128    /// Start time in milliseconds.
129    #[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
130    pub start_time: Option<i64>,
131    /// End time in milliseconds.
132    #[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
133    pub end_time: Option<i64>,
134    /// Maximum number of rows (default 100, max 1000).
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub limit: Option<u32>,
137    /// Recv window override (ms).
138    #[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
139    pub recv_window: Option<u64>,
140}
141
142/// Query parameters for `GET /fapi/v1/userTrades` or `GET /dapi/v1/userTrades`.
143#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
144#[builder(setter(into, strip_option), default)]
145pub struct BinanceUserTradesParams {
146    /// Trading symbol (required).
147    pub symbol: String,
148    /// Start time in milliseconds.
149    #[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
150    pub start_time: Option<i64>,
151    /// End time in milliseconds.
152    #[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
153    pub end_time: Option<i64>,
154    /// Trade ID to fetch from (inclusive).
155    #[serde(rename = "fromId", skip_serializing_if = "Option::is_none")]
156    pub from_id: Option<i64>,
157    /// Number of trades to return (default 500, max 1000).
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub limit: Option<u32>,
160    /// Recv window override (ms).
161    #[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
162    pub recv_window: Option<u64>,
163}
164
165/// Query parameters for `GET /fapi/v1/openOrders` or `GET /dapi/v1/openOrders`.
166#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
167#[builder(default)]
168#[builder(setter(into, strip_option))]
169pub struct BinanceOpenOrdersParams {
170    /// Filter by symbol.
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub symbol: Option<String>,
173    /// Recv window override (ms).
174    #[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
175    pub recv_window: Option<u64>,
176}
177
178/// Query parameters for `GET /fapi/v1/order` or `GET /dapi/v1/order`.
179#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
180#[builder(setter(into, strip_option), default)]
181pub struct BinanceOrderQueryParams {
182    /// Trading symbol (required).
183    pub symbol: String,
184    /// Order ID.
185    #[serde(rename = "orderId", skip_serializing_if = "Option::is_none")]
186    pub order_id: Option<i64>,
187    /// Orig client order ID.
188    #[serde(rename = "origClientOrderId", skip_serializing_if = "Option::is_none")]
189    pub orig_client_order_id: Option<String>,
190    /// Recv window override (ms).
191    #[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
192    pub recv_window: Option<u64>,
193}
194
195#[cfg(test)]
196mod tests {
197    use rstest::rstest;
198
199    use super::*;
200
201    #[rstest]
202    fn test_depth_params_builder() {
203        let params = BinanceDepthParamsBuilder::default()
204            .symbol("BTCUSDT")
205            .limit(100u32)
206            .build()
207            .unwrap();
208
209        assert_eq!(params.symbol, "BTCUSDT");
210        assert_eq!(params.limit, Some(100));
211    }
212
213    #[rstest]
214    fn test_ticker_params_serialization() {
215        let params = BinanceTicker24hrParams {
216            symbol: Some("BTCUSDT".to_string()),
217        };
218
219        let serialized = serde_urlencoded::to_string(&params).unwrap();
220        assert_eq!(serialized, "symbol=BTCUSDT");
221    }
222
223    #[rstest]
224    fn test_order_query_params_builder() {
225        let params = BinanceOrderQueryParamsBuilder::default()
226            .symbol("BTCUSDT")
227            .order_id(12345_i64)
228            .recv_window(5_000_u64)
229            .build()
230            .unwrap();
231
232        assert_eq!(params.symbol, "BTCUSDT");
233        assert_eq!(params.order_id, Some(12345));
234        assert_eq!(params.recv_window, Some(5_000));
235    }
236
237    #[rstest]
238    fn test_income_history_params_serialization() {
239        let params = BinanceIncomeHistoryParamsBuilder::default()
240            .symbol("ETHUSDT")
241            .income_type(BinanceIncomeType::FundingFee)
242            .limit(50_u32)
243            .build()
244            .unwrap();
245
246        let serialized = serde_urlencoded::to_string(&params).unwrap();
247        assert_eq!(serialized, "symbol=ETHUSDT&incomeType=FUNDING_FEE&limit=50");
248    }
249
250    #[rstest]
251    fn test_open_orders_params_builder() {
252        let params = BinanceOpenOrdersParamsBuilder::default()
253            .symbol("BNBUSDT")
254            .build()
255            .unwrap();
256
257        assert_eq!(params.symbol.as_deref(), Some("BNBUSDT"));
258        assert!(params.recv_window.is_none());
259    }
260}