Line data Source code
1 : /**
2 : * @file instrument_manager.cpp
3 : * @brief 合约信息管理模块实现
4 : */
5 :
6 : #include "app/manager/instrument_manager.hpp"
7 : #include <fstream>
8 : #include <sstream>
9 : #include <stdexcept>
10 : #include <algorithm>
11 :
12 : namespace fix40 {
13 :
14 : // =============================================================================
15 : // 简单JSON解析辅助函数
16 : // =============================================================================
17 :
18 : namespace {
19 :
20 : /**
21 : * @brief 跳过空白字符
22 : */
23 105 : void skipWhitespace(const std::string& json, size_t& pos) {
24 741 : while (pos < json.size() && std::isspace(json[pos])) {
25 636 : ++pos;
26 : }
27 105 : }
28 :
29 : /**
30 : * @brief 解析字符串值
31 : */
32 32 : std::string parseString(const std::string& json, size_t& pos) {
33 32 : if (json[pos] != '"') {
34 0 : throw std::runtime_error("Expected '\"' at position " + std::to_string(pos));
35 : }
36 32 : ++pos;
37 :
38 32 : std::string result;
39 333 : while (pos < json.size() && json[pos] != '"') {
40 301 : if (json[pos] == '\\' && pos + 1 < json.size()) {
41 0 : ++pos;
42 0 : switch (json[pos]) {
43 0 : case '"': result += '"'; break;
44 0 : case '\\': result += '\\'; break;
45 0 : case 'n': result += '\n'; break;
46 0 : case 't': result += '\t'; break;
47 0 : default: result += json[pos]; break;
48 : }
49 : } else {
50 301 : result += json[pos];
51 : }
52 301 : ++pos;
53 : }
54 :
55 32 : if (pos >= json.size()) {
56 0 : throw std::runtime_error("Unterminated string");
57 : }
58 32 : ++pos; // skip closing quote
59 32 : return result;
60 0 : }
61 :
62 : /**
63 : * @brief 解析数字值
64 : */
65 12 : double parseNumber(const std::string& json, size_t& pos) {
66 12 : size_t start = pos;
67 12 : if (json[pos] == '-') ++pos;
68 60 : while (pos < json.size() && (std::isdigit(json[pos]) || json[pos] == '.')) {
69 48 : ++pos;
70 : }
71 12 : return std::stod(json.substr(start, pos - start));
72 : }
73 :
74 : /**
75 : * @brief 解析单个合约对象
76 : */
77 3 : Instrument parseInstrumentObject(const std::string& json, size_t& pos) {
78 3 : Instrument inst;
79 :
80 3 : skipWhitespace(json, pos);
81 3 : if (json[pos] != '{') {
82 0 : throw std::runtime_error("Expected '{' at position " + std::to_string(pos));
83 : }
84 3 : ++pos;
85 :
86 24 : while (pos < json.size()) {
87 24 : skipWhitespace(json, pos);
88 24 : if (json[pos] == '}') {
89 3 : ++pos;
90 3 : break;
91 : }
92 :
93 21 : if (json[pos] == ',') {
94 18 : ++pos;
95 18 : skipWhitespace(json, pos);
96 : }
97 :
98 : // 解析键
99 21 : std::string key = parseString(json, pos);
100 :
101 21 : skipWhitespace(json, pos);
102 21 : if (json[pos] != ':') {
103 0 : throw std::runtime_error("Expected ':' after key");
104 : }
105 21 : ++pos;
106 21 : skipWhitespace(json, pos);
107 :
108 : // 解析值
109 21 : if (key == "instrumentId") {
110 3 : inst.instrumentId = parseString(json, pos);
111 18 : } else if (key == "exchangeId") {
112 3 : inst.exchangeId = parseString(json, pos);
113 15 : } else if (key == "productId") {
114 3 : inst.productId = parseString(json, pos);
115 12 : } else if (key == "priceTick") {
116 3 : inst.priceTick = parseNumber(json, pos);
117 9 : } else if (key == "volumeMultiple") {
118 3 : inst.volumeMultiple = static_cast<int>(parseNumber(json, pos));
119 6 : } else if (key == "marginRate") {
120 3 : inst.marginRate = parseNumber(json, pos);
121 3 : } else if (key == "upperLimitPrice") {
122 1 : inst.upperLimitPrice = parseNumber(json, pos);
123 2 : } else if (key == "lowerLimitPrice") {
124 1 : inst.lowerLimitPrice = parseNumber(json, pos);
125 1 : } else if (key == "preSettlementPrice") {
126 1 : inst.preSettlementPrice = parseNumber(json, pos);
127 : } else {
128 : // 跳过未知字段
129 0 : if (json[pos] == '"') {
130 0 : parseString(json, pos);
131 0 : } else if (json[pos] == '-' || std::isdigit(json[pos])) {
132 0 : parseNumber(json, pos);
133 : }
134 : }
135 21 : }
136 :
137 3 : return inst;
138 0 : }
139 :
140 : /**
141 : * @brief 解析合约数组
142 : */
143 2 : std::vector<Instrument> parseInstrumentsArray(const std::string& json, size_t& pos) {
144 2 : std::vector<Instrument> instruments;
145 :
146 2 : skipWhitespace(json, pos);
147 2 : if (json[pos] != '[') {
148 0 : throw std::runtime_error("Expected '[' at position " + std::to_string(pos));
149 : }
150 2 : ++pos;
151 :
152 5 : while (pos < json.size()) {
153 5 : skipWhitespace(json, pos);
154 5 : if (json[pos] == ']') {
155 2 : ++pos;
156 2 : break;
157 : }
158 :
159 3 : if (json[pos] == ',') {
160 1 : ++pos;
161 1 : skipWhitespace(json, pos);
162 : }
163 :
164 3 : instruments.push_back(parseInstrumentObject(json, pos));
165 : }
166 :
167 2 : return instruments;
168 0 : }
169 :
170 : } // anonymous namespace
171 :
172 : // =============================================================================
173 : // InstrumentManager 实现
174 : // =============================================================================
175 :
176 3 : bool InstrumentManager::loadFromConfig(const std::string& configPath) {
177 : // 读取文件内容
178 3 : std::ifstream file(configPath);
179 3 : if (!file.is_open()) {
180 1 : return false;
181 : }
182 :
183 2 : std::stringstream buffer;
184 2 : buffer << file.rdbuf();
185 2 : std::string json = buffer.str();
186 :
187 : try {
188 2 : size_t pos = 0;
189 2 : skipWhitespace(json, pos);
190 :
191 2 : if (json[pos] != '{') {
192 0 : return false;
193 : }
194 2 : ++pos;
195 :
196 4 : while (pos < json.size()) {
197 4 : skipWhitespace(json, pos);
198 4 : if (json[pos] == '}') {
199 2 : break;
200 : }
201 :
202 2 : if (json[pos] == ',') {
203 0 : ++pos;
204 0 : skipWhitespace(json, pos);
205 : }
206 :
207 : // 解析键
208 2 : std::string key = parseString(json, pos);
209 :
210 2 : skipWhitespace(json, pos);
211 2 : if (json[pos] != ':') {
212 0 : return false;
213 : }
214 2 : ++pos;
215 2 : skipWhitespace(json, pos);
216 :
217 2 : if (key == "instruments") {
218 2 : auto instruments = parseInstrumentsArray(json, pos);
219 2 : std::lock_guard<std::mutex> lock(mutex_);
220 5 : for (const auto& inst : instruments) {
221 3 : instruments_[inst.instrumentId] = inst;
222 : }
223 2 : } else {
224 : // 跳过其他字段 - 简单处理
225 0 : if (json[pos] == '"') {
226 0 : parseString(json, pos);
227 0 : } else if (json[pos] == '[') {
228 0 : int depth = 1;
229 0 : ++pos;
230 0 : while (pos < json.size() && depth > 0) {
231 0 : if (json[pos] == '[') ++depth;
232 0 : else if (json[pos] == ']') --depth;
233 0 : ++pos;
234 : }
235 0 : } else if (json[pos] == '{') {
236 0 : int depth = 1;
237 0 : ++pos;
238 0 : while (pos < json.size() && depth > 0) {
239 0 : if (json[pos] == '{') ++depth;
240 0 : else if (json[pos] == '}') --depth;
241 0 : ++pos;
242 : }
243 : }
244 : }
245 2 : }
246 :
247 2 : return true;
248 0 : } catch (const std::exception&) {
249 0 : return false;
250 0 : }
251 3 : }
252 :
253 24 : void InstrumentManager::addInstrument(const Instrument& instrument) {
254 24 : std::lock_guard<std::mutex> lock(mutex_);
255 24 : instruments_[instrument.instrumentId] = instrument;
256 24 : }
257 :
258 1 : void InstrumentManager::addInstruments(const std::vector<Instrument>& instruments) {
259 1 : std::lock_guard<std::mutex> lock(mutex_);
260 4 : for (const auto& inst : instruments) {
261 3 : instruments_[inst.instrumentId] = inst;
262 : }
263 1 : }
264 :
265 17 : const Instrument* InstrumentManager::getInstrument(const std::string& instrumentId) const {
266 17 : std::lock_guard<std::mutex> lock(mutex_);
267 17 : auto it = instruments_.find(instrumentId);
268 17 : if (it != instruments_.end()) {
269 14 : return &it->second;
270 : }
271 3 : return nullptr;
272 17 : }
273 :
274 2 : std::optional<Instrument> InstrumentManager::getInstrumentCopy(const std::string& instrumentId) const {
275 2 : std::lock_guard<std::mutex> lock(mutex_);
276 2 : auto it = instruments_.find(instrumentId);
277 2 : if (it != instruments_.end()) {
278 1 : return it->second;
279 : }
280 1 : return std::nullopt;
281 2 : }
282 :
283 8 : bool InstrumentManager::hasInstrument(const std::string& instrumentId) const {
284 8 : std::lock_guard<std::mutex> lock(mutex_);
285 16 : return instruments_.find(instrumentId) != instruments_.end();
286 8 : }
287 :
288 2 : std::vector<std::string> InstrumentManager::getAllInstrumentIds() const {
289 2 : std::lock_guard<std::mutex> lock(mutex_);
290 2 : std::vector<std::string> ids;
291 2 : ids.reserve(instruments_.size());
292 4 : for (const auto& pair : instruments_) {
293 2 : ids.push_back(pair.first);
294 : }
295 4 : return ids;
296 2 : }
297 :
298 7 : size_t InstrumentManager::size() const {
299 7 : std::lock_guard<std::mutex> lock(mutex_);
300 14 : return instruments_.size();
301 7 : }
302 :
303 4 : bool InstrumentManager::updateLimitPrices(const std::string& instrumentId,
304 : double upperLimit, double lowerLimit) {
305 4 : std::lock_guard<std::mutex> lock(mutex_);
306 4 : auto it = instruments_.find(instrumentId);
307 4 : if (it == instruments_.end()) {
308 1 : return false;
309 : }
310 3 : it->second.updateLimitPrices(upperLimit, lowerLimit);
311 3 : return true;
312 4 : }
313 :
314 2 : bool InstrumentManager::updatePreSettlementPrice(const std::string& instrumentId,
315 : double preSettlementPrice) {
316 2 : std::lock_guard<std::mutex> lock(mutex_);
317 2 : auto it = instruments_.find(instrumentId);
318 2 : if (it == instruments_.end()) {
319 1 : return false;
320 : }
321 1 : it->second.preSettlementPrice = preSettlementPrice;
322 1 : return true;
323 2 : }
324 :
325 1 : void InstrumentManager::clear() {
326 1 : std::lock_guard<std::mutex> lock(mutex_);
327 1 : instruments_.clear();
328 1 : }
329 :
330 0 : std::vector<std::string> InstrumentManager::searchByPrefix(const std::string& prefix, size_t limit) const {
331 0 : std::vector<std::string> results;
332 :
333 0 : if (prefix.empty()) {
334 0 : return results;
335 : }
336 :
337 0 : std::lock_guard<std::mutex> lock(mutex_);
338 :
339 : // 收集所有匹配的合约
340 0 : for (const auto& [id, inst] : instruments_) {
341 0 : if (id.size() >= prefix.size() &&
342 0 : id.compare(0, prefix.size(), prefix) == 0) {
343 0 : results.push_back(id);
344 : }
345 : }
346 :
347 : // 按字母排序
348 0 : std::sort(results.begin(), results.end());
349 :
350 : // 限制返回数量
351 0 : if (results.size() > limit) {
352 0 : results.resize(limit);
353 : }
354 :
355 0 : return results;
356 0 : }
357 :
358 0 : std::vector<std::string> InstrumentManager::getInstrumentsByProduct(const std::string& productId) const {
359 0 : std::vector<std::string> results;
360 :
361 0 : std::lock_guard<std::mutex> lock(mutex_);
362 :
363 0 : for (const auto& [id, inst] : instruments_) {
364 0 : if (inst.productId == productId) {
365 0 : results.push_back(id);
366 : }
367 : }
368 :
369 0 : std::sort(results.begin(), results.end());
370 0 : return results;
371 0 : }
372 :
373 0 : std::vector<std::string> InstrumentManager::getInstrumentsByExchange(const std::string& exchangeId) const {
374 0 : std::vector<std::string> results;
375 :
376 0 : std::lock_guard<std::mutex> lock(mutex_);
377 :
378 0 : for (const auto& [id, inst] : instruments_) {
379 0 : if (inst.exchangeId == exchangeId) {
380 0 : results.push_back(id);
381 : }
382 : }
383 :
384 0 : std::sort(results.begin(), results.end());
385 0 : return results;
386 0 : }
387 :
388 : } // namespace fix40
|