Line data Source code
1 : /**
2 : * @file mock_md_adapter.hpp
3 : * @brief 模拟行情适配器
4 : *
5 : * 用于测试和开发的模拟行情源,生成随机行情数据。
6 : */
7 :
8 : #pragma once
9 :
10 : #include <thread>
11 : #include <atomic>
12 : #include <mutex>
13 : #include <set>
14 : #include <map>
15 : #include <random>
16 : #include <chrono>
17 : #include "market/md_adapter.hpp"
18 :
19 : namespace fix40 {
20 :
21 : /**
22 : * @class MockMdAdapter
23 : * @brief 模拟行情适配器
24 : *
25 : * 生成模拟行情数据用于测试。特点:
26 : * - 在独立线程中按固定频率生成行情
27 : * - 支持订阅/退订合约
28 : * - 价格在基准价附近随机波动
29 : *
30 : * @par 使用示例
31 : * @code
32 : * moodycamel::BlockingConcurrentQueue<MarketData> queue;
33 : * MockMdAdapter adapter(queue);
34 : *
35 : * adapter.setTickInterval(std::chrono::milliseconds(500)); // 500ms 一个 tick
36 : * adapter.start();
37 : * adapter.subscribe({"IF2401", "IC2401"});
38 : *
39 : * // 消费行情...
40 : *
41 : * adapter.stop();
42 : * @endcode
43 : */
44 : class MockMdAdapter : public MdAdapter {
45 : public:
46 : /**
47 : * @brief 构造模拟行情适配器
48 : * @param queue 行情数据输出队列
49 : */
50 : explicit MockMdAdapter(moodycamel::BlockingConcurrentQueue<MarketData>& queue);
51 :
52 : /**
53 : * @brief 析构函数
54 : */
55 : ~MockMdAdapter() override;
56 :
57 : // 禁止拷贝
58 : MockMdAdapter(const MockMdAdapter&) = delete;
59 : MockMdAdapter& operator=(const MockMdAdapter&) = delete;
60 :
61 : // =========================================================================
62 : // MdAdapter 接口实现
63 : // =========================================================================
64 :
65 : bool start() override;
66 : void stop() override;
67 5 : bool isRunning() const override { return running_.load(); }
68 3 : MdAdapterState getState() const override { return state_.load(); }
69 :
70 : bool subscribe(const std::vector<std::string>& instruments) override;
71 : bool unsubscribe(const std::vector<std::string>& instruments) override;
72 :
73 : void setStateCallback(StateCallback callback) override;
74 :
75 3 : std::string getName() const override { return "Mock"; }
76 : std::string getTradingDay() const override;
77 :
78 : // =========================================================================
79 : // Mock 特有配置
80 : // =========================================================================
81 :
82 : /**
83 : * @brief 设置行情生成间隔
84 : * @param interval 间隔时间
85 : * @note 应在 start() 之前调用,运行时修改行为未定义
86 : */
87 5 : void setTickInterval(std::chrono::milliseconds interval) {
88 5 : tickIntervalMs_.store(interval.count());
89 5 : }
90 :
91 : /**
92 : * @brief 设置基准价格
93 : * @param instrument 合约代码
94 : * @param basePrice 基准价格
95 : *
96 : * 模拟行情会在基准价格附近波动。
97 : * 未设置的合约使用默认基准价 5000.0。
98 : */
99 : void setBasePrice(const std::string& instrument, double basePrice);
100 :
101 : /**
102 : * @brief 设置价格波动幅度(百分比)
103 : * @param volatility 波动幅度,如 0.01 表示 1%
104 : * @note 应在 start() 之前调用,运行时修改行为未定义
105 : */
106 : void setVolatility(double volatility) {
107 : volatility_.store(volatility);
108 : }
109 :
110 : private:
111 : /**
112 : * @brief 行情生成线程主循环
113 : */
114 : void run();
115 :
116 : /**
117 : * @brief 生成单个合约的行情
118 : * @param instrument 合约代码
119 : * @return MarketData 生成的行情数据
120 : */
121 : MarketData generateTick(const std::string& instrument);
122 :
123 : /**
124 : * @brief 通知状态变更
125 : * @param state 新状态
126 : * @param message 描述信息
127 : */
128 : void notifyState(MdAdapterState state, const std::string& message);
129 :
130 : /**
131 : * @brief 获取当前时间字符串
132 : * @return std::string 格式 HH:MM:SS
133 : */
134 : std::string getCurrentTime() const;
135 :
136 : std::atomic<bool> running_{false};
137 : std::atomic<MdAdapterState> state_{MdAdapterState::DISCONNECTED};
138 : std::thread workerThread_;
139 :
140 : mutable std::mutex mutex_;
141 : std::set<std::string> subscribedInstruments_;
142 : std::map<std::string, double> basePrices_;
143 : std::map<std::string, double> lastPrices_;
144 :
145 : StateCallback stateCallback_;
146 : std::atomic<int64_t> tickIntervalMs_{1000}; ///< 行情间隔(毫秒),使用 int64_t 保证 lock-free
147 : std::atomic<double> volatility_{0.005}; ///< 默认 0.5% 波动
148 :
149 : std::mt19937 rng_; ///< 随机数生成器(仅工作线程访问)
150 : const std::string tradingDay_; ///< 交易日(构造后不变)
151 : };
152 :
153 : } // namespace fix40
|