1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7pub enum FixVersion {
8 #[serde(rename = "FIX.4.2")]
10 Fix42,
11 #[default]
13 #[serde(rename = "FIX.4.4")]
14 Fix44,
15}
16
17impl FixVersion {
18 #[must_use]
20 pub fn begin_string(&self) -> &'static str {
21 match self {
22 Self::Fix42 => "FIX.4.2",
23 Self::Fix44 => "FIX.4.4",
24 }
25 }
26}
27
28impl std::fmt::Display for FixVersion {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 write!(f, "{}", self.begin_string())
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct FixConfig {
37 pub version: FixVersion,
39 pub sender_comp_id: String,
41 pub target_comp_id: String,
43 pub host: String,
45 pub port: u16,
47 pub heartbeat_interval_secs: u32,
49 pub reconnect_enabled: bool,
51 pub reconnect_max_attempts: u32,
53 pub reconnect_delay_ms: u64,
55 pub message_logging: bool,
57 pub reset_on_logon: bool,
59}
60
61impl Default for FixConfig {
62 fn default() -> Self {
63 Self {
64 version: FixVersion::Fix44,
65 sender_comp_id: String::new(),
66 target_comp_id: "ALPACA".to_string(),
67 host: "fix.alpaca.markets".to_string(),
68 port: 5001,
69 heartbeat_interval_secs: 30,
70 reconnect_enabled: true,
71 reconnect_max_attempts: 5,
72 reconnect_delay_ms: 1000,
73 message_logging: false,
74 reset_on_logon: false,
75 }
76 }
77}
78
79impl FixConfig {
80 #[must_use]
82 pub fn builder() -> FixConfigBuilder {
83 FixConfigBuilder::default()
84 }
85}
86
87#[derive(Debug, Default)]
89pub struct FixConfigBuilder {
90 config: FixConfig,
91}
92
93impl FixConfigBuilder {
94 #[must_use]
96 pub fn version(mut self, version: FixVersion) -> Self {
97 self.config.version = version;
98 self
99 }
100
101 #[must_use]
103 pub fn sender_comp_id(mut self, id: &str) -> Self {
104 self.config.sender_comp_id = id.to_string();
105 self
106 }
107
108 #[must_use]
110 pub fn target_comp_id(mut self, id: &str) -> Self {
111 self.config.target_comp_id = id.to_string();
112 self
113 }
114
115 #[must_use]
117 pub fn host(mut self, host: &str) -> Self {
118 self.config.host = host.to_string();
119 self
120 }
121
122 #[must_use]
124 pub fn port(mut self, port: u16) -> Self {
125 self.config.port = port;
126 self
127 }
128
129 #[must_use]
131 pub fn heartbeat_interval_secs(mut self, secs: u32) -> Self {
132 self.config.heartbeat_interval_secs = secs;
133 self
134 }
135
136 #[must_use]
138 pub fn reconnect_enabled(mut self, enabled: bool) -> Self {
139 self.config.reconnect_enabled = enabled;
140 self
141 }
142
143 #[must_use]
145 pub fn reconnect_max_attempts(mut self, attempts: u32) -> Self {
146 self.config.reconnect_max_attempts = attempts;
147 self
148 }
149
150 #[must_use]
152 pub fn reconnect_delay_ms(mut self, ms: u64) -> Self {
153 self.config.reconnect_delay_ms = ms;
154 self
155 }
156
157 #[must_use]
159 pub fn message_logging(mut self, enabled: bool) -> Self {
160 self.config.message_logging = enabled;
161 self
162 }
163
164 #[must_use]
166 pub fn reset_on_logon(mut self, reset: bool) -> Self {
167 self.config.reset_on_logon = reset;
168 self
169 }
170
171 #[must_use]
173 pub fn build(self) -> FixConfig {
174 self.config
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn test_fix_version_begin_string() {
184 assert_eq!(FixVersion::Fix42.begin_string(), "FIX.4.2");
185 assert_eq!(FixVersion::Fix44.begin_string(), "FIX.4.4");
186 }
187
188 #[test]
189 fn test_fix_config_builder() {
190 let config = FixConfig::builder()
191 .version(FixVersion::Fix42)
192 .sender_comp_id("SENDER")
193 .target_comp_id("TARGET")
194 .host("localhost")
195 .port(9000)
196 .heartbeat_interval_secs(60)
197 .build();
198
199 assert_eq!(config.version, FixVersion::Fix42);
200 assert_eq!(config.sender_comp_id, "SENDER");
201 assert_eq!(config.target_comp_id, "TARGET");
202 assert_eq!(config.host, "localhost");
203 assert_eq!(config.port, 9000);
204 assert_eq!(config.heartbeat_interval_secs, 60);
205 }
206
207 #[test]
208 fn test_fix_config_default() {
209 let config = FixConfig::default();
210 assert_eq!(config.version, FixVersion::Fix44);
211 assert_eq!(config.target_comp_id, "ALPACA");
212 assert_eq!(config.port, 5001);
213 }
214}