deribit_base/
constants.rs1pub const DERIBIT_WS_URL_PROD: &str = "wss://www.deribit.com/ws/api/v2";
19
20pub const DERIBIT_WS_URL_TEST: &str = "wss://test.deribit.com/ws/api/v2";
22
23pub const DERIBIT_HTTP_URL_PROD: &str = "https://www.deribit.com/api/v2";
25
26pub const DERIBIT_HTTP_URL_TEST: &str = "https://test.deribit.com/api/v2";
28
29pub const MAX_REQUESTS_PER_SECOND_AUTH: u32 = 20;
35
36pub const MAX_REQUESTS_PER_SECOND_UNAUTH: u32 = 10;
38
39pub const MAX_SUBSCRIPTIONS_PER_CONNECTION: u32 = 200;
41
42pub const MAX_MESSAGE_SIZE_BYTES: usize = 65536; pub const DEFAULT_CONNECTION_TIMEOUT_MS: u64 = 5000;
51
52pub const DEFAULT_REQUEST_TIMEOUT_MS: u64 = 10000;
54
55pub const HEARTBEAT_INTERVAL_MS: u64 = 10000;
57
58pub const HEARTBEAT_TIMEOUT_MS: u64 = 5000;
60
61pub const SUPPORTED_CRYPTOCURRENCIES: &[&str] = &["BTC", "ETH", "SOL", "USDC", "USDT", "EURR"];
67
68pub const CURRENCY_BTC: &str = "BTC";
70
71pub const CURRENCY_ETH: &str = "ETH";
73
74pub const CURRENCY_SOL: &str = "SOL";
76
77pub const CURRENCY_USDC: &str = "USDC";
79
80pub const CURRENCY_USDT: &str = "USDT";
82
83pub const CURRENCY_EURR: &str = "EURR";
85
86pub const INSTRUMENT_TYPE_FUTURE: &str = "future";
92
93pub const INSTRUMENT_TYPE_OPTION: &str = "option";
95
96pub const INSTRUMENT_TYPE_PERPETUAL: &str = "perpetual";
98
99pub const INSTRUMENT_TYPE_SPOT: &str = "spot";
101
102pub const INSTRUMENT_TYPE_FUTURE_COMBO: &str = "future_combo";
104
105pub const INSTRUMENT_TYPE_OPTION_COMBO: &str = "option_combo";
107
108pub const MIN_ORDER_AMOUNT_BTC: f64 = 0.0001;
114
115pub const MIN_ORDER_AMOUNT_ETH: f64 = 0.001;
117
118pub const MIN_ORDER_AMOUNT_SOL: f64 = 0.1;
120
121pub const MAX_ORDER_AMOUNT: f64 = 1_000_000.0;
123
124pub const MAX_OPEN_ORDERS_PER_INSTRUMENT: u32 = 500;
126
127pub const MAX_OPEN_ORDERS_TOTAL: u32 = 2000;
129
130pub const PRICE_PRECISION_BTC: u8 = 8;
136
137pub const PRICE_PRECISION_ETH: u8 = 4;
139
140pub const PRICE_PRECISION_SOL: u8 = 4;
142
143pub const AMOUNT_PRECISION_BTC: u8 = 4;
145
146pub const AMOUNT_PRECISION_ETH: u8 = 3;
148
149pub const AMOUNT_PRECISION_SOL: u8 = 1;
151
152pub const JSONRPC_VERSION: &str = "2.0";
158
159pub const DEFAULT_REQUEST_ID: u64 = 1;
161
162pub const CHANNEL_BOOK: &str = "book";
168
169pub const CHANNEL_TRADES: &str = "trades";
171
172pub const CHANNEL_TICKER: &str = "ticker";
174
175pub const CHANNEL_QUOTE: &str = "quote";
177
178pub const CHANNEL_USER_ORDERS: &str = "user.orders";
180
181pub const CHANNEL_USER_TRADES: &str = "user.trades";
183
184pub const CHANNEL_USER_PORTFOLIO: &str = "user.portfolio";
186
187pub const FIX_VERSION: &str = "FIX.4.4";
193
194pub const FIX_DELIMITER: char = '\x01';
196
197pub const FIX_DELIMITER_STR: &str = "\x01";
199
200pub const FIX_HEARTBEAT_INTERVAL: u32 = 30;
202
203pub const MAX_RETRY_ATTEMPTS: u8 = 3;
209
210pub const RETRY_BASE_DELAY_MS: u64 = 1000;
212
213pub const RETRY_MAX_DELAY_MS: u64 = 30000;
215
216pub const MAX_ORDER_BOOK_DEPTH: u32 = 10000;
222
223pub const DEFAULT_ORDER_BOOK_DEPTH: u32 = 20;
225
226pub const MAX_RECENT_TRADES: u32 = 10000;
228
229pub const DEFAULT_RECENT_TRADES: u32 = 100;
231
232pub const ACCESS_TOKEN_EXPIRATION_SEC: u64 = 28800;
238
239pub const REFRESH_TOKEN_EXPIRATION_SEC: u64 = 2592000;
241
242pub const TOKEN_REFRESH_BUFFER_SEC: u64 = 300;
244
245pub fn get_min_order_amount(currency: &str) -> f64 {
251    match currency {
252        CURRENCY_BTC => MIN_ORDER_AMOUNT_BTC,
253        CURRENCY_ETH => MIN_ORDER_AMOUNT_ETH,
254        CURRENCY_SOL => MIN_ORDER_AMOUNT_SOL,
255        _ => MIN_ORDER_AMOUNT_BTC, }
257}
258
259pub fn get_price_precision(currency: &str) -> u8 {
261    match currency {
262        CURRENCY_BTC => PRICE_PRECISION_BTC,
263        CURRENCY_ETH => PRICE_PRECISION_ETH,
264        CURRENCY_SOL => PRICE_PRECISION_SOL,
265        _ => PRICE_PRECISION_BTC, }
267}
268
269pub fn get_amount_precision(currency: &str) -> u8 {
271    match currency {
272        CURRENCY_BTC => AMOUNT_PRECISION_BTC,
273        CURRENCY_ETH => AMOUNT_PRECISION_ETH,
274        CURRENCY_SOL => AMOUNT_PRECISION_SOL,
275        _ => AMOUNT_PRECISION_BTC, }
277}
278
279pub fn is_supported_currency(currency: &str) -> bool {
281    matches!(
282        currency,
283        CURRENCY_BTC | CURRENCY_ETH | CURRENCY_SOL | CURRENCY_USDC | CURRENCY_USDT | CURRENCY_EURR
284    )
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290
291    #[test]
292    fn test_api_urls() {
293        assert!(DERIBIT_WS_URL_PROD.starts_with("wss://"));
294        assert!(DERIBIT_WS_URL_TEST.starts_with("wss://"));
295        assert!(DERIBIT_HTTP_URL_PROD.starts_with("https://"));
296        assert!(DERIBIT_HTTP_URL_TEST.starts_with("https://"));
297
298        assert!(DERIBIT_WS_URL_PROD.contains("www.deribit.com"));
299        assert!(DERIBIT_WS_URL_TEST.contains("test.deribit.com"));
300    }
301
302    #[test]
303    fn test_supported_currencies() {
304        assert!(is_supported_currency(CURRENCY_BTC));
305        assert!(is_supported_currency(CURRENCY_ETH));
306        assert!(is_supported_currency(CURRENCY_SOL));
307        assert!(is_supported_currency(CURRENCY_USDC));
308        assert!(is_supported_currency(CURRENCY_USDT));
309        assert!(is_supported_currency(CURRENCY_EURR));
310
311        assert!(!is_supported_currency("INVALID"));
312        assert!(!is_supported_currency("XRP"));
313    }
314
315    #[test]
316    fn test_min_order_amounts() {
317        assert_eq!(get_min_order_amount(CURRENCY_BTC), MIN_ORDER_AMOUNT_BTC);
318        assert_eq!(get_min_order_amount(CURRENCY_ETH), MIN_ORDER_AMOUNT_ETH);
319        assert_eq!(get_min_order_amount(CURRENCY_SOL), MIN_ORDER_AMOUNT_SOL);
320
321        assert_eq!(get_min_order_amount("UNKNOWN"), MIN_ORDER_AMOUNT_BTC);
323    }
324
325    #[test]
326    fn test_precision_functions() {
327        assert_eq!(get_price_precision(CURRENCY_BTC), PRICE_PRECISION_BTC);
328        assert_eq!(get_price_precision(CURRENCY_ETH), PRICE_PRECISION_ETH);
329        assert_eq!(get_price_precision(CURRENCY_SOL), PRICE_PRECISION_SOL);
330
331        assert_eq!(get_amount_precision(CURRENCY_BTC), AMOUNT_PRECISION_BTC);
332        assert_eq!(get_amount_precision(CURRENCY_ETH), AMOUNT_PRECISION_ETH);
333        assert_eq!(get_amount_precision(CURRENCY_SOL), AMOUNT_PRECISION_SOL);
334    }
335
336    #[test]
337    fn test_rate_limits() {
338        #[allow(clippy::assertions_on_constants)]
340        {
341            assert!(MAX_REQUESTS_PER_SECOND_AUTH > MAX_REQUESTS_PER_SECOND_UNAUTH);
342            assert!(MAX_SUBSCRIPTIONS_PER_CONNECTION > 0);
343            assert!(MAX_MESSAGE_SIZE_BYTES > 0);
344        }
345
346        assert_eq!(MAX_REQUESTS_PER_SECOND_AUTH, 20);
348        assert_eq!(MAX_REQUESTS_PER_SECOND_UNAUTH, 10);
349        assert_eq!(MAX_SUBSCRIPTIONS_PER_CONNECTION, 200);
350        assert_eq!(MAX_MESSAGE_SIZE_BYTES, 65536);
351    }
352
353    #[test]
354    fn test_timeouts() {
355        #[allow(clippy::assertions_on_constants)]
357        {
358            assert!(DEFAULT_CONNECTION_TIMEOUT_MS > 0);
359            assert!(DEFAULT_REQUEST_TIMEOUT_MS > DEFAULT_CONNECTION_TIMEOUT_MS);
360            assert!(HEARTBEAT_INTERVAL_MS > HEARTBEAT_TIMEOUT_MS);
361        }
362
363        assert_eq!(DEFAULT_CONNECTION_TIMEOUT_MS, 5000);
365        assert_eq!(DEFAULT_REQUEST_TIMEOUT_MS, 10000);
366        assert_eq!(HEARTBEAT_INTERVAL_MS, 10000);
367        assert_eq!(HEARTBEAT_TIMEOUT_MS, 5000);
368    }
369
370    #[test]
371    fn test_order_limits() {
372        #[allow(clippy::assertions_on_constants)]
374        {
375            assert!(MIN_ORDER_AMOUNT_BTC > 0.0);
376            assert!(MIN_ORDER_AMOUNT_ETH > 0.0);
377            assert!(MIN_ORDER_AMOUNT_SOL > 0.0);
378            assert!(MAX_ORDER_AMOUNT > MIN_ORDER_AMOUNT_BTC);
379            assert!(MAX_OPEN_ORDERS_TOTAL > MAX_OPEN_ORDERS_PER_INSTRUMENT);
380        }
381
382        assert_eq!(get_min_order_amount(CURRENCY_BTC), MIN_ORDER_AMOUNT_BTC);
384        assert_eq!(get_min_order_amount(CURRENCY_ETH), MIN_ORDER_AMOUNT_ETH);
385        assert_eq!(get_min_order_amount(CURRENCY_SOL), MIN_ORDER_AMOUNT_SOL);
386    }
387
388    #[test]
389    fn test_jsonrpc_constants() {
390        assert_eq!(JSONRPC_VERSION, "2.0");
391
392        #[allow(clippy::assertions_on_constants)]
394        {
395            assert!(DEFAULT_REQUEST_ID > 0);
396        }
397
398        assert_eq!(DEFAULT_REQUEST_ID, 1);
400    }
401
402    #[test]
403    fn test_fix_constants() {
404        assert_eq!(FIX_VERSION, "FIX.4.4");
405        assert_eq!(FIX_DELIMITER, '\x01');
406        assert_eq!(FIX_DELIMITER_STR, "\x01");
407
408        #[allow(clippy::assertions_on_constants)]
410        {
411            assert!(FIX_HEARTBEAT_INTERVAL > 0);
412        }
413
414        assert_eq!(FIX_HEARTBEAT_INTERVAL, 30);
416    }
417
418    #[test]
419    fn test_channel_names() {
420        #[allow(clippy::const_is_empty)]
422        {
423            assert!(!CHANNEL_BOOK.is_empty());
424            assert!(!CHANNEL_TRADES.is_empty());
425            assert!(!CHANNEL_TICKER.is_empty());
426            assert!(!CHANNEL_QUOTE.is_empty());
427        }
428
429        assert_eq!(CHANNEL_BOOK, "book");
431        assert_eq!(CHANNEL_TRADES, "trades");
432        assert_eq!(CHANNEL_TICKER, "ticker");
433        assert_eq!(CHANNEL_QUOTE, "quote");
434
435        assert!(CHANNEL_USER_ORDERS.starts_with("user."));
437        assert!(CHANNEL_USER_TRADES.starts_with("user."));
438        assert!(CHANNEL_USER_PORTFOLIO.starts_with("user."));
439    }
440
441    #[test]
442    fn test_instrument_types() {
443        let types = [
444            INSTRUMENT_TYPE_FUTURE,
445            INSTRUMENT_TYPE_OPTION,
446            INSTRUMENT_TYPE_PERPETUAL,
447            INSTRUMENT_TYPE_SPOT,
448            INSTRUMENT_TYPE_FUTURE_COMBO,
449            INSTRUMENT_TYPE_OPTION_COMBO,
450        ];
451
452        for instrument_type in types {
453            assert!(!instrument_type.is_empty());
454        }
455    }
456
457    #[test]
458    fn test_authentication_constants() {
459        #[allow(clippy::assertions_on_constants)]
461        {
462            assert!(ACCESS_TOKEN_EXPIRATION_SEC > 0);
463            assert!(REFRESH_TOKEN_EXPIRATION_SEC > ACCESS_TOKEN_EXPIRATION_SEC);
464            assert!(TOKEN_REFRESH_BUFFER_SEC < ACCESS_TOKEN_EXPIRATION_SEC);
465        }
466
467        assert_eq!(ACCESS_TOKEN_EXPIRATION_SEC, 28800); assert_eq!(REFRESH_TOKEN_EXPIRATION_SEC, 2592000); assert_eq!(TOKEN_REFRESH_BUFFER_SEC, 300); }
472
473    #[test]
474    fn test_market_data_constants() {
475        #[allow(clippy::assertions_on_constants)]
477        {
478            assert!(MAX_ORDER_BOOK_DEPTH > DEFAULT_ORDER_BOOK_DEPTH);
479            assert!(MAX_RECENT_TRADES > DEFAULT_RECENT_TRADES);
480            assert!(DEFAULT_ORDER_BOOK_DEPTH > 0);
481            assert!(DEFAULT_RECENT_TRADES > 0);
482        }
483
484        assert_eq!(MAX_ORDER_BOOK_DEPTH, 10000);
486        assert_eq!(DEFAULT_ORDER_BOOK_DEPTH, 20);
487        assert_eq!(MAX_RECENT_TRADES, 10000);
488        assert_eq!(DEFAULT_RECENT_TRADES, 100);
489    }
490
491    #[test]
492    fn test_error_handling_constants() {
493        #[allow(clippy::assertions_on_constants)]
495        {
496            assert!(MAX_RETRY_ATTEMPTS > 0);
497            assert!(RETRY_BASE_DELAY_MS > 0);
498            assert!(RETRY_MAX_DELAY_MS > RETRY_BASE_DELAY_MS);
499        }
500
501        assert_eq!(MAX_RETRY_ATTEMPTS, 3);
503        assert_eq!(RETRY_BASE_DELAY_MS, 1000);
504        assert_eq!(RETRY_MAX_DELAY_MS, 30000);
505    }
506}