deribit_fix/message/
builder.rs1use crate::error::{DeribitFixError, Result};
7use crate::model::message::FixMessage;
8use crate::model::types::MsgType;
9use chrono::{DateTime, Utc};
10
11pub struct MessageBuilder {
13 message: FixMessage,
14}
15
16impl MessageBuilder {
17 pub fn new() -> Self {
19 let mut message = FixMessage::new();
20
21 message.set_field(8, "FIX.4.4".to_string()); Self { message }
25 }
26
27 pub fn msg_type(mut self, msg_type: MsgType) -> Self {
29 self.message.set_field(35, msg_type.as_str().to_string());
30 self
31 }
32
33 pub fn sender_comp_id(mut self, sender_comp_id: String) -> Self {
35 self.message.set_field(49, sender_comp_id);
36 self
37 }
38
39 pub fn target_comp_id(mut self, target_comp_id: String) -> Self {
41 self.message.set_field(56, target_comp_id);
42 self
43 }
44
45 pub fn msg_seq_num(mut self, seq_num: u32) -> Self {
47 self.message.set_field(34, seq_num.to_string());
48 self
49 }
50
51 pub fn sending_time(mut self, time: DateTime<Utc>) -> Self {
53 let time_str = time.format("%Y%m%d-%H:%M:%S%.3f").to_string();
54 self.message.set_field(52, time_str);
55 self
56 }
57
58 pub fn field(mut self, tag: u32, value: String) -> Self {
60 self.message.set_field(tag, value);
61 self
62 }
63
64 pub fn build(mut self) -> Result<FixMessage> {
66 if !self.message.has_field(8) {
68 return Err(DeribitFixError::MessageConstruction(
69 "BeginString (8) is required".to_string(),
70 ));
71 }
72
73 if !self.message.has_field(35) {
74 return Err(DeribitFixError::MessageConstruction(
75 "MsgType (35) is required".to_string(),
76 ));
77 }
78
79 if !self.message.has_field(49) {
80 return Err(DeribitFixError::MessageConstruction(
81 "SenderCompID (49) is required".to_string(),
82 ));
83 }
84
85 if !self.message.has_field(56) {
86 return Err(DeribitFixError::MessageConstruction(
87 "TargetCompID (56) is required".to_string(),
88 ));
89 }
90
91 if !self.message.has_field(34) {
92 return Err(DeribitFixError::MessageConstruction(
93 "MsgSeqNum (34) is required".to_string(),
94 ));
95 }
96
97 if !self.message.has_field(52) {
98 let now = Utc::now();
100 let time_str = now.format("%Y%m%d-%H:%M:%S%.3f").to_string();
101 self.message.set_field(52, time_str);
102 }
103
104 let body_length = self.calculate_body_length();
106 self.message.set_field(9, body_length.to_string());
107
108 let checksum = self.message.calculate_checksum();
110 self.message.set_field(10, format!("{checksum:03}"));
111
112 let mut field_pairs: Vec<_> = self.message.fields.iter().collect();
118 field_pairs.sort_by_key(|(tag, _)| *tag);
119
120 let mut raw_parts = Vec::new();
121 let mut checksum_part = None;
122
123 if let Some((_, value)) = field_pairs.iter().find(|(tag, _)| *tag == 8) {
125 raw_parts.push(format!("8={value}"));
126 }
127
128 if let Some((_, value)) = field_pairs.iter().find(|(tag, _)| *tag == 9) {
130 raw_parts.push(format!("9={value}"));
131 }
132
133 for (tag, value) in field_pairs {
135 if *tag == 10 {
136 checksum_part = Some(format!("{tag}={value}"));
138 } else if *tag != 8 && *tag != 9 {
139 raw_parts.push(format!("{tag}={value}"));
140 }
141 }
142
143 if let Some(checksum) = checksum_part {
145 raw_parts.push(checksum);
146 }
147
148 self.message.raw_message = raw_parts.join("\x01") + "\x01";
149
150 Ok(self.message)
151 }
152
153 fn calculate_body_length(&self) -> usize {
156 let mut body_parts = Vec::new();
157
158 for (tag, value) in &self.message.fields {
160 if *tag != 8 && *tag != 9 && *tag != 10 {
161 body_parts.push(format!("{tag}={value}"));
162 }
163 }
164
165 let body_str = body_parts.join("\x01") + "\x01";
167 body_str.len()
168 }
169}
170
171impl Default for MessageBuilder {
172 fn default() -> Self {
173 Self::new()
174 }
175}