Line data Source code
1 : /**
2 : * @file client_state.cpp
3 : * @brief 客户端状态管理实现
4 : */
5 :
6 : #include "client_state.hpp"
7 : #include <algorithm>
8 : #include <chrono>
9 : #include <iomanip>
10 : #include <sstream>
11 : #include <fstream>
12 : #include <cstdlib>
13 :
14 : namespace fix40::client {
15 :
16 : // ============================================================================
17 : // 连接状态
18 : // ============================================================================
19 :
20 0 : void ClientState::setConnectionState(ConnectionState state) {
21 0 : connectionState_.store(state);
22 0 : notifyStateChange();
23 0 : }
24 :
25 0 : ConnectionState ClientState::getConnectionState() const {
26 0 : return connectionState_.load();
27 : }
28 :
29 0 : std::string ClientState::getConnectionStateString() const {
30 0 : switch (connectionState_.load()) {
31 0 : case ConnectionState::DISCONNECTED: return "断开连接";
32 0 : case ConnectionState::CONNECTING: return "连接中...";
33 0 : case ConnectionState::CONNECTED: return "已连接";
34 0 : case ConnectionState::LOGGING_IN: return "登录中...";
35 0 : case ConnectionState::LOGGED_IN: return "已登录";
36 0 : case ConnectionState::ERROR: return "错误";
37 0 : default: return "未知";
38 : }
39 : }
40 :
41 0 : void ClientState::setUserId(const std::string& userId) {
42 0 : std::lock_guard<std::mutex> lock(mutex_);
43 0 : userId_ = userId;
44 0 : }
45 :
46 0 : std::string ClientState::getUserId() const {
47 0 : std::lock_guard<std::mutex> lock(mutex_);
48 0 : return userId_;
49 0 : }
50 :
51 : // ============================================================================
52 : // 账户信息
53 : // ============================================================================
54 :
55 2 : void ClientState::updateAccount(const AccountInfo& info) {
56 : {
57 2 : std::lock_guard<std::mutex> lock(mutex_);
58 2 : account_ = info;
59 2 : }
60 2 : notifyStateChange();
61 2 : }
62 :
63 2 : AccountInfo ClientState::getAccount() const {
64 2 : std::lock_guard<std::mutex> lock(mutex_);
65 2 : return account_;
66 2 : }
67 :
68 : // ============================================================================
69 : // 持仓信息
70 : // ============================================================================
71 :
72 2 : void ClientState::updatePosition(const PositionInfo& pos) {
73 2 : bool updated = false;
74 : {
75 2 : std::lock_guard<std::mutex> lock(mutex_);
76 2 : auto it = std::find_if(positions_.begin(), positions_.end(),
77 2 : [&](const PositionInfo& p) { return p.instrumentId == pos.instrumentId; });
78 2 : if (it != positions_.end()) {
79 : // 合并更新:推送消息可能包含0数量(用于“平到0后清空持仓”)。
80 : // 仅当 quantitiesValid=true 时才认为数量字段可用(即使为0也要应用/删除)。
81 2 : if (pos.quantitiesValid && pos.longPosition == 0 && pos.shortPosition == 0) {
82 : // 持仓已清空:移除该合约持仓,避免 UI 停留在平仓前的最后一刻。
83 1 : positions_.erase(it);
84 1 : updated = true;
85 : } else {
86 1 : if (pos.quantitiesValid) {
87 0 : it->longPosition = pos.longPosition;
88 0 : it->shortPosition = pos.shortPosition;
89 : }
90 1 : if (pos.longAvgPrice > 0) it->longAvgPrice = pos.longAvgPrice;
91 1 : if (pos.shortAvgPrice > 0) it->shortAvgPrice = pos.shortAvgPrice;
92 : // 盈亏始终更新(可能为负)
93 1 : it->profit = pos.profit;
94 1 : updated = true;
95 : }
96 : } else {
97 : // 新增持仓:若推送的是“0数量清空”则忽略即可。
98 0 : if (!(pos.quantitiesValid && pos.longPosition == 0 && pos.shortPosition == 0)) {
99 0 : positions_.push_back(pos);
100 0 : updated = true;
101 : }
102 : }
103 2 : }
104 2 : if (updated) {
105 2 : notifyStateChange();
106 : }
107 2 : }
108 :
109 2 : void ClientState::setPositions(const std::vector<PositionInfo>& positions) {
110 : {
111 2 : std::lock_guard<std::mutex> lock(mutex_);
112 2 : positions_ = positions;
113 2 : }
114 2 : notifyStateChange();
115 2 : }
116 :
117 2 : std::vector<PositionInfo> ClientState::getPositions() const {
118 2 : std::lock_guard<std::mutex> lock(mutex_);
119 4 : return positions_;
120 2 : }
121 :
122 0 : void ClientState::clearPositions() {
123 : {
124 0 : std::lock_guard<std::mutex> lock(mutex_);
125 0 : positions_.clear();
126 0 : }
127 0 : notifyStateChange();
128 0 : }
129 :
130 : // ============================================================================
131 : // 订单信息
132 : // ============================================================================
133 :
134 2 : void ClientState::addOrder(const OrderInfo& order) {
135 : {
136 2 : std::lock_guard<std::mutex> lock(mutex_);
137 2 : if (orders_.find(order.clOrdID) == orders_.end()) {
138 2 : orderSequence_.push_back(order.clOrdID);
139 : }
140 2 : orders_[order.clOrdID] = order;
141 2 : }
142 2 : notifyStateChange();
143 2 : }
144 :
145 0 : void ClientState::updateOrder(const std::string& clOrdID, const OrderInfo& order) {
146 : {
147 0 : std::lock_guard<std::mutex> lock(mutex_);
148 0 : if (orders_.find(clOrdID) == orders_.end()) {
149 0 : orderSequence_.push_back(clOrdID);
150 : }
151 0 : orders_[clOrdID] = order;
152 0 : }
153 0 : notifyStateChange();
154 0 : }
155 :
156 1 : std::vector<OrderInfo> ClientState::getOrders() const {
157 1 : std::lock_guard<std::mutex> lock(mutex_);
158 1 : std::vector<OrderInfo> result;
159 1 : result.reserve(orderSequence_.size());
160 3 : for (const auto& clOrdID : orderSequence_) {
161 2 : auto it = orders_.find(clOrdID);
162 2 : if (it != orders_.end()) {
163 2 : result.push_back(it->second);
164 : }
165 : }
166 2 : return result;
167 1 : }
168 :
169 0 : std::vector<OrderInfo> ClientState::getActiveOrders() const {
170 0 : std::lock_guard<std::mutex> lock(mutex_);
171 0 : std::vector<OrderInfo> result;
172 0 : result.reserve(orderSequence_.size());
173 0 : for (const auto& clOrdID : orderSequence_) {
174 0 : auto it = orders_.find(clOrdID);
175 0 : if (it == orders_.end()) {
176 0 : continue;
177 : }
178 0 : const auto& order = it->second;
179 0 : if (order.state == OrderState::PENDING_NEW ||
180 0 : order.state == OrderState::NEW ||
181 0 : order.state == OrderState::PARTIALLY_FILLED) {
182 0 : result.push_back(order);
183 : }
184 : }
185 0 : return result;
186 0 : }
187 :
188 0 : void ClientState::clearOrders() {
189 : {
190 0 : std::lock_guard<std::mutex> lock(mutex_);
191 0 : orders_.clear();
192 0 : orderSequence_.clear();
193 0 : }
194 0 : notifyStateChange();
195 0 : }
196 :
197 0 : void ClientState::setOrders(const std::vector<OrderInfo>& orders) {
198 : {
199 0 : std::lock_guard<std::mutex> lock(mutex_);
200 0 : orders_.clear();
201 0 : orderSequence_.clear();
202 0 : orderSequence_.reserve(orders.size());
203 0 : for (const auto& order : orders) {
204 0 : if (order.clOrdID.empty()) {
205 0 : continue;
206 : }
207 0 : orderSequence_.push_back(order.clOrdID);
208 0 : orders_[order.clOrdID] = order;
209 : }
210 0 : }
211 0 : notifyStateChange();
212 0 : }
213 :
214 0 : static std::string getDefaultOrdersPath() {
215 0 : const char* home = std::getenv("HOME");
216 0 : if (home) {
217 0 : return std::string(home) + "/.fix_client_orders.dat";
218 : }
219 0 : return ".fix_client_orders.dat";
220 : }
221 :
222 0 : void ClientState::saveOrders(const std::string& filepath) {
223 0 : std::string path = filepath.empty() ? getDefaultOrdersPath() : filepath;
224 0 : std::lock_guard<std::mutex> lock(mutex_);
225 :
226 0 : std::ofstream ofs(path);
227 0 : if (!ofs) return;
228 :
229 : // 简单的文本格式:每行一个订单,字段用 | 分隔
230 0 : for (const auto& clOrdID : orderSequence_) {
231 0 : auto it = orders_.find(clOrdID);
232 0 : if (it == orders_.end()) {
233 0 : continue;
234 : }
235 0 : const auto& order = it->second;
236 0 : ofs << order.clOrdID << "|"
237 0 : << order.orderId << "|"
238 0 : << order.symbol << "|"
239 0 : << order.side << "|"
240 0 : << order.price << "|"
241 0 : << order.orderQty << "|"
242 0 : << order.filledQty << "|"
243 0 : << order.avgPx << "|"
244 0 : << static_cast<int>(order.state) << "|"
245 0 : << order.text << "|"
246 0 : << order.updateTime << "\n";
247 : }
248 0 : }
249 :
250 0 : void ClientState::loadOrders(const std::string& filepath) {
251 0 : std::string path = filepath.empty() ? getDefaultOrdersPath() : filepath;
252 :
253 0 : std::ifstream ifs(path);
254 0 : if (!ifs) return;
255 :
256 0 : std::lock_guard<std::mutex> lock(mutex_);
257 0 : orders_.clear();
258 0 : orderSequence_.clear();
259 :
260 0 : std::string line;
261 0 : while (std::getline(ifs, line)) {
262 0 : if (line.empty()) continue;
263 :
264 0 : std::vector<std::string> fields;
265 0 : std::istringstream iss(line);
266 0 : std::string field;
267 0 : while (std::getline(iss, field, '|')) {
268 0 : fields.push_back(field);
269 : }
270 :
271 : // 至少需要 9 个字段(到 state)
272 0 : if (fields.size() >= 9) {
273 : try {
274 0 : OrderInfo order;
275 0 : order.clOrdID = fields[0];
276 0 : order.orderId = fields[1];
277 0 : order.symbol = fields[2];
278 0 : order.side = fields[3];
279 0 : order.price = std::stod(fields[4]);
280 0 : order.orderQty = std::stoll(fields[5]);
281 0 : order.filledQty = std::stoll(fields[6]);
282 0 : order.avgPx = std::stod(fields[7]);
283 0 : order.state = static_cast<OrderState>(std::stoi(fields[8]));
284 0 : if (fields.size() > 9) order.text = fields[9];
285 0 : if (fields.size() > 10) order.updateTime = fields[10];
286 0 : orders_[order.clOrdID] = order;
287 0 : orderSequence_.push_back(order.clOrdID);
288 0 : } catch (...) {
289 : // 解析失败,跳过该条目
290 0 : }
291 : }
292 0 : }
293 :
294 : // 旧版本保存顺序来自 unordered_map,可能是“随机”的。
295 : // 这里按 clOrdID 做一次稳定排序,至少能让展示顺序可预测(也更接近下单序号)。
296 0 : std::sort(orderSequence_.begin(), orderSequence_.end());
297 0 : orderSequence_.erase(std::unique(orderSequence_.begin(), orderSequence_.end()),
298 0 : orderSequence_.end());
299 0 : }
300 :
301 : // ============================================================================
302 : // 合约搜索结果
303 : // ============================================================================
304 :
305 0 : void ClientState::setSearchResults(const std::vector<std::string>& results) {
306 : {
307 0 : std::lock_guard<std::mutex> lock(mutex_);
308 0 : searchResults_ = results;
309 0 : }
310 0 : notifyStateChange();
311 0 : }
312 :
313 0 : std::vector<std::string> ClientState::getSearchResults() const {
314 0 : std::lock_guard<std::mutex> lock(mutex_);
315 0 : return searchResults_;
316 0 : }
317 :
318 : // ============================================================================
319 : // 状态变更通知
320 : // ============================================================================
321 :
322 0 : void ClientState::setOnStateChange(StateChangeCallback callback) {
323 0 : std::lock_guard<std::mutex> lock(mutex_);
324 0 : onStateChange_ = std::move(callback);
325 0 : }
326 :
327 10 : void ClientState::notifyStateChange() {
328 10 : StateChangeCallback callback;
329 : {
330 10 : std::lock_guard<std::mutex> lock(mutex_);
331 :
332 : // 节流:最多每 50ms 通知一次,避免高频刷新导致崩溃
333 10 : auto now = std::chrono::steady_clock::now();
334 10 : auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastNotifyTime_);
335 10 : if (elapsed.count() < 50) {
336 6 : return;
337 : }
338 4 : lastNotifyTime_ = now;
339 :
340 4 : callback = onStateChange_;
341 10 : }
342 4 : if (callback) {
343 0 : callback();
344 : }
345 10 : }
346 :
347 : // ============================================================================
348 : // 消息/错误
349 : // ============================================================================
350 :
351 0 : void ClientState::setLastError(const std::string& error) {
352 : {
353 0 : std::lock_guard<std::mutex> lock(mutex_);
354 0 : lastError_ = error;
355 0 : }
356 0 : notifyStateChange();
357 0 : }
358 :
359 0 : std::string ClientState::getLastError() const {
360 0 : std::lock_guard<std::mutex> lock(mutex_);
361 0 : return lastError_;
362 0 : }
363 :
364 2 : void ClientState::addMessage(const std::string& msg) {
365 : {
366 2 : std::lock_guard<std::mutex> lock(mutex_);
367 : // 获取当前时间
368 2 : auto now = std::chrono::system_clock::now();
369 2 : auto time = std::chrono::system_clock::to_time_t(now);
370 2 : std::ostringstream oss;
371 2 : std::tm tm_buf{};
372 : #if defined(_WIN32)
373 : localtime_s(&tm_buf, &time);
374 : #else
375 2 : localtime_r(&time, &tm_buf);
376 : #endif
377 2 : oss << std::put_time(&tm_buf, "%H:%M:%S") << " " << msg;
378 2 : messages_.push_back(oss.str());
379 : // 保留最近 100 条消息
380 2 : if (messages_.size() > 100) {
381 0 : messages_.erase(messages_.begin());
382 : }
383 2 : }
384 2 : notifyStateChange();
385 2 : }
386 :
387 0 : std::vector<std::string> ClientState::getMessages() const {
388 0 : std::lock_guard<std::mutex> lock(mutex_);
389 0 : return messages_;
390 0 : }
391 :
392 : } // namespace fix40::client
|