Line data Source code
1 : /**
2 : * @file fix_messages.hpp
3 : * @brief FIX 会话层消息工厂函数
4 : *
5 : * 提供创建标准 FIX 会话层消息的便捷函数,包括:
6 : * - Logon (A) - 登录
7 : * - Heartbeat (0) - 心跳
8 : * - TestRequest (1) - 测试请求
9 : * - Logout (5) - 登出
10 : */
11 :
12 : #pragma once
13 :
14 : #include "fix/fix_codec.hpp"
15 : #include "fix/fix_tags.hpp"
16 : #include "base/config.hpp"
17 :
18 : namespace fix40 {
19 :
20 : /**
21 : * @brief 创建 Logon 消息
22 : * @param sender 发送方 CompID
23 : * @param target 接收方 CompID
24 : * @param seq_num 消息序列号(默认为 1)
25 : * @param heart_bt 心跳间隔秒数(默认从配置读取)
26 : * @return FixMessage Logon 消息对象
27 : *
28 : * Logon 消息用于建立 FIX 会话,包含:
29 : * - MsgType (35) = "A"
30 : * - EncryptMethod (98) = "0" (无加密)
31 : * - HeartBtInt (108) = 心跳间隔
32 : */
33 281 : inline FixMessage create_logon_message(const std::string& sender,
34 : const std::string& target,
35 : int seq_num = 1,
36 : int heart_bt = Config::instance().get_int("fix_session", "default_heartbeat_interval", 30),
37 : bool reset_seq_num = false) {
38 281 : FixMessage logon;
39 562 : logon.set(tags::MsgType, "A");
40 281 : logon.set(tags::EncryptMethod, "0");
41 281 : logon.set(tags::HeartBtInt, heart_bt);
42 281 : logon.set(tags::SenderCompID, sender);
43 281 : logon.set(tags::TargetCompID, target);
44 281 : logon.set(tags::MsgSeqNum, seq_num);
45 281 : if (reset_seq_num) {
46 70 : logon.set(tags::ResetSeqNumFlag, "Y");
47 : }
48 281 : return logon;
49 0 : }
50 :
51 : /**
52 : * @brief 创建 Heartbeat 消息
53 : * @param sender 发送方 CompID
54 : * @param target 接收方 CompID
55 : * @param seq_num 消息序列号
56 : * @param test_req_id TestReqID(响应 TestRequest 时填写,否则为空)
57 : * @return FixMessage Heartbeat 消息对象
58 : *
59 : * Heartbeat 消息用于:
60 : * 1. 定期发送以维持连接活跃
61 : * 2. 响应 TestRequest(此时需包含对应的 TestReqID)
62 : *
63 : * - MsgType (35) = "0"
64 : * - TestReqID (112) = 可选
65 : */
66 14 : inline FixMessage create_heartbeat_message(const std::string& sender,
67 : const std::string& target,
68 : int seq_num,
69 : const std::string& test_req_id = "") {
70 14 : FixMessage hb;
71 14 : hb.set(tags::MsgType, "0");
72 14 : hb.set(tags::SenderCompID, sender);
73 14 : hb.set(tags::TargetCompID, target);
74 14 : hb.set(tags::MsgSeqNum, seq_num);
75 :
76 14 : if (!test_req_id.empty()) {
77 4 : hb.set(tags::TestReqID, test_req_id);
78 : }
79 :
80 14 : return hb;
81 0 : }
82 :
83 : /**
84 : * @brief 创建 TestRequest 消息
85 : * @param sender 发送方 CompID
86 : * @param target 接收方 CompID
87 : * @param seq_num 消息序列号
88 : * @param test_req_id 测试请求标识符(必填,对方需在 Heartbeat 中回传)
89 : * @return FixMessage TestRequest 消息对象
90 : *
91 : * TestRequest 消息用于检测对端是否存活。
92 : * 对端收到后应回复包含相同 TestReqID 的 Heartbeat。
93 : *
94 : * - MsgType (35) = "1"
95 : * - TestReqID (112) = 必填
96 : */
97 3 : inline FixMessage create_test_request_message(const std::string& sender,
98 : const std::string& target,
99 : int seq_num,
100 : const std::string& test_req_id) {
101 3 : FixMessage tr;
102 3 : tr.set(tags::MsgType, "1");
103 3 : tr.set(tags::SenderCompID, sender);
104 3 : tr.set(tags::TargetCompID, target);
105 3 : tr.set(tags::MsgSeqNum, seq_num);
106 3 : tr.set(tags::TestReqID, test_req_id);
107 3 : return tr;
108 0 : }
109 :
110 : /**
111 : * @brief 创建 Logout 消息
112 : * @param sender 发送方 CompID
113 : * @param target 接收方 CompID
114 : * @param seq_num 消息序列号
115 : * @param text 登出原因(可选)
116 : * @return FixMessage Logout 消息对象
117 : *
118 : * Logout 消息用于优雅地终止 FIX 会话。
119 : * 发起方发送 Logout 后等待对方确认,然后关闭连接。
120 : *
121 : * - MsgType (35) = "5"
122 : * - Text (58) = 可选,说明登出原因
123 : */
124 11 : inline FixMessage create_logout_message(const std::string& sender,
125 : const std::string& target,
126 : int seq_num,
127 : const std::string& text = "") {
128 11 : FixMessage lo;
129 11 : lo.set(tags::MsgType, "5");
130 11 : lo.set(tags::SenderCompID, sender);
131 11 : lo.set(tags::TargetCompID, target);
132 11 : lo.set(tags::MsgSeqNum, seq_num);
133 11 : if (!text.empty()) {
134 10 : lo.set(tags::Text, text);
135 : }
136 11 : return lo;
137 0 : }
138 :
139 : /**
140 : * @brief 创建 ResendRequest 消息
141 : * @param sender 发送方 CompID
142 : * @param target 接收方 CompID
143 : * @param seq_num 消息序列号
144 : * @param begin_seq_no 请求重传的起始序列号
145 : * @param end_seq_no 请求重传的结束序列号(0 表示到最新)
146 : * @return FixMessage ResendRequest 消息对象
147 : *
148 : * ResendRequest 消息用于请求对方重传指定范围的消息。
149 : * 当检测到序列号 gap 时发送此消息。
150 : *
151 : * - MsgType (35) = "2"
152 : * - BeginSeqNo (7) = 起始序列号
153 : * - EndSeqNo (16) = 结束序列号(0 表示无限)
154 : */
155 3 : inline FixMessage create_resend_request_message(const std::string& sender,
156 : const std::string& target,
157 : int seq_num,
158 : int begin_seq_no,
159 : int end_seq_no) {
160 3 : FixMessage rr;
161 3 : rr.set(tags::MsgType, "2");
162 3 : rr.set(tags::SenderCompID, sender);
163 3 : rr.set(tags::TargetCompID, target);
164 3 : rr.set(tags::MsgSeqNum, seq_num);
165 3 : rr.set(tags::BeginSeqNo, begin_seq_no);
166 3 : rr.set(tags::EndSeqNo, end_seq_no);
167 3 : return rr;
168 0 : }
169 :
170 : /**
171 : * @brief 创建 SequenceReset 消息
172 : * @param sender 发送方 CompID
173 : * @param target 接收方 CompID
174 : * @param seq_num 消息序列号
175 : * @param new_seq_no 新的序列号
176 : * @param gap_fill 是否为 GapFill 模式
177 : * @return FixMessage SequenceReset 消息对象
178 : *
179 : * SequenceReset 消息用于:
180 : * 1. GapFill 模式:跳过管理消息(如 Heartbeat、TestRequest)
181 : * 2. Reset 模式:重置序列号(通常在会话重置时使用)
182 : *
183 : * - MsgType (35) = "4"
184 : * - NewSeqNo (36) = 新序列号
185 : * - GapFillFlag (123) = Y/N
186 : */
187 2 : inline FixMessage create_sequence_reset_message(const std::string& sender,
188 : const std::string& target,
189 : int seq_num,
190 : int new_seq_no,
191 : bool gap_fill = true) {
192 2 : FixMessage sr;
193 2 : sr.set(tags::MsgType, "4");
194 2 : sr.set(tags::SenderCompID, sender);
195 2 : sr.set(tags::TargetCompID, target);
196 2 : sr.set(tags::MsgSeqNum, seq_num);
197 2 : sr.set(tags::NewSeqNo, new_seq_no);
198 2 : sr.set(tags::GapFillFlag, gap_fill ? "Y" : "N");
199 2 : return sr;
200 0 : }
201 :
202 : /**
203 : * @brief 判断消息类型是否为管理消息
204 : * @param msg_type 消息类型
205 : * @return true 如果是管理消息(Heartbeat、TestRequest、ResendRequest、SequenceReset、Logout、Logon)
206 : *
207 : * 管理消息在重传时应使用 SequenceReset-GapFill 跳过,而不是重新发送。
208 : */
209 10 : inline bool is_admin_message(const std::string& msg_type) {
210 10 : return msg_type == "0" || // Heartbeat
211 9 : msg_type == "1" || // TestRequest
212 8 : msg_type == "2" || // ResendRequest
213 7 : msg_type == "4" || // SequenceReset
214 24 : msg_type == "5" || // Logout
215 15 : msg_type == "A"; // Logon
216 : }
217 :
218 : } // namespace fix40
|