LCOV - code coverage report
Current view: top level - src/app/manager - position_manager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.9 % 142 139
Test Date: 2025-12-19 03:13:09 Functions: 100.0 % 15 15

            Line data    Source code
       1              : /**
       2              :  * @file position_manager.cpp
       3              :  * @brief 持仓管理模块实现
       4              :  */
       5              : 
       6              : #include "app/manager/position_manager.hpp"
       7              : #include "storage/store.hpp"
       8              : #include <chrono>
       9              : 
      10              : namespace fix40 {
      11              : 
      12              : // =============================================================================
      13              : // 构造函数
      14              : // =============================================================================
      15              : 
      16          546 : PositionManager::PositionManager()
      17          546 :     : store_(nullptr)
      18          546 : {}
      19              : 
      20            8 : PositionManager::PositionManager(IStore* store)
      21            8 :     : store_(store)
      22              : {
      23            8 :     if (store_) {
      24              :         // 启动时从存储恢复持仓状态(用于服务端重启后持仓连续性)。
      25            8 :         auto positions = store_->loadAllPositions();
      26            8 :         std::lock_guard<std::mutex> lock(mutex_);
      27            8 :         positions_.clear();
      28           10 :         for (const auto& position : positions) {
      29            2 :             if (!position.accountId.empty() && !position.instrumentId.empty()) {
      30            2 :                 positions_[makeKey(position.accountId, position.instrumentId)] = position;
      31              :             }
      32              :         }
      33            8 :     }
      34            8 : }
      35              : 
      36              : // =============================================================================
      37              : // 查询方法
      38              : // =============================================================================
      39              : 
      40          244 : std::optional<Position> PositionManager::getPosition(const std::string& accountId,
      41              :                                                       const std::string& instrumentId) const {
      42          244 :     std::lock_guard<std::mutex> lock(mutex_);
      43              :     
      44          244 :     auto it = positions_.find(makeKey(accountId, instrumentId));
      45          244 :     if (it != positions_.end()) {
      46          238 :         return it->second;
      47              :     }
      48            6 :     return std::nullopt;
      49          244 : }
      50              : 
      51            1 : std::vector<Position> PositionManager::getPositionsByAccount(const std::string& accountId) const {
      52            1 :     std::lock_guard<std::mutex> lock(mutex_);
      53              :     
      54            1 :     std::vector<Position> result;
      55            4 :     for (const auto& pair : positions_) {
      56            3 :         if (pair.second.accountId == accountId) {
      57            2 :             result.push_back(pair.second);
      58              :         }
      59              :     }
      60            2 :     return result;
      61            1 : }
      62              : 
      63            3 : std::vector<Position> PositionManager::getAllPositions() const {
      64            3 :     std::lock_guard<std::mutex> lock(mutex_);
      65              :     
      66            3 :     std::vector<Position> result;
      67            3 :     result.reserve(positions_.size());
      68            3 :     for (const auto& pair : positions_) {
      69            0 :         result.push_back(pair.second);
      70              :     }
      71            6 :     return result;
      72            3 : }
      73              : 
      74            3 : bool PositionManager::hasPosition(const std::string& accountId,
      75              :                                    const std::string& instrumentId) const {
      76            3 :     std::lock_guard<std::mutex> lock(mutex_);
      77              :     
      78            3 :     auto it = positions_.find(makeKey(accountId, instrumentId));
      79            3 :     if (it == positions_.end()) {
      80            2 :         return false;
      81              :     }
      82            1 :     return it->second.hasPosition();
      83            3 : }
      84              : 
      85            3 : size_t PositionManager::size() const {
      86            3 :     std::lock_guard<std::mutex> lock(mutex_);
      87            6 :     return positions_.size();
      88            3 : }
      89              : 
      90              : // =============================================================================
      91              : // 开仓操作
      92              : // =============================================================================
      93              : 
      94          804 : void PositionManager::openPosition(const std::string& accountId,
      95              :                                     const std::string& instrumentId,
      96              :                                     OrderSide side,
      97              :                                     int64_t volume,
      98              :                                     double price,
      99              :                                     double margin) {
     100          804 :     std::lock_guard<std::mutex> lock(mutex_);
     101              :     
     102          804 :     std::string key = makeKey(accountId, instrumentId);
     103              :     
     104              :     // 获取或创建持仓
     105          804 :     auto it = positions_.find(key);
     106          804 :     if (it == positions_.end()) {
     107          537 :         Position pos(accountId, instrumentId);
     108          537 :         positions_[key] = pos;
     109          537 :         it = positions_.find(key);
     110          537 :     }
     111              :     
     112          804 :     Position& pos = it->second;
     113              :     
     114          804 :     if (side == OrderSide::BUY) {
     115              :         // 多头开仓
     116              :         // 新均价 = (原均价 × 原持仓 + 开仓价 × 开仓量) / (原持仓 + 开仓量)
     117          687 :         double totalCost = pos.longAvgPrice * pos.longPosition + price * volume;
     118          687 :         int64_t totalVolume = pos.longPosition + volume;
     119              :         
     120          687 :         pos.longPosition = totalVolume;
     121          687 :         pos.longAvgPrice = totalVolume > 0 ? totalCost / totalVolume : 0.0;
     122          687 :         pos.longMargin += margin;
     123              :     } else {
     124              :         // 空头开仓
     125          117 :         double totalCost = pos.shortAvgPrice * pos.shortPosition + price * volume;
     126          117 :         int64_t totalVolume = pos.shortPosition + volume;
     127              :         
     128          117 :         pos.shortPosition = totalVolume;
     129          117 :         pos.shortAvgPrice = totalVolume > 0 ? totalCost / totalVolume : 0.0;
     130          117 :         pos.shortMargin += margin;
     131              :     }
     132              :     
     133          804 :     pos.updateTime = std::chrono::system_clock::now();
     134              :     
     135              :     // 持久化
     136          804 :     persistPosition(pos);
     137          804 : }
     138              : 
     139              : // =============================================================================
     140              : // 平仓操作
     141              : // =============================================================================
     142              : 
     143          217 : double PositionManager::closePosition(const std::string& accountId,
     144              :                                        const std::string& instrumentId,
     145              :                                        OrderSide side,
     146              :                                        int64_t volume,
     147              :                                        double price,
     148              :                                        int volumeMultiple) {
     149          217 :     std::lock_guard<std::mutex> lock(mutex_);
     150              :     
     151          217 :     std::string key = makeKey(accountId, instrumentId);
     152              :     
     153          217 :     auto it = positions_.find(key);
     154          217 :     if (it == positions_.end()) {
     155            0 :         return 0.0;
     156              :     }
     157              :     
     158          217 :     Position& pos = it->second;
     159          217 :     double profit = 0.0;
     160              :     
     161          217 :     if (side == OrderSide::SELL) {
     162              :         // 平多头(卖出平仓)
     163              :         // 盈亏 = (平仓价 - 持仓均价) × 平仓量 × 合约乘数
     164          110 :         profit = (price - pos.longAvgPrice) * volume * volumeMultiple;
     165              :         
     166              :         // 计算平仓前的持仓量,用于按比例计算保证金释放
     167          110 :         int64_t originalPosition = pos.longPosition;
     168              :         
     169              :         // 减少持仓
     170          110 :         pos.longPosition -= volume;
     171          110 :         if (pos.longPosition <= 0) {
     172          105 :             pos.longPosition = 0;
     173          105 :             pos.longAvgPrice = 0.0;
     174          105 :             pos.longProfit = 0.0;
     175          105 :             pos.longMargin = 0.0;
     176              :         } else {
     177              :             // 按比例减少保证金:释放的保证金 = 原保证金 × (平仓量 / 原持仓量)
     178            5 :             double marginToRelease = pos.longMargin * (static_cast<double>(volume) / originalPosition);
     179            5 :             pos.longMargin -= marginToRelease;
     180              :             // 浮动盈亏与持仓量成比例:若当前 longProfit 基于某个最新价计算过,平仓后按剩余仓位缩放,
     181              :             // 避免出现“持仓量减少但浮动盈亏仍保持旧值”的情况。
     182            5 :             pos.longProfit *= (static_cast<double>(pos.longPosition) / originalPosition);
     183              :         }
     184              :     } else {
     185              :         // 平空头(买入平仓)
     186              :         // 盈亏 = (持仓均价 - 平仓价) × 平仓量 × 合约乘数
     187          107 :         profit = (pos.shortAvgPrice - price) * volume * volumeMultiple;
     188              :         
     189              :         // 计算平仓前的持仓量,用于按比例计算保证金释放
     190          107 :         int64_t originalPosition = pos.shortPosition;
     191              :         
     192              :         // 减少持仓
     193          107 :         pos.shortPosition -= volume;
     194          107 :         if (pos.shortPosition <= 0) {
     195          104 :             pos.shortPosition = 0;
     196          104 :             pos.shortAvgPrice = 0.0;
     197          104 :             pos.shortProfit = 0.0;
     198          104 :             pos.shortMargin = 0.0;
     199              :         } else {
     200              :             // 按比例减少保证金:释放的保证金 = 原保证金 × (平仓量 / 原持仓量)
     201            3 :             double marginToRelease = pos.shortMargin * (static_cast<double>(volume) / originalPosition);
     202            3 :             pos.shortMargin -= marginToRelease;
     203            3 :             pos.shortProfit *= (static_cast<double>(pos.shortPosition) / originalPosition);
     204              :         }
     205              :     }
     206              :     
     207          217 :     pos.updateTime = std::chrono::system_clock::now();
     208              :     
     209              :     // 持久化
     210          217 :     persistPosition(pos);
     211              :     
     212          217 :     return profit;
     213          217 : }
     214              : 
     215              : // =============================================================================
     216              : // 盈亏更新
     217              : // =============================================================================
     218              : 
     219            1 : void PositionManager::updateAllProfits(const MarketDataSnapshot& snapshot, int volumeMultiple) {
     220            1 :     std::lock_guard<std::mutex> lock(mutex_);
     221              :     
     222            3 :     for (auto& pair : positions_) {
     223            2 :         if (pair.second.instrumentId == snapshot.instrumentId) {
     224            2 :             pair.second.updateProfit(snapshot.lastPrice, volumeMultiple);
     225            2 :             pair.second.updateTime = std::chrono::system_clock::now();
     226              :         }
     227              :     }
     228            1 : }
     229              : 
     230          105 : double PositionManager::updateProfit(const std::string& accountId,
     231              :                                       const std::string& instrumentId,
     232              :                                       double lastPrice,
     233              :                                       int volumeMultiple) {
     234          105 :     std::lock_guard<std::mutex> lock(mutex_);
     235              :     
     236          105 :     std::string key = makeKey(accountId, instrumentId);
     237              :     
     238          105 :     auto it = positions_.find(key);
     239          105 :     if (it == positions_.end()) {
     240            0 :         return 0.0;
     241              :     }
     242              :     
     243          105 :     Position& pos = it->second;
     244          105 :     pos.updateProfit(lastPrice, volumeMultiple);
     245          105 :     pos.updateTime = std::chrono::system_clock::now();
     246              :     
     247          105 :     return pos.getTotalProfit();
     248          105 : }
     249              : 
     250            2 : double PositionManager::getTotalProfit(const std::string& accountId) const {
     251            2 :     std::lock_guard<std::mutex> lock(mutex_);
     252              :     
     253            2 :     double total = 0.0;
     254            5 :     for (const auto& pair : positions_) {
     255            3 :         if (pair.second.accountId == accountId) {
     256            3 :             total += pair.second.getTotalProfit();
     257              :         }
     258              :     }
     259            2 :     return total;
     260            2 : }
     261              : 
     262              : // =============================================================================
     263              : // 清理方法
     264              : // =============================================================================
     265              : 
     266            1 : void PositionManager::clear() {
     267            1 :     std::lock_guard<std::mutex> lock(mutex_);
     268            1 :     positions_.clear();
     269            1 : }
     270              : 
     271              : // =============================================================================
     272              : // 私有方法
     273              : // =============================================================================
     274              : 
     275         1375 : std::string PositionManager::makeKey(const std::string& accountId,
     276              :                                       const std::string& instrumentId) {
     277         1375 :     return accountId + "_" + instrumentId;
     278              : }
     279              : 
     280         1021 : void PositionManager::persistPosition(const Position& position) {
     281         1021 :     if (!store_) return;
     282              :     // 注意:此处为 best-effort 持久化。存储失败时不抛异常,以免影响撮合主流程。
     283            3 :     store_->savePosition(position);
     284              : }
     285              : 
     286              : } // namespace fix40
        

Generated by: LCOV version 2.0-1