LCOV - code coverage report
Current view: top level - src/app/manager - risk_manager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.5 % 81 79
Test Date: 2025-12-19 03:13:09 Functions: 100.0 % 6 6

            Line data    Source code
       1              : /**
       2              :  * @file risk_manager.cpp
       3              :  * @brief 风险控制模块实现
       4              :  *
       5              :  * 实现订单风控检查功能。
       6              :  */
       7              : 
       8              : #include "app/manager/risk_manager.hpp"
       9              : #include <sstream>
      10              : 
      11              : namespace fix40 {
      12              : 
      13              : // =============================================================================
      14              : // 主检查方法
      15              : // =============================================================================
      16              : 
      17           10 : CheckResult RiskManager::checkOrder(
      18              :     const Order& order,
      19              :     const Account& account,
      20              :     const Position& position,
      21              :     const Instrument& instrument,
      22              :     const MarketDataSnapshot& snapshot,
      23              :     OffsetFlag offsetFlag
      24              : ) const {
      25              :     // 1. 价格检查(限价单)
      26           10 :     if (order.ordType == OrderType::LIMIT) {
      27            8 :         CheckResult priceResult = checkPrice(order, instrument);
      28            8 :         if (!priceResult.passed) {
      29            2 :             return priceResult;
      30              :         }
      31            8 :     }
      32              : 
      33              :     // 2. 资金检查(开仓)
      34            8 :     if (offsetFlag == OffsetFlag::OPEN) {
      35            6 :         CheckResult marginResult = checkMargin(order, account, instrument);
      36            6 :         if (!marginResult.passed) {
      37            1 :             return marginResult;
      38              :         }
      39            6 :     }
      40              : 
      41              :     // 3. 持仓检查(平仓)
      42            7 :     if (offsetFlag == OffsetFlag::CLOSE) {
      43            2 :         CheckResult positionResult = checkPosition(order, position);
      44            2 :         if (!positionResult.passed) {
      45            1 :             return positionResult;
      46              :         }
      47            2 :     }
      48              : 
      49              :     // 4. 对手盘检查(市价单)
      50            6 :     if (order.ordType == OrderType::MARKET) {
      51            2 :         CheckResult counterPartyResult = checkCounterParty(order, snapshot);
      52            2 :         if (!counterPartyResult.passed) {
      53            1 :             return counterPartyResult;
      54              :         }
      55            2 :     }
      56              : 
      57            5 :     return CheckResult::success();
      58              : }
      59              : 
      60              : // =============================================================================
      61              : // 子检查方法
      62              : // =============================================================================
      63              : 
      64          211 : CheckResult RiskManager::checkMargin(
      65              :     const Order& order,
      66              :     const Account& account,
      67              :     const Instrument& instrument
      68              : ) const {
      69          211 :     double requiredMargin = calculateRequiredMargin(order, instrument);
      70              :     
      71          211 :     if (account.available < requiredMargin) {
      72          103 :         std::ostringstream oss;
      73          103 :         oss << "Insufficient funds: required=" << requiredMargin
      74          103 :             << ", available=" << account.available;
      75          103 :         return CheckResult::failure(RejectReason::INSUFFICIENT_FUNDS, oss.str());
      76          103 :     }
      77              :     
      78          108 :     return CheckResult::success();
      79              : }
      80              : 
      81          415 : CheckResult RiskManager::checkPrice(
      82              :     const Order& order,
      83              :     const Instrument& instrument
      84              : ) const {
      85              :     // 市价单不检查价格
      86          415 :     if (order.ordType == OrderType::MARKET) {
      87          101 :         return CheckResult::success();
      88              :     }
      89              :     
      90              :     // 如果涨跌停价格未设置,跳过检查
      91          314 :     if (instrument.lowerLimitPrice <= 0 && instrument.upperLimitPrice <= 0) {
      92            1 :         return CheckResult::success();
      93              :     }
      94              :     
      95              :     // 检查价格是否在涨跌停范围内
      96          313 :     if (!instrument.isPriceValid(order.price)) {
      97          204 :         std::ostringstream oss;
      98          204 :         oss << "Price out of limit: price=" << order.price
      99          204 :             << ", lower=" << instrument.lowerLimitPrice
     100          204 :             << ", upper=" << instrument.upperLimitPrice;
     101          204 :         return CheckResult::failure(RejectReason::PRICE_OUT_OF_LIMIT, oss.str());
     102          204 :     }
     103              :     
     104          109 :     return CheckResult::success();
     105              : }
     106              : 
     107          508 : CheckResult RiskManager::checkPosition(
     108              :     const Order& order,
     109              :     const Position& position
     110              : ) const {
     111              :     // 买单平空头,卖单平多头
     112          508 :     int64_t availablePosition = 0;
     113              :     
     114          508 :     if (order.side == OrderSide::BUY) {
     115              :         // 买入平仓 = 平空头
     116          202 :         availablePosition = position.shortPosition;
     117              :     } else {
     118              :         // 卖出平仓 = 平多头
     119          306 :         availablePosition = position.longPosition;
     120              :     }
     121              :     
     122          508 :     if (order.orderQty > availablePosition) {
     123          204 :         std::ostringstream oss;
     124          204 :         oss << "Insufficient position: required=" << order.orderQty
     125          204 :             << ", available=" << availablePosition;
     126          204 :         return CheckResult::failure(RejectReason::INSUFFICIENT_POSITION, oss.str());
     127          204 :     }
     128              :     
     129          304 :     return CheckResult::success();
     130              : }
     131              : 
     132            7 : CheckResult RiskManager::checkCounterParty(
     133              :     const Order& order,
     134              :     const MarketDataSnapshot& snapshot
     135              : ) const {
     136              :     // 限价单不检查对手盘
     137            7 :     if (order.ordType == OrderType::LIMIT) {
     138            1 :         return CheckResult::success();
     139              :     }
     140              :     
     141            6 :     bool hasCounterParty = false;
     142              :     
     143            6 :     if (order.side == OrderSide::BUY) {
     144              :         // 买单需要有卖盘
     145            4 :         hasCounterParty = snapshot.hasAsk();
     146              :     } else {
     147              :         // 卖单需要有买盘
     148            2 :         hasCounterParty = snapshot.hasBid();
     149              :     }
     150              :     
     151            6 :     if (!hasCounterParty) {
     152            3 :         std::string sideStr = (order.side == OrderSide::BUY) ? "ask" : "bid";
     153            3 :         std::ostringstream oss;
     154            3 :         oss << "No counter party: no " << sideStr << " available";
     155            3 :         return CheckResult::failure(RejectReason::NO_COUNTER_PARTY, oss.str());
     156            3 :     }
     157              :     
     158            3 :     return CheckResult::success();
     159              : }
     160              : 
     161              : // =============================================================================
     162              : // 辅助方法
     163              : // =============================================================================
     164              : 
     165          316 : double RiskManager::calculateRequiredMargin(
     166              :     const Order& order,
     167              :     const Instrument& instrument
     168              : ) const {
     169          316 :     double price = order.price;
     170              :     
     171              :     // 市价单使用涨停价(买单)或跌停价(卖单)计算保证金
     172          316 :     if (order.ordType == OrderType::MARKET) {
     173            6 :         if (order.side == OrderSide::BUY) {
     174              :             // 买单使用涨停价
     175            4 :             price = instrument.upperLimitPrice;
     176              :             // 如果涨停价未设置,使用昨结算价
     177            4 :             if (price <= 0) {
     178            0 :                 price = instrument.preSettlementPrice;
     179              :             }
     180              :         } else {
     181              :             // 卖单使用跌停价
     182            2 :             price = instrument.lowerLimitPrice;
     183              :             // 如果跌停价未设置,使用昨结算价
     184            2 :             if (price <= 0) {
     185            0 :                 price = instrument.preSettlementPrice;
     186              :             }
     187              :         }
     188              :     }
     189              :     
     190          316 :     return instrument.calculateMargin(price, order.orderQty);
     191              : }
     192              : 
     193              : } // namespace fix40
        

Generated by: LCOV version 2.0-1