LCOV - code coverage report
Current view: top level - src/app/manager - instrument_manager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 68.8 % 237 163
Test Date: 2025-12-19 03:13:09 Functions: 84.2 % 19 16

            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
        

Generated by: LCOV version 2.0-1