FIX 4.0 Demo 1.0
Loading...
Searching...
No Matches
fix_codec.hpp
Go to the documentation of this file.
1
9#pragma once
10
11#include <cstdint>
12#include <ctime>
13#include <iomanip>
14#include <numeric>
15#include <stdexcept>
16#include <string>
17#include <sstream>
18#include <unordered_map>
19#include <vector>
20#include <algorithm>
21#include <array>
22
23#include "fix/fix_tags.hpp"
24
25namespace fix40 {
26
28constexpr char SOH = '\x01';
29
47public:
53 void set(int tag, const std::string& value) { fields_[tag] = value; }
54
60 void set(int tag, int value) { fields_[tag] = std::to_string(value); }
61
68 std::string get_string(int tag) const {
69 auto it = fields_.find(tag);
70 if (it == fields_.end()) {
71 throw std::runtime_error("Tag not found: " + std::to_string(tag));
72 }
73 return it->second;
74 }
75
82 int get_int(int tag) const {
83 return std::stoi(get_string(tag));
84 }
85
92 bool has(int tag) const {
93 return fields_.count(tag) > 0;
94 }
95
100 const std::unordered_map<int, std::string>& get_fields() const {
101 return fields_;
102 }
103
104private:
105 friend class FixCodec;
106 std::unordered_map<int, std::string> fields_;
107};
108
109
133class FixCodec {
134public:
142 std::string encode(FixMessage& msg) const {
143 // 1. 准备时间戳
144 char ts[32];
145 generate_utc_timestamp(ts, sizeof(ts));
146 msg.set(tags::SendingTime, ts);
147
148 // 2. 构造标准 Header(除 8= 和 9= 之外)
149 static constexpr std::array<int, 5> kStdHeaderOrder = {
150 tags::MsgType, // 35
151 tags::SenderCompID, // 49
152 tags::TargetCompID, // 56
153 tags::MsgSeqNum, // 34
155 };
156
157 std::ostringstream header_rest_ss;
158 for (int tag : kStdHeaderOrder) {
159 if (msg.has(tag)) {
160 header_rest_ss << tag << "=" << msg.get_string(tag) << SOH;
161 }
162 }
163
164 // 3. 构造报文体 (Body) —— 仅业务字段
165 std::string body_str = build_body_from_message(msg);
166
167 std::string header_rest = header_rest_ss.str();
168
169 // 4. 计算 BodyLength (从 35= 起始到 CheckSum 前一个 SOH)
170 std::size_t body_length_val = header_rest.size() + body_str.size();
171 msg.set(tags::BodyLength, static_cast<int>(body_length_val));
172
173 // 5. 构造最终前缀(8= & 9= + HeaderRest + Body)
174 std::ostringstream prefix_ss;
175 prefix_ss << tags::BeginString << "=" << "FIX.4.0" << SOH
177 << header_rest
178 << body_str; // 如果 body_str 非空,则其已包含 SOH 分隔符
179
180 std::string prefix = prefix_ss.str();
181
182 // 6. 计算并附加校验和
183 std::string checksum = calculate_checksum(prefix);
184 return prefix + std::to_string(tags::CheckSum) + "=" + checksum + SOH;
185 }
186
193 FixMessage decode(const std::string& raw) const {
194 // 1. 校验和验证
195 const std::string checksum_tag = std::string(1, SOH) + std::to_string(tags::CheckSum) + "=";
196 const size_t checksum_pos = raw.rfind(checksum_tag);
197 if (checksum_pos == std::string::npos) {
198 throw std::runtime_error("Tag 10 (Checksum) not found");
199 }
200 const std::string prefix = raw.substr(0, checksum_pos + 1);
201 const std::string expected_checksum = raw.substr(checksum_pos + checksum_tag.length(), 3);
202 const std::string actual_checksum = calculate_checksum(prefix);
203 if (expected_checksum != actual_checksum) {
204 throw std::runtime_error("Checksum mismatch: expected " + expected_checksum + ", got " + actual_checksum);
205 }
206
207 // 2. 逐字段解析
208 FixMessage msg;
209 size_t pos = 0;
210 size_t next_soh;
211 while ((next_soh = raw.find(SOH, pos)) != std::string::npos) {
212 const std::string field = raw.substr(pos, next_soh - pos);
213 if (field.empty()) {
214 pos = next_soh + 1;
215 continue;
216 }
217 const size_t eq_pos = field.find('=');
218 if (eq_pos == std::string::npos) {
219 throw std::runtime_error("Invalid field format: " + field);
220 }
221 int tag = std::stoi(field.substr(0, eq_pos));
222 std::string value = field.substr(eq_pos + 1);
223 msg.set(tag, value);
224 pos = next_soh + 1;
225 }
226
227 // 3. BodyLength 验证
228 const int body_len_from_msg = msg.get_int(tags::BodyLength);
229 const size_t body_start_pos = raw.find(SOH, raw.find(std::to_string(tags::BodyLength) + "=")) + 1;
230 const size_t actual_body_len = checksum_pos + 1 - body_start_pos;
231 if (static_cast<size_t>(body_len_from_msg) != actual_body_len) {
232 throw std::runtime_error("BodyLength mismatch: expected " + std::to_string(body_len_from_msg) + ", got " + std::to_string(actual_body_len));
233 }
234
235 return msg;
236 }
237
238private:
244 std::string build_body_from_message(const FixMessage& msg) const {
245 std::ostringstream body;
246
247 // 定义哪些 tag 属于 Body,并按 tag 升序排列以提高一致性
248 std::vector<int> body_tags;
249 for (const auto& pair : msg.get_fields()) {
250 // Body 部分包含除标准头 (8,9,35,49,56,34,52) 和尾 (10) 之外的所有字段
251 if (pair.first != tags::BeginString && pair.first != tags::BodyLength && pair.first != tags::CheckSum &&
252 pair.first != tags::MsgType && pair.first != tags::SenderCompID && pair.first != tags::TargetCompID &&
253 pair.first != tags::MsgSeqNum && pair.first != tags::SendingTime) {
254 body_tags.push_back(pair.first);
255 }
256 }
257 std::sort(body_tags.begin(), body_tags.end());
258
259 for (int tag : body_tags) {
260 body << tag << "=" << msg.get_string(tag) << SOH;
261 }
262
263 return body.str();
264 }
265
273 std::string calculate_checksum(const std::string& data) const {
274 const uint32_t sum = std::accumulate(data.begin(), data.end(), 0U);
275 std::ostringstream oss;
276 oss << std::setfill('0') << std::setw(3) << (sum % 256);
277 return oss.str();
278 }
279
287 void generate_utc_timestamp(char* buf, size_t buf_size) const {
288 std::time_t t = std::time(nullptr);
289 std::tm tm{};
290#ifdef _WIN32
291 gmtime_s(&tm, &t);
292#else
293 gmtime_r(&t, &tm);
294#endif
295 std::strftime(buf, buf_size, "%Y%m%d-%H:%M:%S", &tm);
296 }
297};
298} // fix40 名称空间结束
FIX 消息编解码器
Definition fix_codec.hpp:133
FixMessage decode(const std::string &raw) const
将 FIX 协议字符串解码为 FixMessage 对象
Definition fix_codec.hpp:193
std::string encode(FixMessage &msg) const
将 FixMessage 编码为 FIX 协议字符串
Definition fix_codec.hpp:142
FIX 消息的面向对象封装
Definition fix_codec.hpp:46
void set(int tag, const std::string &value)
设置字符串类型字段
Definition fix_codec.hpp:53
const std::unordered_map< int, std::string > & get_fields() const
获取所有字段的只读引用
Definition fix_codec.hpp:100
std::string get_string(int tag) const
获取字符串类型字段值
Definition fix_codec.hpp:68
bool has(int tag) const
检查标签是否存在
Definition fix_codec.hpp:92
void set(int tag, int value)
设置整数类型字段
Definition fix_codec.hpp:60
int get_int(int tag) const
获取整数类型字段值
Definition fix_codec.hpp:82
FIX 4.0 协议标签定义
constexpr int BeginString
协议版本标识,固定为 "FIX.4.0"
Definition fix_tags.hpp:27
constexpr int MsgSeqNum
消息序列号
Definition fix_tags.hpp:42
constexpr int SenderCompID
发送方标识符
Definition fix_tags.hpp:36
constexpr int TargetCompID
接收方标识符
Definition fix_tags.hpp:39
constexpr int BodyLength
消息体长度(从 Tag 35 到 CheckSum 前的字节数)
Definition fix_tags.hpp:30
constexpr int MsgType
消息类型(如 "A"=Logon, "0"=Heartbeat, "5"=Logout)
Definition fix_tags.hpp:33
constexpr int SendingTime
发送时间(UTC 格式:YYYYMMDD-HH:MM:SS)
Definition fix_tags.hpp:45
constexpr int CheckSum
校验和(消息所有字节之和 mod 256,3 位数字)
Definition fix_tags.hpp:72
Definition matching_engine.hpp:23
constexpr char SOH
FIX 字段分隔符:ASCII SOH (0x01)
Definition fix_codec.hpp:28