Line data Source code
1 : /**
2 : * @file fix_message_builder.hpp
3 : * @brief FIX 消息构建辅助函数
4 : *
5 : * 提供将内部数据结构转换为 FIX 消息的辅助函数。
6 : */
7 :
8 : #pragma once
9 :
10 : #include "fix/fix_codec.hpp"
11 : #include "fix/fix_tags.hpp"
12 : #include "app/model/order.hpp"
13 : #include <sstream>
14 : #include <iomanip>
15 : #include <ctime>
16 :
17 : namespace fix40 {
18 :
19 : /**
20 : * @brief 格式化 UTC 时间为 FIX 格式
21 : * @param tp 时间点
22 : * @return std::string FIX 格式时间字符串 (YYYYMMDD-HH:MM:SS)
23 : */
24 705 : inline std::string formatTransactTime(std::chrono::system_clock::time_point tp) {
25 705 : auto time_t_val = std::chrono::system_clock::to_time_t(tp);
26 : std::tm tm_buf;
27 705 : gmtime_r(&time_t_val, &tm_buf);
28 :
29 705 : std::ostringstream oss;
30 705 : oss << std::put_time(&tm_buf, "%Y%m%d-%H:%M:%S");
31 1410 : return oss.str();
32 705 : }
33 :
34 : /**
35 : * @brief 将 OrderSide 转换为 FIX 字符串
36 : */
37 805 : inline std::string sideToFix(OrderSide side) {
38 1610 : return side == OrderSide::BUY ? "1" : "2";
39 : }
40 :
41 : /**
42 : * @brief 将 OrderType 转换为 FIX 字符串
43 : */
44 805 : inline std::string ordTypeToFix(OrderType type) {
45 1610 : return type == OrderType::MARKET ? "1" : "2";
46 : }
47 :
48 : /**
49 : * @brief 将 OrderStatus 转换为 FIX 字符串
50 : */
51 805 : inline std::string ordStatusToFix(OrderStatus status) {
52 805 : switch (status) {
53 783 : case OrderStatus::NEW: return "0";
54 456 : case OrderStatus::PARTIALLY_FILLED: return "1";
55 177 : case OrderStatus::FILLED: return "2";
56 483 : case OrderStatus::CANCELED: return "4";
57 0 : case OrderStatus::PENDING_CANCEL: return "6";
58 516 : case OrderStatus::REJECTED: return "8";
59 0 : case OrderStatus::PENDING_NEW: return "A"; // FIX 4.2+, 但为了兼容
60 0 : default: return "0";
61 : }
62 : }
63 :
64 : /**
65 : * @brief 将 ExecTransType 转换为 FIX 字符串
66 : */
67 705 : inline std::string execTransTypeToFix(ExecTransType type) {
68 705 : switch (type) {
69 2115 : case ExecTransType::NEW: return "0";
70 0 : case ExecTransType::CANCEL: return "1";
71 0 : case ExecTransType::CORRECT: return "2";
72 0 : case ExecTransType::STATUS: return "3";
73 0 : default: return "0";
74 : }
75 : }
76 :
77 : /**
78 : * @brief 将 ExecutionReport 转换为 FIX 消息
79 : * @param report ExecutionReport 结构
80 : * @return FixMessage FIX 消息对象
81 : *
82 : * 构建 FIX 4.0 ExecutionReport (MsgType=8) 消息。
83 : */
84 705 : inline FixMessage buildExecutionReport(const ExecutionReport& report) {
85 705 : FixMessage msg;
86 :
87 : // MsgType = 8 (ExecutionReport)
88 705 : msg.set(tags::MsgType, "8");
89 :
90 : // 标识符
91 705 : msg.set(tags::OrderID, report.orderID);
92 705 : msg.set(tags::ClOrdID, report.clOrdID);
93 705 : msg.set(tags::ExecID, report.execID);
94 :
95 705 : if (!report.origClOrdID.empty()) {
96 100 : msg.set(tags::OrigClOrdID, report.origClOrdID);
97 : }
98 :
99 : // 执行信息
100 705 : msg.set(tags::ExecTransType, execTransTypeToFix(report.execTransType));
101 705 : msg.set(tags::OrdStatus, ordStatusToFix(report.ordStatus));
102 :
103 : // 订单信息
104 705 : msg.set(tags::Symbol, report.symbol);
105 705 : msg.set(tags::Side, sideToFix(report.side));
106 705 : msg.set(tags::OrderQty, std::to_string(report.orderQty));
107 :
108 705 : if (report.ordType == OrderType::LIMIT && report.price > 0) {
109 623 : msg.set(tags::Price, std::to_string(report.price));
110 : }
111 705 : msg.set(tags::OrdType, ordTypeToFix(report.ordType));
112 :
113 : // 成交信息
114 705 : msg.set(tags::CumQty, std::to_string(report.cumQty));
115 705 : msg.set(tags::AvgPx, std::to_string(report.avgPx));
116 :
117 705 : if (report.lastShares > 0) {
118 101 : msg.set(tags::LastShares, std::to_string(report.lastShares));
119 101 : msg.set(tags::LastPx, std::to_string(report.lastPx));
120 : }
121 :
122 : // 剩余数量(FIX 4.0 没有 LeavesQty,但可以通过 OrderQty - CumQty 计算)
123 : // 这里我们用 Text 字段传递额外信息
124 :
125 : // 时间
126 705 : msg.set(tags::TransactTime, formatTransactTime(report.transactTime));
127 :
128 : // 拒绝原因
129 705 : if (report.ordStatus == OrderStatus::REJECTED && report.ordRejReason != 0) {
130 103 : msg.set(tags::OrdRejReason, std::to_string(report.ordRejReason));
131 : }
132 :
133 : // 文本说明
134 705 : if (!report.text.empty()) {
135 104 : msg.set(tags::Text, report.text);
136 : }
137 :
138 705 : return msg;
139 0 : }
140 :
141 : } // namespace fix40
|