deribit_base/model/
request.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 21/7/25
5******************************************************************************/
6
7use crate::model::order::{OrderSide, OrderType, TimeInForce};
8use serde::{Deserialize, Serialize};
9
10/// FIX protocol compatible structures
11pub mod fix {
12    use super::*;
13
14    /// New order request structure for FIX protocol
15    #[derive(Debug, Clone, Serialize, Deserialize)]
16    pub struct NewOrderRequest {
17        /// Instrument symbol (e.g., "BTC-PERPETUAL")
18        pub symbol: String,
19        /// Order side (buy/sell)
20        pub side: OrderSide,
21        /// Order type
22        pub order_type: OrderType,
23        /// Order quantity
24        pub quantity: f64,
25        /// Order price (required for limit orders)
26        pub price: Option<f64>,
27        /// Time in force
28        pub time_in_force: TimeInForce,
29        /// Client order ID
30        pub client_order_id: Option<String>,
31    }
32
33    impl NewOrderRequest {
34        /// Create a new market buy order
35        pub fn market_buy(symbol: String, quantity: f64) -> Self {
36            Self {
37                symbol,
38                side: OrderSide::Buy,
39                order_type: OrderType::Market,
40                quantity,
41                price: None,
42                time_in_force: TimeInForce::ImmediateOrCancel,
43                client_order_id: None,
44            }
45        }
46
47        /// Create a new market sell order
48        pub fn market_sell(symbol: String, quantity: f64) -> Self {
49            Self {
50                symbol,
51                side: OrderSide::Sell,
52                order_type: OrderType::Market,
53                quantity,
54                price: None,
55                time_in_force: TimeInForce::ImmediateOrCancel,
56                client_order_id: None,
57            }
58        }
59
60        /// Create a new limit buy order
61        pub fn limit_buy(symbol: String, quantity: f64, price: f64) -> Self {
62            Self {
63                symbol,
64                side: OrderSide::Buy,
65                order_type: OrderType::Limit,
66                quantity,
67                price: Some(price),
68                time_in_force: TimeInForce::GoodTillCancel,
69                client_order_id: None,
70            }
71        }
72
73        /// Create a new limit sell order
74        pub fn limit_sell(symbol: String, quantity: f64, price: f64) -> Self {
75            Self {
76                symbol,
77                side: OrderSide::Sell,
78                order_type: OrderType::Limit,
79                quantity,
80                price: Some(price),
81                time_in_force: TimeInForce::GoodTillCancel,
82                client_order_id: None,
83            }
84        }
85
86        /// Set client order ID
87        pub fn with_client_order_id(mut self, client_order_id: String) -> Self {
88            self.client_order_id = Some(client_order_id);
89            self
90        }
91
92        /// Set time in force
93        pub fn with_time_in_force(mut self, tif: TimeInForce) -> Self {
94            self.time_in_force = tif;
95            self
96        }
97    }
98
99    /// Convert from REST/WebSocket NewOrderRequest to FIX NewOrderRequest
100    impl From<super::NewOrderRequest> for NewOrderRequest {
101        fn from(rest_order: super::NewOrderRequest) -> Self {
102            Self {
103                symbol: rest_order.instrument_name,
104                side: rest_order.side,
105                order_type: rest_order.order_type,
106                quantity: rest_order.amount,
107                price: rest_order.price,
108                time_in_force: rest_order.time_in_force,
109                client_order_id: rest_order.client_order_id,
110            }
111        }
112    }
113
114    /// Convert from FIX NewOrderRequest to REST/WebSocket NewOrderRequest
115    impl From<NewOrderRequest> for super::NewOrderRequest {
116        fn from(fix_order: NewOrderRequest) -> Self {
117            Self {
118                instrument_name: fix_order.symbol,
119                amount: fix_order.quantity,
120                order_type: fix_order.order_type,
121                side: fix_order.side,
122                price: fix_order.price,
123                time_in_force: fix_order.time_in_force,
124                post_only: None,
125                reduce_only: None,
126                label: None,
127                stop_price: None,
128                trigger: None,
129                advanced: None,
130                max_show: None,
131                reject_post_only: None,
132                valid_until: None,
133                client_order_id: fix_order.client_order_id,
134            }
135        }
136    }
137}
138
139/// Generic request for creating new orders
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct NewOrderRequest {
142    /// Instrument name
143    pub instrument_name: String,
144    /// Order amount
145    pub amount: f64,
146    /// Order type
147    #[serde(rename = "type")]
148    pub order_type: OrderType,
149    /// Order side (buy/sell)
150    pub side: OrderSide,
151    /// Order price (required for limit orders)
152    pub price: Option<f64>,
153    /// Time in force
154    pub time_in_force: TimeInForce,
155    /// Post-only flag
156    pub post_only: Option<bool>,
157    /// Reduce-only flag
158    pub reduce_only: Option<bool>,
159    /// Order label
160    pub label: Option<String>,
161    /// Stop price for stop orders
162    pub stop_price: Option<f64>,
163    /// Trigger type for stop orders
164    pub trigger: Option<TriggerType>,
165    /// Advanced order type
166    pub advanced: Option<AdvancedOrderType>,
167    /// Maximum show amount (iceberg orders)
168    pub max_show: Option<f64>,
169    /// Reject post-only flag
170    pub reject_post_only: Option<bool>,
171    /// Valid until timestamp
172    pub valid_until: Option<i64>,
173    /// Client order ID for tracking
174    pub client_order_id: Option<String>,
175}
176
177impl NewOrderRequest {
178    /// Create a new market buy order
179    pub fn market_buy(instrument_name: String, amount: f64) -> Self {
180        Self {
181            instrument_name,
182            amount,
183            order_type: OrderType::Market,
184            side: OrderSide::Buy,
185            price: None,
186            time_in_force: TimeInForce::ImmediateOrCancel,
187            post_only: None,
188            reduce_only: None,
189            label: None,
190            stop_price: None,
191            trigger: None,
192            advanced: None,
193            max_show: None,
194            reject_post_only: None,
195            valid_until: None,
196            client_order_id: None,
197        }
198    }
199
200    /// Create a new market sell order
201    pub fn market_sell(instrument_name: String, amount: f64) -> Self {
202        Self {
203            instrument_name,
204            amount,
205            order_type: OrderType::Market,
206            side: OrderSide::Sell,
207            price: None,
208            time_in_force: TimeInForce::ImmediateOrCancel,
209            post_only: None,
210            reduce_only: None,
211            label: None,
212            stop_price: None,
213            trigger: None,
214            advanced: None,
215            max_show: None,
216            reject_post_only: None,
217            valid_until: None,
218            client_order_id: None,
219        }
220    }
221
222    /// Create a new limit buy order
223    pub fn limit_buy(instrument_name: String, amount: f64, price: f64) -> Self {
224        Self {
225            instrument_name,
226            amount,
227            order_type: OrderType::Limit,
228            side: OrderSide::Buy,
229            price: Some(price),
230            time_in_force: TimeInForce::GoodTillCancel,
231            post_only: None,
232            reduce_only: None,
233            label: None,
234            stop_price: None,
235            trigger: None,
236            advanced: None,
237            max_show: None,
238            reject_post_only: None,
239            valid_until: None,
240            client_order_id: None,
241        }
242    }
243
244    /// Create a new limit sell order
245    pub fn limit_sell(instrument_name: String, amount: f64, price: f64) -> Self {
246        Self {
247            instrument_name,
248            amount,
249            order_type: OrderType::Limit,
250            side: OrderSide::Sell,
251            price: Some(price),
252            time_in_force: TimeInForce::GoodTillCancel,
253            post_only: None,
254            reduce_only: None,
255            label: None,
256            stop_price: None,
257            trigger: None,
258            advanced: None,
259            max_show: None,
260            reject_post_only: None,
261            valid_until: None,
262            client_order_id: None,
263        }
264    }
265
266    /// Set the order as post-only
267    pub fn with_post_only(mut self, post_only: bool) -> Self {
268        self.post_only = Some(post_only);
269        self
270    }
271
272    /// Set the order as reduce-only
273    pub fn with_reduce_only(mut self, reduce_only: bool) -> Self {
274        self.reduce_only = Some(reduce_only);
275        self
276    }
277
278    /// Set order label
279    pub fn with_label(mut self, label: String) -> Self {
280        self.label = Some(label);
281        self
282    }
283
284    /// Set time in force
285    pub fn with_time_in_force(mut self, tif: TimeInForce) -> Self {
286        self.time_in_force = tif;
287        self
288    }
289}
290
291/// Trigger type for stop orders
292#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
293#[serde(rename_all = "snake_case")]
294pub enum TriggerType {
295    /// Index price trigger
296    IndexPrice,
297    /// Mark price trigger
298    MarkPrice,
299    /// Last price trigger
300    LastPrice,
301}
302
303/// Advanced order type
304#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
305#[serde(rename_all = "lowercase")]
306pub enum AdvancedOrderType {
307    /// USD denomination
308    Usd,
309    /// Implied volatility
310    Implv,
311}
312
313/// Order modification request
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct ModifyOrderRequest {
316    /// Order ID to modify
317    pub order_id: String,
318    /// New amount
319    pub amount: Option<f64>,
320    /// New price
321    pub price: Option<f64>,
322    /// New stop price
323    pub stop_price: Option<f64>,
324    /// New post-only flag
325    pub post_only: Option<bool>,
326    /// New reduce-only flag
327    pub reduce_only: Option<bool>,
328    /// New reject post-only flag
329    pub reject_post_only: Option<bool>,
330    /// New advanced order type
331    pub advanced: Option<AdvancedOrderType>,
332}
333
334/// Order cancellation request
335#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct CancelOrderRequest {
337    /// Order ID to cancel
338    pub order_id: String,
339}
340
341/// Cancel all orders request
342#[derive(Debug, Clone, Serialize, Deserialize)]
343pub struct CancelAllOrdersRequest {
344    /// Currency filter
345    pub currency: Option<String>,
346    /// Instrument kind filter
347    pub kind: Option<String>,
348    /// Instrument type filter
349    #[serde(rename = "type")]
350    pub instrument_type: Option<String>,
351}
352
353/// Position close request
354#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct ClosePositionRequest {
356    /// Instrument name
357    pub instrument_name: String,
358    /// Order type for closing
359    #[serde(rename = "type")]
360    pub order_type: OrderType,
361    /// Price for limit orders
362    pub price: Option<f64>,
363}
364
365/// Authentication request
366#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct AuthRequest {
368    /// Grant type
369    pub grant_type: String,
370    /// Client ID
371    pub client_id: String,
372    /// Client secret
373    pub client_secret: String,
374    /// Refresh token (for refresh grant)
375    pub refresh_token: Option<String>,
376    /// Scope
377    pub scope: Option<String>,
378}
379
380impl AuthRequest {
381    /// Create a client credentials authentication request
382    pub fn client_credentials(client_id: String, client_secret: String) -> Self {
383        Self {
384            grant_type: "client_credentials".to_string(),
385            client_id,
386            client_secret,
387            refresh_token: None,
388            scope: None,
389        }
390    }
391
392    /// Create a refresh token authentication request
393    pub fn refresh_token(client_id: String, client_secret: String, refresh_token: String) -> Self {
394        Self {
395            grant_type: "refresh_token".to_string(),
396            client_id,
397            client_secret,
398            refresh_token: Some(refresh_token),
399            scope: None,
400        }
401    }
402}