deribit_base/model/
response.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::OrderInfo;
8use crate::model::order_management::QuoteResult;
9use crate::model::trade::{LastTrade, TradeExecution};
10use crate::{impl_json_debug_pretty, impl_json_display};
11use serde::{Deserialize, Serialize};
12
13/// Generic JSON-RPC 2.0 response wrapper
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct JsonRpcResponse<T> {
16    /// JSON-RPC version
17    pub jsonrpc: String,
18    /// Request ID
19    pub id: Option<serde_json::Value>,
20    /// Result data (present on success)
21    pub result: Option<T>,
22    /// Error information (present on error)
23    pub error: Option<JsonRpcError>,
24    /// Test net flag
25    pub testnet: Option<bool>,
26    /// Use server time
27    #[serde(rename = "usIn")]
28    pub us_in: Option<i64>,
29    /// Use out time
30    #[serde(rename = "usOut")]
31    pub us_out: Option<i64>,
32    /// Use diff time
33    #[serde(rename = "usDiff")]
34    pub us_diff: Option<i64>,
35}
36
37impl<T> JsonRpcResponse<T> {
38    /// Create a successful response
39    pub fn success(id: Option<serde_json::Value>, result: T) -> Self {
40        Self {
41            jsonrpc: "2.0".to_string(),
42            id,
43            result: Some(result),
44            error: None,
45            testnet: None,
46            us_in: None,
47            us_out: None,
48            us_diff: None,
49        }
50    }
51
52    /// Create an error response
53    pub fn error(id: Option<serde_json::Value>, error: JsonRpcError) -> Self {
54        Self {
55            jsonrpc: "2.0".to_string(),
56            id,
57            result: None,
58            error: Some(error),
59            testnet: None,
60            us_in: None,
61            us_out: None,
62            us_diff: None,
63        }
64    }
65
66    /// Check if the response is successful
67    pub fn is_success(&self) -> bool {
68        self.error.is_none() && self.result.is_some()
69    }
70
71    /// Check if the response is an error
72    pub fn is_error(&self) -> bool {
73        self.error.is_some()
74    }
75
76    /// Get the result, consuming the response
77    pub fn into_result(self) -> Result<T, JsonRpcError> {
78        match (self.result, self.error) {
79            (Some(result), None) => Ok(result),
80            (None, Some(error)) => Err(error),
81            (Some(_), Some(error)) => Err(error), // Error takes precedence
82            (None, None) => Err(JsonRpcError {
83                code: -32603,
84                message: "Internal error: neither result nor error present".to_string(),
85                data: None,
86            }),
87        }
88    }
89}
90
91/// JSON-RPC error information
92#[derive(Clone, Serialize, Deserialize)]
93pub struct JsonRpcError {
94    /// Error code
95    pub code: i32,
96    /// Error message
97    pub message: String,
98    /// Additional error data
99    pub data: Option<serde_json::Value>,
100}
101
102impl JsonRpcError {
103    /// Create a new JSON-RPC error
104    pub fn new(code: i32, message: String) -> Self {
105        Self {
106            code,
107            message,
108            data: None,
109        }
110    }
111
112    /// Create an error with additional data
113    pub fn with_data(code: i32, message: String, data: serde_json::Value) -> Self {
114        Self {
115            code,
116            message,
117            data: Some(data),
118        }
119    }
120
121    /// Parse error (-32700)
122    pub fn parse_error() -> Self {
123        Self::new(-32700, "Parse error".to_string())
124    }
125
126    /// Invalid request (-32600)
127    pub fn invalid_request() -> Self {
128        Self::new(-32600, "Invalid Request".to_string())
129    }
130
131    /// Method not found (-32601)
132    pub fn method_not_found() -> Self {
133        Self::new(-32601, "Method not found".to_string())
134    }
135
136    /// Invalid params (-32602)
137    pub fn invalid_params() -> Self {
138        Self::new(-32602, "Invalid params".to_string())
139    }
140
141    /// Internal error (-32603)
142    pub fn internal_error() -> Self {
143        Self::new(-32603, "Internal error".to_string())
144    }
145
146    /// Check if this is a server error (code between -32099 and -32000)
147    pub fn is_server_error(&self) -> bool {
148        self.code <= -32000 && self.code >= -32099
149    }
150
151    /// Check if this is an application error (code > -32000)
152    pub fn is_application_error(&self) -> bool {
153        self.code > -32000
154    }
155}
156
157/// Authentication response
158#[derive(Clone, Serialize, Deserialize)]
159pub struct AuthResponse {
160    /// Access token
161    pub access_token: String,
162    /// Token type (usually "bearer")
163    pub token_type: String,
164    /// Expires in seconds
165    pub expires_in: i64,
166    /// Refresh token
167    pub refresh_token: String,
168    /// Scope
169    pub scope: String,
170}
171
172/// Pagination information
173#[derive(Clone, Serialize, Deserialize)]
174pub struct Pagination {
175    /// Current page
176    pub page: Option<u32>,
177    /// Items per page
178    pub per_page: Option<u32>,
179    /// Total items
180    pub total: Option<u64>,
181    /// Total pages
182    pub pages: Option<u32>,
183    /// Has more pages
184    pub has_more: Option<bool>,
185}
186
187/// Generic paginated response
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct PaginatedResponse<T> {
190    /// Data items
191    pub data: Vec<T>,
192    /// Pagination information
193    pub pagination: Option<Pagination>,
194}
195
196impl<T> PaginatedResponse<T> {
197    /// Create a new paginated response
198    pub fn new(data: Vec<T>) -> Self {
199        Self {
200            data,
201            pagination: None,
202        }
203    }
204
205    /// Create a paginated response with pagination info
206    pub fn with_pagination(data: Vec<T>, pagination: Pagination) -> Self {
207        Self {
208            data,
209            pagination: Some(pagination),
210        }
211    }
212
213    /// Check if there are more pages
214    pub fn has_more(&self) -> bool {
215        self.pagination
216            .as_ref()
217            .and_then(|p| p.has_more)
218            .unwrap_or(false)
219    }
220
221    /// Get the number of items
222    pub fn len(&self) -> usize {
223        self.data.len()
224    }
225
226    /// Check if the response is empty
227    pub fn is_empty(&self) -> bool {
228        self.data.is_empty()
229    }
230}
231
232/// WebSocket notification
233#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct Notification<T> {
235    /// JSON-RPC version
236    pub jsonrpc: String,
237    /// Method name
238    pub method: String,
239    /// Parameters/data
240    pub params: T,
241}
242
243impl<T> Notification<T> {
244    /// Create a new notification
245    pub fn new(method: String, params: T) -> Self {
246        Self {
247            jsonrpc: "2.0".to_string(),
248            method,
249            params,
250        }
251    }
252}
253
254/// Subscription response
255#[derive(Clone, Serialize, Deserialize)]
256pub struct SubscriptionResponse {
257    /// Subscription ID
258    pub subscription: String,
259    /// Channel name
260    pub channel: String,
261}
262
263/// Heartbeat response
264#[derive(Clone, Serialize, Deserialize)]
265pub struct HeartbeatResponse {
266    /// Type (always "heartbeat")
267    #[serde(rename = "type")]
268    pub type_: String,
269}
270
271/// Test response for connectivity checks
272#[derive(Clone, Serialize, Deserialize)]
273pub struct TestResponse {
274    /// Version information
275    pub version: String,
276}
277
278/// Server time response
279#[derive(Clone, Serialize, Deserialize)]
280pub struct ServerTimeResponse {
281    /// Current server timestamp in milliseconds
282    pub timestamp: i64,
283}
284
285/// Settlements response structure
286#[derive(Clone, Serialize, Deserialize)]
287pub struct SettlementsResponse {
288    /// Continuation token for pagination
289    pub continuation: Option<String>,
290    /// List of settlement events
291    pub settlements: Vec<crate::model::settlement::Settlement>,
292}
293
294impl SettlementsResponse {
295    /// Create a new settlements response
296    pub fn new(settlements: Vec<crate::model::settlement::Settlement>) -> Self {
297        Self {
298            continuation: None,
299            settlements,
300        }
301    }
302
303    /// Create settlements response with continuation token
304    pub fn with_continuation(
305        settlements: Vec<crate::model::settlement::Settlement>,
306        continuation: String,
307    ) -> Self {
308        Self {
309            continuation: Some(continuation),
310            settlements,
311        }
312    }
313
314    /// Check if there are more results
315    pub fn has_more(&self) -> bool {
316        self.continuation.is_some()
317    }
318}
319
320/// Contract size response
321#[derive(Clone, Serialize, Deserialize)]
322pub struct ContractSizeResponse {
323    /// Contract size value
324    pub contract_size: f64,
325}
326
327/// Status response
328#[derive(Clone, Serialize, Deserialize)]
329pub struct StatusResponse {
330    /// Whether the system is locked (optional)
331    pub locked: Option<bool>,
332    /// Status message (optional)
333    pub message: Option<String>,
334    /// List of locked indices (optional)
335    pub locked_indices: Option<Vec<String>>,
336    /// Additional fields that might be present in the API response
337    #[serde(flatten)]
338    pub additional_fields: std::collections::HashMap<String, serde_json::Value>,
339}
340
341/// APR history response
342#[derive(Clone, Serialize, Deserialize)]
343pub struct AprHistoryResponse {
344    /// List of APR data points
345    pub data: Vec<AprDataPoint>,
346    /// Continuation token for pagination
347    pub continuation: Option<String>,
348}
349/// APR data point
350#[derive(Clone, Serialize, Deserialize)]
351pub struct AprDataPoint {
352    /// Annual percentage rate
353    pub apr: f64,
354    /// Timestamp of the data point (optional)
355    pub timestamp: Option<u64>,
356    /// Day of the data point
357    pub day: i32,
358}
359
360/// Hello response
361#[derive(Clone, Serialize, Deserialize)]
362pub struct HelloResponse {
363    /// Version string
364    pub version: String,
365}
366
367/// Delivery prices response
368#[derive(Clone, Serialize, Deserialize)]
369pub struct DeliveryPricesResponse {
370    /// List of delivery price data
371    pub data: Vec<DeliveryPriceData>,
372    /// Total number of records
373    pub records_total: u32,
374}
375
376/// Delivery price data
377#[derive(Clone, Serialize, Deserialize)]
378pub struct DeliveryPriceData {
379    /// Date of the delivery price
380    pub date: String,
381    /// Delivery price value
382    pub delivery_price: f64,
383}
384
385/// Currency-specific expirations
386#[derive(Clone, Serialize, Deserialize)]
387pub struct CurrencyExpirations {
388    /// Future instrument expirations
389    pub future: Option<Vec<String>>,
390    /// Option instrument expirations
391    pub option: Option<Vec<String>>,
392}
393
394/// Expirations response
395#[derive(Clone, Serialize, Deserialize)]
396pub struct ExpirationsResponse {
397    /// Direct future expirations (when currency="any")
398    pub future: Option<Vec<String>>,
399    /// Direct option expirations (when currency="any")
400    pub option: Option<Vec<String>>,
401    /// Map of currency to their expirations (when specific currency)
402    #[serde(flatten)]
403    pub currencies: std::collections::HashMap<String, CurrencyExpirations>,
404}
405
406/// Last trades response
407#[derive(Clone, Serialize, Deserialize)]
408pub struct LastTradesResponse {
409    /// Whether there are more trades available
410    pub has_more: bool,
411    /// List of recent trades
412    pub trades: Vec<LastTrade>,
413}
414
415/// Order response
416#[derive(Clone, Serialize, Deserialize)]
417pub struct OrderResponse {
418    /// Order information
419    pub order: OrderInfo,
420    /// List of trade executions for the order
421    pub trades: Vec<TradeExecution>,
422}
423
424/// Mass quote response
425#[derive(Clone, Serialize, Deserialize)]
426pub struct MassQuoteResponse {
427    /// List of quote results
428    pub quotes: Vec<QuoteResult>,
429}
430
431impl_json_display!(
432    MassQuoteResponse,
433    JsonRpcError,
434    AuthResponse,
435    Pagination,
436    SubscriptionResponse,
437    HeartbeatResponse,
438    TestResponse,
439    ServerTimeResponse,
440    SettlementsResponse,
441    ContractSizeResponse,
442    StatusResponse,
443    AprHistoryResponse,
444    AprDataPoint,
445    HelloResponse,
446    DeliveryPricesResponse,
447    DeliveryPriceData,
448    CurrencyExpirations,
449    ExpirationsResponse,
450    LastTradesResponse,
451    OrderResponse
452);
453impl_json_debug_pretty!(
454    MassQuoteResponse,
455    JsonRpcError,
456    AuthResponse,
457    Pagination,
458    SubscriptionResponse,
459    HeartbeatResponse,
460    TestResponse,
461    ServerTimeResponse,
462    SettlementsResponse,
463    ContractSizeResponse,
464    StatusResponse,
465    AprHistoryResponse,
466    AprDataPoint,
467    HelloResponse,
468    DeliveryPricesResponse,
469    DeliveryPriceData,
470    CurrencyExpirations,
471    ExpirationsResponse,
472    LastTradesResponse,
473    OrderResponse
474);
475
476impl std::error::Error for JsonRpcError {}