deribit_fix/config/
mod.rs

1//! Configuration module for the Deribit FIX client
2
3use crate::error::{DeribitFixError, Result};
4use serde::{Deserialize, Serialize};
5use std::time::Duration;
6
7/// Configuration for the Deribit FIX client
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Config {
10    /// Deribit username
11    pub username: String,
12    /// Deribit password
13    pub password: String,
14    /// FIX server host (default: www.deribit.com for production, test.deribit.com for test)
15    pub host: String,
16    /// FIX server port (default: 9881 for test, 9880 for production)
17    pub port: u16,
18    /// Whether to use SSL connection (default: false for raw TCP)
19    pub use_ssl: bool,
20    /// Whether to use test environment
21    pub test_mode: bool,
22    /// Heartbeat interval in seconds (default: 30)
23    pub heartbeat_interval: u32,
24    /// Connection timeout in seconds (default: 10)
25    pub connection_timeout: Duration,
26    /// Reconnection attempts (default: 3)
27    pub reconnect_attempts: u32,
28    /// Reconnection delay in seconds (default: 5)
29    pub reconnect_delay: Duration,
30    /// Enable logging (default: true)
31    pub enable_logging: bool,
32    /// Log level filter
33    pub log_level: String,
34    /// Sender company ID for FIX messages
35    pub sender_comp_id: String,
36    /// Target company ID for FIX messages (DERIBITSERVER)
37    pub target_comp_id: String,
38    /// Cancel orders on disconnect (default: false)
39    pub cancel_on_disconnect: bool,
40    /// Application ID for registered applications
41    pub app_id: Option<String>,
42    /// Application secret for registered applications
43    pub app_secret: Option<String>,
44}
45
46impl Config {
47    /// Create a new configuration with username and password
48    pub fn new(username: String, password: String) -> Self {
49        Self {
50            username,
51            password,
52            host: "test.deribit.com".to_string(),
53            port: 9881, // Test environment by default
54            use_ssl: false,
55            test_mode: true,
56            heartbeat_interval: 30,
57            connection_timeout: Duration::from_secs(10),
58            reconnect_attempts: 3,
59            reconnect_delay: Duration::from_secs(5),
60            enable_logging: true,
61            log_level: "info".to_string(),
62            sender_comp_id: "CLIENT".to_string(),
63            target_comp_id: "DERIBITSERVER".to_string(),
64            cancel_on_disconnect: false,
65            app_id: None,
66            app_secret: None,
67        }
68    }
69
70    /// Create configuration for production environment
71    pub fn production(username: String, password: String) -> Self {
72        let mut config = Self::new(username, password);
73        config.test_mode = false;
74        config.host = "www.deribit.com".to_string();
75        config.port = 9880; // Production port
76        config
77    }
78
79    /// Create configuration for production environment with SSL
80    pub fn production_ssl(username: String, password: String) -> Self {
81        let mut config = Self::production(username, password);
82        config.use_ssl = true;
83        config.port = 9883; // Production SSL port
84        config
85    }
86
87    /// Create configuration for test environment with SSL
88    pub fn test_ssl(username: String, password: String) -> Self {
89        let mut config = Self::new(username, password);
90        config.use_ssl = true;
91        config.port = 9883; // Test SSL port
92        config
93    }
94
95    /// Set custom host and port
96    pub fn with_endpoint(mut self, host: String, port: u16) -> Self {
97        self.host = host;
98        self.port = port;
99        self
100    }
101
102    /// Enable or disable SSL
103    pub fn with_ssl(mut self, use_ssl: bool) -> Self {
104        self.use_ssl = use_ssl;
105        self
106    }
107
108    /// Set heartbeat interval
109    pub fn with_heartbeat_interval(mut self, interval: u32) -> Self {
110        self.heartbeat_interval = interval;
111        self
112    }
113
114    /// Set connection timeout
115    pub fn with_connection_timeout(mut self, timeout: Duration) -> Self {
116        self.connection_timeout = timeout;
117        self
118    }
119
120    /// Set reconnection parameters
121    pub fn with_reconnection(mut self, attempts: u32, delay: Duration) -> Self {
122        self.reconnect_attempts = attempts;
123        self.reconnect_delay = delay;
124        self
125    }
126
127    /// Set logging configuration
128    pub fn with_logging(mut self, enabled: bool, level: String) -> Self {
129        self.enable_logging = enabled;
130        self.log_level = level;
131        self
132    }
133
134    /// Set FIX session identifiers
135    pub fn with_session_ids(mut self, sender_comp_id: String, target_comp_id: String) -> Self {
136        self.sender_comp_id = sender_comp_id;
137        self.target_comp_id = target_comp_id;
138        self
139    }
140
141    /// Set cancel on disconnect behavior
142    pub fn with_cancel_on_disconnect(mut self, cancel_on_disconnect: bool) -> Self {
143        self.cancel_on_disconnect = cancel_on_disconnect;
144        self
145    }
146
147    /// Set application credentials for registered applications
148    pub fn with_app_credentials(mut self, app_id: String, app_secret: String) -> Self {
149        self.app_id = Some(app_id);
150        self.app_secret = Some(app_secret);
151        self
152    }
153
154    /// Get the connection URL
155    pub fn connection_url(&self) -> String {
156        format!("{}:{}", self.host, self.port)
157    }
158
159    /// Validate the configuration
160    pub fn validate(&self) -> Result<()> {
161        if self.username.is_empty() {
162            return Err(DeribitFixError::Config("Username cannot be empty".to_string()));
163        }
164
165        if self.password.is_empty() {
166            return Err(DeribitFixError::Config("Password cannot be empty".to_string()));
167        }
168
169        if self.host.is_empty() {
170            return Err(DeribitFixError::Config("Host cannot be empty".to_string()));
171        }
172
173        if self.port == 0 {
174            return Err(DeribitFixError::Config("Port must be greater than 0".to_string()));
175        }
176
177        if self.heartbeat_interval == 0 {
178            return Err(DeribitFixError::Config("Heartbeat interval must be greater than 0".to_string()));
179        }
180
181        if self.sender_comp_id.is_empty() {
182            return Err(DeribitFixError::Config("Sender company ID cannot be empty".to_string()));
183        }
184
185        if self.target_comp_id.is_empty() {
186            return Err(DeribitFixError::Config("Target company ID cannot be empty".to_string()));
187        }
188
189        // Validate app credentials if provided
190        if self.app_id.is_some() && self.app_secret.is_none() {
191            return Err(DeribitFixError::Config("Application secret is required when app ID is provided".to_string()));
192        }
193
194        if self.app_secret.is_some() && self.app_id.is_none() {
195            return Err(DeribitFixError::Config("Application ID is required when app secret is provided".to_string()));
196        }
197
198        Ok(())
199    }
200}
201
202impl Default for Config {
203    fn default() -> Self {
204        Self::new("".to_string(), "".to_string())
205    }
206}