pub const DERIBIT_WS_URL_PROD: &str = "wss://www.deribit.com/ws/api/v2";
pub const DERIBIT_WS_URL_TEST: &str = "wss://test.deribit.com/ws/api/v2";
pub const DERIBIT_HTTP_URL_PROD: &str = "https://www.deribit.com/api/v2";
pub const DERIBIT_HTTP_URL_TEST: &str = "https://test.deribit.com/api/v2";
pub const MAX_REQUESTS_PER_SECOND_AUTH: u32 = 20;
pub const MAX_REQUESTS_PER_SECOND_UNAUTH: u32 = 10;
pub const MAX_SUBSCRIPTIONS_PER_CONNECTION: u32 = 200;
pub const MAX_MESSAGE_SIZE_BYTES: usize = 65536;
pub const DEFAULT_CONNECTION_TIMEOUT_MS: u64 = 5000;
pub const DEFAULT_REQUEST_TIMEOUT_MS: u64 = 10000;
pub const HEARTBEAT_INTERVAL_MS: u64 = 10000;
pub const HEARTBEAT_TIMEOUT_MS: u64 = 5000;
pub const SUPPORTED_CRYPTOCURRENCIES: &[&str] = &["BTC", "ETH", "SOL", "USDC", "USDT", "EURR"];
pub const CURRENCY_BTC: &str = "BTC";
pub const CURRENCY_ETH: &str = "ETH";
pub const CURRENCY_SOL: &str = "SOL";
pub const CURRENCY_USDC: &str = "USDC";
pub const CURRENCY_USDT: &str = "USDT";
pub const CURRENCY_EURR: &str = "EURR";
pub const INSTRUMENT_TYPE_FUTURE: &str = "future";
pub const INSTRUMENT_TYPE_OPTION: &str = "option";
pub const INSTRUMENT_TYPE_PERPETUAL: &str = "perpetual";
pub const INSTRUMENT_TYPE_SPOT: &str = "spot";
pub const INSTRUMENT_TYPE_FUTURE_COMBO: &str = "future_combo";
pub const INSTRUMENT_TYPE_OPTION_COMBO: &str = "option_combo";
pub const MIN_ORDER_AMOUNT_BTC: f64 = 0.0001;
pub const MIN_ORDER_AMOUNT_ETH: f64 = 0.001;
pub const MIN_ORDER_AMOUNT_SOL: f64 = 0.1;
pub const MAX_ORDER_AMOUNT: f64 = 1_000_000.0;
pub const MAX_OPEN_ORDERS_PER_INSTRUMENT: u32 = 500;
pub const MAX_OPEN_ORDERS_TOTAL: u32 = 2000;
pub const PRICE_PRECISION_BTC: u8 = 8;
pub const PRICE_PRECISION_ETH: u8 = 4;
pub const PRICE_PRECISION_SOL: u8 = 4;
pub const AMOUNT_PRECISION_BTC: u8 = 4;
pub const AMOUNT_PRECISION_ETH: u8 = 3;
pub const AMOUNT_PRECISION_SOL: u8 = 1;
pub const JSONRPC_VERSION: &str = "2.0";
pub const DEFAULT_REQUEST_ID: u64 = 1;
pub const CHANNEL_BOOK: &str = "book";
pub const CHANNEL_TRADES: &str = "trades";
pub const CHANNEL_TICKER: &str = "ticker";
pub const CHANNEL_QUOTE: &str = "quote";
pub const CHANNEL_USER_ORDERS: &str = "user.orders";
pub const CHANNEL_USER_TRADES: &str = "user.trades";
pub const CHANNEL_USER_PORTFOLIO: &str = "user.portfolio";
pub const FIX_VERSION: &str = "FIX.4.4";
pub const FIX_DELIMITER: char = '\x01';
pub const FIX_DELIMITER_STR: &str = "\x01";
pub const FIX_HEARTBEAT_INTERVAL: u32 = 30;
pub const MAX_RETRY_ATTEMPTS: u8 = 3;
pub const RETRY_BASE_DELAY_MS: u64 = 1000;
pub const RETRY_MAX_DELAY_MS: u64 = 30000;
pub const MAX_ORDER_BOOK_DEPTH: u32 = 10000;
pub const DEFAULT_ORDER_BOOK_DEPTH: u32 = 20;
pub const MAX_RECENT_TRADES: u32 = 10000;
pub const DEFAULT_RECENT_TRADES: u32 = 100;
pub const ACCESS_TOKEN_EXPIRATION_SEC: u64 = 28800;
pub const REFRESH_TOKEN_EXPIRATION_SEC: u64 = 2592000;
pub const TOKEN_REFRESH_BUFFER_SEC: u64 = 300;
pub fn get_min_order_amount(currency: &str) -> f64 {
match currency {
CURRENCY_BTC => MIN_ORDER_AMOUNT_BTC,
CURRENCY_ETH => MIN_ORDER_AMOUNT_ETH,
CURRENCY_SOL => MIN_ORDER_AMOUNT_SOL,
_ => MIN_ORDER_AMOUNT_BTC, }
}
pub fn get_price_precision(currency: &str) -> u8 {
match currency {
CURRENCY_BTC => PRICE_PRECISION_BTC,
CURRENCY_ETH => PRICE_PRECISION_ETH,
CURRENCY_SOL => PRICE_PRECISION_SOL,
_ => PRICE_PRECISION_BTC, }
}
pub fn get_amount_precision(currency: &str) -> u8 {
match currency {
CURRENCY_BTC => AMOUNT_PRECISION_BTC,
CURRENCY_ETH => AMOUNT_PRECISION_ETH,
CURRENCY_SOL => AMOUNT_PRECISION_SOL,
_ => AMOUNT_PRECISION_BTC, }
}
pub fn is_supported_currency(currency: &str) -> bool {
matches!(
currency,
CURRENCY_BTC | CURRENCY_ETH | CURRENCY_SOL | CURRENCY_USDC | CURRENCY_USDT | CURRENCY_EURR
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_urls() {
assert!(DERIBIT_WS_URL_PROD.starts_with("wss://"));
assert!(DERIBIT_WS_URL_TEST.starts_with("wss://"));
assert!(DERIBIT_HTTP_URL_PROD.starts_with("https://"));
assert!(DERIBIT_HTTP_URL_TEST.starts_with("https://"));
assert!(DERIBIT_WS_URL_PROD.contains("www.deribit.com"));
assert!(DERIBIT_WS_URL_TEST.contains("test.deribit.com"));
}
#[test]
fn test_supported_currencies() {
assert!(is_supported_currency(CURRENCY_BTC));
assert!(is_supported_currency(CURRENCY_ETH));
assert!(is_supported_currency(CURRENCY_SOL));
assert!(is_supported_currency(CURRENCY_USDC));
assert!(is_supported_currency(CURRENCY_USDT));
assert!(is_supported_currency(CURRENCY_EURR));
assert!(!is_supported_currency("INVALID"));
assert!(!is_supported_currency("XRP"));
}
#[test]
fn test_min_order_amounts() {
assert_eq!(get_min_order_amount(CURRENCY_BTC), MIN_ORDER_AMOUNT_BTC);
assert_eq!(get_min_order_amount(CURRENCY_ETH), MIN_ORDER_AMOUNT_ETH);
assert_eq!(get_min_order_amount(CURRENCY_SOL), MIN_ORDER_AMOUNT_SOL);
assert_eq!(get_min_order_amount("UNKNOWN"), MIN_ORDER_AMOUNT_BTC);
}
#[test]
fn test_precision_functions() {
assert_eq!(get_price_precision(CURRENCY_BTC), PRICE_PRECISION_BTC);
assert_eq!(get_price_precision(CURRENCY_ETH), PRICE_PRECISION_ETH);
assert_eq!(get_price_precision(CURRENCY_SOL), PRICE_PRECISION_SOL);
assert_eq!(get_amount_precision(CURRENCY_BTC), AMOUNT_PRECISION_BTC);
assert_eq!(get_amount_precision(CURRENCY_ETH), AMOUNT_PRECISION_ETH);
assert_eq!(get_amount_precision(CURRENCY_SOL), AMOUNT_PRECISION_SOL);
}
#[test]
fn test_rate_limits() {
#[allow(clippy::assertions_on_constants)]
{
assert!(MAX_REQUESTS_PER_SECOND_AUTH > MAX_REQUESTS_PER_SECOND_UNAUTH);
assert!(MAX_SUBSCRIPTIONS_PER_CONNECTION > 0);
assert!(MAX_MESSAGE_SIZE_BYTES > 0);
}
assert_eq!(MAX_REQUESTS_PER_SECOND_AUTH, 20);
assert_eq!(MAX_REQUESTS_PER_SECOND_UNAUTH, 10);
assert_eq!(MAX_SUBSCRIPTIONS_PER_CONNECTION, 200);
assert_eq!(MAX_MESSAGE_SIZE_BYTES, 65536);
}
#[test]
fn test_timeouts() {
#[allow(clippy::assertions_on_constants)]
{
assert!(DEFAULT_CONNECTION_TIMEOUT_MS > 0);
assert!(DEFAULT_REQUEST_TIMEOUT_MS > DEFAULT_CONNECTION_TIMEOUT_MS);
assert!(HEARTBEAT_INTERVAL_MS > HEARTBEAT_TIMEOUT_MS);
}
assert_eq!(DEFAULT_CONNECTION_TIMEOUT_MS, 5000);
assert_eq!(DEFAULT_REQUEST_TIMEOUT_MS, 10000);
assert_eq!(HEARTBEAT_INTERVAL_MS, 10000);
assert_eq!(HEARTBEAT_TIMEOUT_MS, 5000);
}
#[test]
fn test_order_limits() {
#[allow(clippy::assertions_on_constants)]
{
assert!(MIN_ORDER_AMOUNT_BTC > 0.0);
assert!(MIN_ORDER_AMOUNT_ETH > 0.0);
assert!(MIN_ORDER_AMOUNT_SOL > 0.0);
assert!(MAX_ORDER_AMOUNT > MIN_ORDER_AMOUNT_BTC);
assert!(MAX_OPEN_ORDERS_TOTAL > MAX_OPEN_ORDERS_PER_INSTRUMENT);
}
assert_eq!(get_min_order_amount(CURRENCY_BTC), MIN_ORDER_AMOUNT_BTC);
assert_eq!(get_min_order_amount(CURRENCY_ETH), MIN_ORDER_AMOUNT_ETH);
assert_eq!(get_min_order_amount(CURRENCY_SOL), MIN_ORDER_AMOUNT_SOL);
}
#[test]
fn test_jsonrpc_constants() {
assert_eq!(JSONRPC_VERSION, "2.0");
#[allow(clippy::assertions_on_constants)]
{
assert!(DEFAULT_REQUEST_ID > 0);
}
assert_eq!(DEFAULT_REQUEST_ID, 1);
}
#[test]
fn test_fix_constants() {
assert_eq!(FIX_VERSION, "FIX.4.4");
assert_eq!(FIX_DELIMITER, '\x01');
assert_eq!(FIX_DELIMITER_STR, "\x01");
#[allow(clippy::assertions_on_constants)]
{
assert!(FIX_HEARTBEAT_INTERVAL > 0);
}
assert_eq!(FIX_HEARTBEAT_INTERVAL, 30);
}
#[test]
fn test_channel_names() {
#[allow(clippy::const_is_empty)]
{
assert!(!CHANNEL_BOOK.is_empty());
assert!(!CHANNEL_TRADES.is_empty());
assert!(!CHANNEL_TICKER.is_empty());
assert!(!CHANNEL_QUOTE.is_empty());
}
assert_eq!(CHANNEL_BOOK, "book");
assert_eq!(CHANNEL_TRADES, "trades");
assert_eq!(CHANNEL_TICKER, "ticker");
assert_eq!(CHANNEL_QUOTE, "quote");
assert!(CHANNEL_USER_ORDERS.starts_with("user."));
assert!(CHANNEL_USER_TRADES.starts_with("user."));
assert!(CHANNEL_USER_PORTFOLIO.starts_with("user."));
}
#[test]
fn test_instrument_types() {
let types = [
INSTRUMENT_TYPE_FUTURE,
INSTRUMENT_TYPE_OPTION,
INSTRUMENT_TYPE_PERPETUAL,
INSTRUMENT_TYPE_SPOT,
INSTRUMENT_TYPE_FUTURE_COMBO,
INSTRUMENT_TYPE_OPTION_COMBO,
];
for instrument_type in types {
assert!(!instrument_type.is_empty());
}
}
#[test]
fn test_authentication_constants() {
#[allow(clippy::assertions_on_constants)]
{
assert!(ACCESS_TOKEN_EXPIRATION_SEC > 0);
assert!(REFRESH_TOKEN_EXPIRATION_SEC > ACCESS_TOKEN_EXPIRATION_SEC);
assert!(TOKEN_REFRESH_BUFFER_SEC < ACCESS_TOKEN_EXPIRATION_SEC);
}
assert_eq!(ACCESS_TOKEN_EXPIRATION_SEC, 28800); assert_eq!(REFRESH_TOKEN_EXPIRATION_SEC, 2592000); assert_eq!(TOKEN_REFRESH_BUFFER_SEC, 300); }
#[test]
fn test_market_data_constants() {
#[allow(clippy::assertions_on_constants)]
{
assert!(MAX_ORDER_BOOK_DEPTH > DEFAULT_ORDER_BOOK_DEPTH);
assert!(MAX_RECENT_TRADES > DEFAULT_RECENT_TRADES);
assert!(DEFAULT_ORDER_BOOK_DEPTH > 0);
assert!(DEFAULT_RECENT_TRADES > 0);
}
assert_eq!(MAX_ORDER_BOOK_DEPTH, 10000);
assert_eq!(DEFAULT_ORDER_BOOK_DEPTH, 20);
assert_eq!(MAX_RECENT_TRADES, 10000);
assert_eq!(DEFAULT_RECENT_TRADES, 100);
}
#[test]
fn test_error_handling_constants() {
#[allow(clippy::assertions_on_constants)]
{
assert!(MAX_RETRY_ATTEMPTS > 0);
assert!(RETRY_BASE_DELAY_MS > 0);
assert!(RETRY_MAX_DELAY_MS > RETRY_BASE_DELAY_MS);
}
assert_eq!(MAX_RETRY_ATTEMPTS, 3);
assert_eq!(RETRY_BASE_DELAY_MS, 1000);
assert_eq!(RETRY_MAX_DELAY_MS, 30000);
}
}