LCOV - code coverage report
Current view: top level - include/app - simulation_app.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 95.0 % 20 19
Test Date: 2025-12-19 03:13:09 Functions: 88.9 % 9 8

            Line data    Source code
       1              : /**
       2              :  * @file simulation_app.hpp
       3              :  * @brief 模拟交易网关 (Trade Gateway)
       4              :  *
       5              :  * 提供一个线程安全的 Application 实现,作为交易网关:
       6              :  * - 身份绑定:利用 FIX Logon 消息中的 SenderCompID 作为用户标识
       7              :  * - 安全路由:强制使用 Session 绑定的 UserID 进行验资和下单
       8              :  * - 协议扩展:支持 FIX User Defined Message (U系列) 实现自定义查询
       9              :  * 
      10              :  * 集成以下模块:
      11              :  * - AccountManager: 账户管理
      12              :  * - PositionManager: 持仓管理
      13              :  * - InstrumentManager: 合约信息管理
      14              :  * - RiskManager: 风险控制
      15              :  * 
      16              :  * @par 支持的消息类型
      17              :  * - D:  NewOrderSingle (新订单)
      18              :  * - F:  OrderCancelRequest (撤单请求)
      19              :  * - U1: BalanceQueryRequest (资金查询请求) - 自定义
      20              :  * - U3: PositionQueryRequest (持仓查询请求) - 自定义
      21              :  * 
      22              :  * @par 发送的消息类型
      23              :  * - 8:  ExecutionReport (执行报告)
      24              :  * - U2: BalanceQueryResponse (资金查询响应) - 自定义
      25              :  * - U4: PositionQueryResponse (持仓查询响应) - 自定义
      26              :  */
      27              : 
      28              : #pragma once
      29              : 
      30              : #include "fix/application.hpp"
      31              : #include "fix/session_manager.hpp"
      32              : #include "app/engine/matching_engine.hpp"
      33              : #include "app/manager/account_manager.hpp"
      34              : #include "app/manager/position_manager.hpp"
      35              : #include "app/manager/instrument_manager.hpp"
      36              : #include "app/manager/risk_manager.hpp"
      37              : #include <memory>
      38              : #include <unordered_map>
      39              : #include <mutex>
      40              : 
      41              : namespace fix40 {
      42              : 
      43              : // 前向声明
      44              : class IStore;
      45              : struct SimulationAppTestAccess;
      46              : 
      47              : /**
      48              :  * @class SimulationApp
      49              :  * @brief 模拟交易应用层
      50              :  *
      51              :  * 实现 Application 接口,采用生产者-消费者模式处理业务消息:
      52              :  * - fromApp() 将消息封装为事件,push 到无锁队列(生产者)
      53              :  * - MatchingEngine 在独立线程中消费并处理事件(消费者)
      54              :  *
      55              :  * 这种设计确保:
      56              :  * - Application 回调快速返回,不阻塞工作线程
      57              :  * - 所有订单处理在单线程中串行执行,无需加锁
      58              :  * - 异常隔离:撮合引擎的异常不会影响网络层
      59              :  *
      60              :  * @par 集成模块
      61              :  * - AccountManager: 账户管理(资金冻结/释放)
      62              :  * - PositionManager: 持仓管理(开仓/平仓)
      63              :  * - InstrumentManager: 合约信息管理
      64              :  * - RiskManager: 风险控制(资金/价格/持仓检查)
      65              :  *
      66              :  * @par 支持的消息类型
      67              :  * - D: NewOrderSingle (新订单)
      68              :  * - F: OrderCancelRequest (撤单请求)
      69              :  * - G: OrderCancelReplaceRequest (改单请求)
      70              :  *
      71              :  * @par 使用示例
      72              :  * @code
      73              :  * IStore* store = ...;  // 存储接口
      74              :  * SimulationApp app(store);
      75              :  * 
      76              :  * // 加载合约配置
      77              :  * app.getInstrumentManager().loadFromConfig("config/instruments.json");
      78              :  * 
      79              :  * app.start();  // 启动撮合引擎
      80              :  * 
      81              :  * session->set_application(&app);
      82              :  * 
      83              :  * // 关闭时
      84              :  * app.stop();
      85              :  * @endcode
      86              :  */
      87              : class SimulationApp : public Application {
      88              : public:
      89              :     /**
      90              :      * @struct OrderMarginInfo
      91              :      * @brief 订单保证金信息
      92              :      * 
      93              :      * 用于正确处理部分成交时的保证金计算。
      94              :      * 存储原始总冻结保证金和订单总数量,避免累计误差。
      95              :      */
      96              :     struct OrderMarginInfo {
      97              :         double originalFrozenMargin;  ///< 原始总冻结保证金
      98              :         int64_t originalOrderQty;     ///< 原始订单总数量
      99              :         double releasedMargin;        ///< 已释放的保证金(累计)
     100              :         
     101            3 :         OrderMarginInfo() 
     102            3 :             : originalFrozenMargin(0.0)
     103            3 :             , originalOrderQty(0)
     104            3 :             , releasedMargin(0.0) {}
     105              :         
     106            8 :         OrderMarginInfo(double frozen, int64_t qty)
     107            8 :             : originalFrozenMargin(frozen)
     108            8 :             , originalOrderQty(qty)
     109            8 :             , releasedMargin(0.0) {}
     110              :         
     111              :         /// 计算本次成交应释放的冻结保证金
     112           12 :         double calculateReleaseAmount(int64_t fillQty) {
     113           12 :             if (originalOrderQty <= 0) return 0.0;
     114           11 :             double amount = originalFrozenMargin * fillQty / originalOrderQty;
     115           11 :             releasedMargin += amount;
     116           11 :             return amount;
     117              :         }
     118              :         
     119              :         /// 获取剩余未释放的冻结保证金
     120            6 :         double getRemainingFrozen() const {
     121            6 :             return originalFrozenMargin - releasedMargin;
     122              :         }
     123              :     };
     124              : 
     125              :     /**
     126              :      * @brief 默认构造函数(不带持久化)
     127              :      */
     128              :     SimulationApp();
     129              : 
     130              :     /**
     131              :      * @brief 带存储接口的构造函数
     132              :      * 
     133              :      * @param store 存储接口指针,用于账户和持仓的持久化
     134              :      */
     135              :     explicit SimulationApp(IStore* store);
     136              : 
     137              :     /**
     138              :      * @brief 析构函数
     139              :      *
     140              :      * 自动停止撮合引擎。
     141              :      */
     142              :     ~SimulationApp() override;
     143              : 
     144              :     /**
     145              :      * @brief 启动撮合引擎
     146              :      *
     147              :      * 必须在处理消息前调用。
     148              :      */
     149              :     void start();
     150              : 
     151              :     /**
     152              :      * @brief 停止撮合引擎
     153              :      *
     154              :      * 等待当前处理完成后退出。
     155              :      */
     156              :     void stop();
     157              : 
     158              :     // =========================================================================
     159              :     // Application 接口实现
     160              :     // =========================================================================
     161              : 
     162              :     /**
     163              :      * @brief 会话登录成功回调
     164              :      * @param sessionID 已建立的会话标识符
     165              :      *
     166              :      * 将登录事件提交到撮合引擎队列。
     167              :      */
     168              :     void onLogon(const SessionID& sessionID) override;
     169              : 
     170              :     /**
     171              :      * @brief 会话登出回调
     172              :      * @param sessionID 即将断开的会话标识符
     173              :      *
     174              :      * 将登出事件提交到撮合引擎队列。
     175              :      */
     176              :     void onLogout(const SessionID& sessionID) override;
     177              : 
     178              :     /**
     179              :      * @brief 收到业务消息回调
     180              :      * @param msg 收到的 FIX 业务消息
     181              :      * @param sessionID 消息来源的会话标识符
     182              :      *
     183              :      * 将消息封装为事件,提交到撮合引擎队列。
     184              :      * 此方法只做轻量的入队操作,快速返回。
     185              :      */
     186              :     void fromApp(const FixMessage& msg, const SessionID& sessionID) override;
     187              : 
     188              :     /**
     189              :      * @brief 发送业务消息前回调
     190              :      * @param msg 即将发送的 FIX 业务消息
     191              :      * @param sessionID 发送消息的会话标识符
     192              :      *
     193              :      * 用于记录审计日志。
     194              :      */
     195              :     void toApp(FixMessage& msg, const SessionID& sessionID) override;
     196              : 
     197              :     /**
     198              :      * @brief 获取会话管理器
     199              :      * @return SessionManager& 会话管理器引用
     200              :      *
     201              :      * 返回内部会话管理器的引用,调用者可通过该引用调用
     202              :      * registerSession()/unregisterSession() 等方法管理会话。
     203              :      */
     204            4 :     SessionManager& getSessionManager() { return sessionManager_; }
     205              : 
     206              :     /**
     207              :      * @brief 获取存储接口
     208              :      * @return IStore* 存储接口指针,可能为 nullptr
     209              :      *
     210              :      * 该指针用于账户/持仓等数据的持久化与重启恢复。
     211              :      */
     212            0 :     IStore* getStore() const override { return store_; }
     213              : 
     214              :     // =========================================================================
     215              :     // 管理器访问接口
     216              :     // =========================================================================
     217              : 
     218              :     /**
     219              :      * @brief 获取账户管理器
     220              :      * @return AccountManager& 账户管理器引用
     221              :      */
     222           12 :     AccountManager& getAccountManager() { return accountManager_; }
     223              : 
     224              :     /**
     225              :      * @brief 获取持仓管理器
     226              :      * @return PositionManager& 持仓管理器引用
     227              :      */
     228              :     PositionManager& getPositionManager() { return positionManager_; }
     229              : 
     230              :     /**
     231              :      * @brief 获取合约管理器
     232              :      * @return InstrumentManager& 合约管理器引用
     233              :      */
     234            8 :     InstrumentManager& getInstrumentManager() { return instrumentManager_; }
     235              : 
     236              :     /**
     237              :      * @brief 获取风控管理器
     238              :      * @return RiskManager& 风控管理器引用
     239              :      */
     240              :     RiskManager& getRiskManager() { return riskManager_; }
     241              : 
     242              :     /**
     243              :      * @brief 获取撮合引擎
     244              :      * @return MatchingEngine& 撮合引擎引用
     245              :      */
     246            7 :     MatchingEngine& getMatchingEngine() { return engine_; }
     247              : 
     248              :     // =========================================================================
     249              :     // 账户操作接口
     250              :     // =========================================================================
     251              : 
     252              :     /**
     253              :      * @brief 创建或获取账户
     254              :      * 
     255              :      * 如果账户不存在,创建一个新账户;否则返回现有账户。
     256              :      * 
     257              :      * @param accountId 账户ID
     258              :      * @param initialBalance 初始余额(仅在创建时使用)
     259              :      * @return Account 账户信息
     260              :      */
     261              :     Account getOrCreateAccount(const std::string& accountId, double initialBalance = 1000000.0);
     262              : 
     263              : private:
     264              :     /**
     265              :      * @brief 单元测试访问器
     266              :      *
     267              :      * 仅用于单元测试访问内部实现细节(例如 pushAccountUpdate),避免在测试中使用
     268              :      * `#define private public` 破坏标准库头文件的可见性/封装并导致编译失败。
     269              :      */
     270              :     friend struct SimulationAppTestAccess;
     271              : 
     272              :     /**
     273              :      * @brief 初始化各管理器
     274              :      * 
     275              :      * 设置撮合引擎与各管理器的关联。
     276              :      */
     277              :     void initializeManagers();
     278              : 
     279              :     /**
     280              :      * @brief ExecutionReport 回调处理
     281              :      * @param sessionID 目标会话
     282              :      * @param report 执行报告
     283              :      *
     284              :      * 将 ExecutionReport 转换为 FIX 消息并发送到客户端。
     285              :      * 同时更新账户和持仓状态。
     286              :      */
     287              :     void onExecutionReport(const SessionID& sessionID, const ExecutionReport& report);
     288              : 
     289              :     /**
     290              :      * @brief 处理订单成交
     291              :      * 
     292              :      * 更新账户资金和持仓状态。
     293              :      * 
     294              :      * @param accountId 账户ID
     295              :      * @param report 执行报告
     296              :      */
     297              :     void handleFill(const std::string& accountId, const ExecutionReport& report);
     298              : 
     299              :     /**
     300              :      * @brief 处理订单拒绝
     301              :      * 
     302              :      * 释放冻结的保证金。
     303              :      * 
     304              :      * @param accountId 账户ID
     305              :      * @param report 执行报告
     306              :      */
     307              :     void handleReject(const std::string& accountId, const ExecutionReport& report);
     308              : 
     309              :     /**
     310              :      * @brief 处理订单撤销
     311              :      * 
     312              :      * 释放冻结的保证金。
     313              :      * 
     314              :      * @param accountId 账户ID
     315              :      * @param report 执行报告
     316              :      */
     317              :     void handleCancel(const std::string& accountId, const ExecutionReport& report);
     318              : 
     319              :     /**
     320              :      * @brief 从SessionID提取账户ID
     321              :      * 
     322              :      * 使用 SenderCompID 作为账户ID,实现身份绑定。
     323              :      * 
     324              :      * @param sessionID 会话ID
     325              :      * @return 账户ID(使用SenderCompID)
     326              :      */
     327              :     std::string extractAccountId(const SessionID& sessionID) const;
     328              : 
     329              :     // =========================================================================
     330              :     // 消息处理函数 (Message Handlers)
     331              :     // =========================================================================
     332              : 
     333              :     /**
     334              :      * @brief 处理新订单 (MsgType = D)
     335              :      * 
     336              :      * @param msg FIX 消息
     337              :      * @param sessionID 会话标识
     338              :      * @param userId 绑定的用户ID(从 Session 提取,非消息体)
     339              :      */
     340              :     void handleNewOrderSingle(const FixMessage& msg, const SessionID& sessionID, const std::string& userId);
     341              : 
     342              :     /**
     343              :      * @brief 处理撤单请求 (MsgType = F)
     344              :      * 
     345              :      * @param msg FIX 消息
     346              :      * @param sessionID 会话标识
     347              :      * @param userId 绑定的用户ID
     348              :      */
     349              :     void handleOrderCancelRequest(const FixMessage& msg, const SessionID& sessionID, const std::string& userId);
     350              : 
     351              :     /**
     352              :      * @brief 处理资金查询请求 (MsgType = U1)
     353              :      * 
     354              :      * 查询用户账户的资金信息,返回 U2 响应。
     355              :      * 
     356              :      * @param msg FIX 消息
     357              :      * @param sessionID 会话标识
     358              :      * @param userId 绑定的用户ID
     359              :      */
     360              :     void handleBalanceQuery(const FixMessage& msg, const SessionID& sessionID, const std::string& userId);
     361              : 
     362              :     /**
     363              :      * @brief 处理持仓查询请求 (MsgType = U3)
     364              :      * 
     365              :      * 查询用户的持仓信息,返回 U4 响应。
     366              :      * 
     367              :      * @param msg FIX 消息
     368              :      * @param sessionID 会话标识
     369              :      * @param userId 绑定的用户ID
     370              :      */
     371              :     void handlePositionQuery(const FixMessage& msg, const SessionID& sessionID, const std::string& userId);
     372              : 
     373              :     /**
     374              :      * @brief 处理合约搜索请求 (MsgType = U7)
     375              :      * 
     376              :      * 根据前缀搜索合约,返回 U8 响应。
     377              :      * 用于 Client 端的合约代码自动补全功能。
     378              :      * 
     379              :      * @param msg FIX 消息
     380              :      * @param sessionID 会话标识
     381              :      */
     382              :     void handleInstrumentSearch(const FixMessage& msg, const SessionID& sessionID);
     383              : 
     384              :     /**
     385              :      * @brief 处理订单历史查询请求 (MsgType = U9)
     386              :      *
     387              :      * 从服务端持久化存储中加载该用户的历史订单,并返回 U10 响应。
     388              :      *
     389              :      * @param msg FIX 请求消息
     390              :      * @param sessionID 会话标识
     391              :      * @param userId 绑定的用户ID(从 Session 提取,非消息体)
     392              :      *
     393              :      * @note 由于 FIX RepeatingGroup 实现较复杂,本项目将订单列表序列化为文本放入 Text(58)。
     394              :      */
     395              :     void handleOrderHistoryQuery(const FixMessage& msg, const SessionID& sessionID, const std::string& userId);
     396              : 
     397              :     /**
     398              :      * @brief 发送拒绝消息
     399              :      * 
     400              :      * 当收到无法处理的消息时,发送 BusinessMessageReject。
     401              :      * 
     402              :      * @param sessionID 会话标识
     403              :      * @param refMsgType 被拒绝的消息类型
     404              :      * @param reason 拒绝原因
     405              :      */
     406              :     void sendBusinessReject(const SessionID& sessionID, const std::string& refMsgType, const std::string& reason);
     407              : 
     408              :     // =========================================================================
     409              :     // 行情驱动账户更新 (Market-Driven Account Update)
     410              :     // =========================================================================
     411              : 
     412              :     /**
     413              :      * @brief 处理行情更新,重算所有相关账户的价值
     414              :      * 
     415              :      * 当行情变化时调用,更新持仓浮动盈亏和账户价值。
     416              :      * 可选择性地推送更新给相关 Client。
     417              :      * 
     418              :      * @param instrumentId 合约代码
     419              :      * @param lastPrice 最新价
     420              :      */
     421              :     void onMarketDataUpdate(const std::string& instrumentId, double lastPrice);
     422              : 
     423              :     /**
     424              :      * @brief 向指定用户推送账户更新 (MsgType = U5)
     425              :      * 
     426              :      * 当账户价值发生变化时,主动推送给 Client。
     427              :      * 
     428              :      * @param userId 用户ID
     429              :      * @param reason 更新原因 (1=行情变化, 2=成交, 3=出入金)
     430              :      */
     431              :     void pushAccountUpdate(const std::string& userId, int reason = 1);
     432              : 
     433              :     /**
     434              :      * @brief 向指定用户推送持仓更新 (MsgType = U6)
     435              :      * 
     436              :      * 当持仓发生变化时,主动推送给 Client。
     437              :      * 
     438              :      * @param userId 用户ID
     439              :      * @param instrumentId 合约代码
     440              :      * @param reason 更新原因
     441              :      */
     442              :     void pushPositionUpdate(const std::string& userId, const std::string& instrumentId, int reason = 1);
     443              : 
     444              :     /**
     445              :      * @brief 根据用户ID查找对应的 SessionID
     446              :      * 
     447              :      * @param userId 用户ID
     448              :      * @return std::optional<SessionID> 找到返回 SessionID,否则返回 nullopt
     449              :      */
     450              :     std::optional<SessionID> findSessionByUserId(const std::string& userId) const;
     451              : 
     452              :     // =========================================================================
     453              :     // 成员变量
     454              :     // =========================================================================
     455              : 
     456              :     MatchingEngine engine_;              ///< 撮合引擎
     457              :     SessionManager sessionManager_;      ///< 会话管理器
     458              :     
     459              :     AccountManager accountManager_;      ///< 账户管理器
     460              :     PositionManager positionManager_;    ///< 持仓管理器
     461              :     InstrumentManager instrumentManager_; ///< 合约管理器
     462              :     RiskManager riskManager_;            ///< 风控管理器
     463              :     
     464              :     IStore* store_ = nullptr;            ///< 存储接口(可为nullptr)
     465              : 
     466              :     /// 订单到账户的映射:clOrdID -> accountId
     467              :     std::unordered_map<std::string, std::string> orderAccountMap_;
     468              :     
     469              :     /// 订单保证金信息映射:clOrdID -> OrderMarginInfo
     470              :     std::unordered_map<std::string, OrderMarginInfo> orderMarginInfoMap_;
     471              :     
     472              :     /// 互斥锁,保护映射表
     473              :     mutable std::mutex mapMutex_;
     474              : };
     475              : 
     476              : } // namespace fix40
        

Generated by: LCOV version 2.0-1