Line data Source code
1 : /**
2 : * @file md_adapter.hpp
3 : * @brief 行情适配器接口定义
4 : *
5 : * 定义行情数据源的抽象接口,支持多种行情源(CTP、模拟等)。
6 : * 适配器负责:连接数据源 -> 接收原始数据 -> 转换为 MarketData -> 写入队列
7 : */
8 :
9 : #pragma once
10 :
11 : #include <string>
12 : #include <vector>
13 : #include <functional>
14 : #include <atomic>
15 : #include "market/market_data.hpp"
16 : #include "base/blockingconcurrentqueue.h"
17 :
18 : namespace fix40 {
19 :
20 : /**
21 : * @enum MdAdapterState
22 : * @brief 行情适配器状态
23 : */
24 : enum class MdAdapterState {
25 : DISCONNECTED, ///< 未连接
26 : CONNECTING, ///< 连接中
27 : CONNECTED, ///< 已连接(未登录)
28 : LOGGING_IN, ///< 登录中
29 : READY, ///< 就绪(已登录,可订阅)
30 : ERROR ///< 错误状态
31 : };
32 :
33 : /**
34 : * @brief 状态变更回调类型
35 : * @param state 新状态
36 : * @param message 状态描述信息
37 : */
38 : using StateCallback = std::function<void(MdAdapterState state, const std::string& message)>;
39 :
40 : /**
41 : * @class MdAdapter
42 : * @brief 行情适配器抽象接口
43 : *
44 : * 所有行情数据源都应实现此接口。适配器的职责:
45 : * 1. 管理与数据源的连接
46 : * 2. 处理登录/登出
47 : * 3. 订阅/退订合约
48 : * 4. 将收到的行情转换为 MarketData 格式
49 : * 5. 将 MarketData 写入无锁队列供下游消费
50 : *
51 : * @par 线程模型
52 : * - 适配器内部可能有自己的回调线程(如 CTP)
53 : * - 所有行情数据通过无锁队列传递,避免阻塞回调线程
54 : * - start()/stop() 应由主线程调用
55 : *
56 : * @par 使用示例
57 : * @code
58 : * moodycamel::BlockingConcurrentQueue<MarketData> mdQueue;
59 : * auto adapter = std::make_unique<MockMdAdapter>(mdQueue);
60 : *
61 : * adapter->setStateCallback([](MdAdapterState state, const std::string& msg) {
62 : * LOG() << "State: " << static_cast<int>(state) << " - " << msg;
63 : * });
64 : *
65 : * adapter->start();
66 : * adapter->subscribe({"IF2401", "IC2401"});
67 : *
68 : * // 消费行情
69 : * MarketData md;
70 : * while (mdQueue.wait_dequeue_timed(md, std::chrono::milliseconds(100))) {
71 : * process(md);
72 : * }
73 : *
74 : * adapter->stop();
75 : * @endcode
76 : */
77 : class MdAdapter {
78 : public:
79 : /**
80 : * @brief 虚析构函数
81 : */
82 14 : virtual ~MdAdapter() = default;
83 :
84 : // =========================================================================
85 : // 生命周期管理
86 : // =========================================================================
87 :
88 : /**
89 : * @brief 启动适配器
90 : * @return true 启动成功
91 : * @return false 启动失败
92 : *
93 : * 启动后适配器会尝试连接数据源并登录。
94 : * 状态变化通过 StateCallback 通知。
95 : */
96 : virtual bool start() = 0;
97 :
98 : /**
99 : * @brief 停止适配器
100 : *
101 : * 断开与数据源的连接,释放资源。
102 : * 调用后适配器进入 DISCONNECTED 状态。
103 : */
104 : virtual void stop() = 0;
105 :
106 : /**
107 : * @brief 检查适配器是否正在运行
108 : * @return true 正在运行
109 : * @return false 已停止
110 : */
111 : virtual bool isRunning() const = 0;
112 :
113 : /**
114 : * @brief 获取当前状态
115 : * @return MdAdapterState 当前状态
116 : */
117 : virtual MdAdapterState getState() const = 0;
118 :
119 : // =========================================================================
120 : // 订阅管理
121 : // =========================================================================
122 :
123 : /**
124 : * @brief 订阅合约行情
125 : * @param instruments 合约代码列表
126 : * @return true 订阅请求已发送
127 : * @return false 订阅失败(如未连接)
128 : *
129 : * @note 订阅结果通过 StateCallback 异步通知
130 : */
131 : virtual bool subscribe(const std::vector<std::string>& instruments) = 0;
132 :
133 : /**
134 : * @brief 退订合约行情
135 : * @param instruments 合约代码列表
136 : * @return true 退订请求已发送
137 : * @return false 退订失败
138 : */
139 : virtual bool unsubscribe(const std::vector<std::string>& instruments) = 0;
140 :
141 : // =========================================================================
142 : // 回调设置
143 : // =========================================================================
144 :
145 : /**
146 : * @brief 设置状态变更回调
147 : * @param callback 回调函数
148 : */
149 : virtual void setStateCallback(StateCallback callback) = 0;
150 :
151 : // =========================================================================
152 : // 信息查询
153 : // =========================================================================
154 :
155 : /**
156 : * @brief 获取适配器名称
157 : * @return std::string 适配器名称(如 "CTP", "Mock")
158 : */
159 : virtual std::string getName() const = 0;
160 :
161 : /**
162 : * @brief 获取交易日
163 : * @return std::string 交易日 (YYYYMMDD),未连接时返回空
164 : */
165 : virtual std::string getTradingDay() const = 0;
166 :
167 : protected:
168 : /**
169 : * @brief 构造函数
170 : * @param queue 行情数据输出队列
171 : */
172 14 : explicit MdAdapter(moodycamel::BlockingConcurrentQueue<MarketData>& queue)
173 14 : : marketDataQueue_(queue) {}
174 :
175 : /**
176 : * @brief 将行情数据写入队列
177 : * @param data 行情数据
178 : *
179 : * 子类在收到行情后调用此方法将数据写入队列。
180 : */
181 : void pushMarketData(const MarketData& data) {
182 : marketDataQueue_.enqueue(data);
183 : }
184 :
185 : /**
186 : * @brief 将行情数据写入队列(移动语义)
187 : * @param data 行情数据
188 : */
189 33 : void pushMarketData(MarketData&& data) {
190 33 : marketDataQueue_.enqueue(std::move(data));
191 33 : }
192 :
193 : /// 行情数据输出队列
194 : moodycamel::BlockingConcurrentQueue<MarketData>& marketDataQueue_;
195 : };
196 :
197 : } // namespace fix40
|