Line data Source code
1 : /**
2 : * @file sqlite_store.cpp
3 : * @brief SQLite 持久化存储实现
4 : */
5 :
6 : #include "storage/sqlite_store.hpp"
7 : #include "base/logger.hpp"
8 : #include <chrono>
9 : #include <filesystem>
10 :
11 : namespace fix40 {
12 :
13 1136 : SqliteStore::SqliteStore(const std::string& dbPath) {
14 : // 如果不是内存数据库,确保目录存在
15 1136 : if (dbPath != ":memory:") {
16 2 : std::filesystem::path path(dbPath);
17 2 : if (path.has_parent_path()) {
18 2 : std::error_code ec;
19 2 : std::filesystem::create_directories(path.parent_path(), ec);
20 2 : if (ec) {
21 0 : LOG() << "[SqliteStore] 创建目录失败: " << ec.message();
22 : }
23 : }
24 2 : }
25 :
26 1136 : int rc = sqlite3_open(dbPath.c_str(), &db_);
27 1136 : if (rc != SQLITE_OK) {
28 0 : LOG() << "[SqliteStore] 打开数据库失败: " << sqlite3_errmsg(db_);
29 0 : sqlite3_close(db_);
30 0 : db_ = nullptr;
31 0 : return;
32 : }
33 :
34 : // 启用 WAL 模式提高并发性能
35 2272 : execute("PRAGMA journal_mode=WAL");
36 2272 : execute("PRAGMA synchronous=NORMAL");
37 : // 启用外键约束
38 1136 : execute("PRAGMA foreign_keys=ON");
39 :
40 1136 : if (!initTables()) {
41 0 : LOG() << "[SqliteStore] 初始化表失败";
42 0 : sqlite3_close(db_);
43 0 : db_ = nullptr;
44 0 : return;
45 : }
46 :
47 1136 : LOG() << "[SqliteStore] 数据库已打开: " << dbPath;
48 0 : }
49 :
50 1136 : SqliteStore::~SqliteStore() {
51 1136 : if (db_) {
52 1136 : sqlite3_close(db_);
53 1136 : LOG() << "[SqliteStore] 数据库已关闭";
54 : }
55 1136 : }
56 :
57 1136 : bool SqliteStore::initTables() {
58 : // 订单表
59 1136 : const char* createOrders = R"(
60 : CREATE TABLE IF NOT EXISTS orders (
61 : cl_ord_id TEXT PRIMARY KEY,
62 : order_id TEXT,
63 : account_id TEXT NOT NULL DEFAULT '',
64 : symbol TEXT NOT NULL,
65 : side INTEGER NOT NULL,
66 : order_type INTEGER NOT NULL,
67 : time_in_force INTEGER NOT NULL,
68 : price REAL NOT NULL,
69 : order_qty INTEGER NOT NULL,
70 : cum_qty INTEGER NOT NULL DEFAULT 0,
71 : leaves_qty INTEGER NOT NULL DEFAULT 0,
72 : avg_px REAL NOT NULL DEFAULT 0,
73 : status INTEGER NOT NULL,
74 : create_time INTEGER NOT NULL,
75 : update_time INTEGER NOT NULL
76 : )
77 : )";
78 :
79 : // 成交表
80 1136 : const char* createTrades = R"(
81 : CREATE TABLE IF NOT EXISTS trades (
82 : trade_id TEXT PRIMARY KEY,
83 : cl_ord_id TEXT NOT NULL,
84 : symbol TEXT NOT NULL,
85 : side INTEGER NOT NULL,
86 : price REAL NOT NULL,
87 : quantity INTEGER NOT NULL,
88 : timestamp INTEGER NOT NULL,
89 : counterparty_order_id TEXT,
90 : FOREIGN KEY (cl_ord_id) REFERENCES orders(cl_ord_id)
91 : )
92 : )";
93 :
94 : // 会话状态表
95 1136 : const char* createSessions = R"(
96 : CREATE TABLE IF NOT EXISTS session_states (
97 : sender_comp_id TEXT NOT NULL,
98 : target_comp_id TEXT NOT NULL,
99 : send_seq_num INTEGER NOT NULL,
100 : recv_seq_num INTEGER NOT NULL,
101 : last_update_time INTEGER NOT NULL,
102 : PRIMARY KEY (sender_comp_id, target_comp_id)
103 : )
104 : )";
105 :
106 : // 消息存储表 (用于重传)
107 1136 : const char* createMessages = R"(
108 : CREATE TABLE IF NOT EXISTS messages (
109 : id INTEGER PRIMARY KEY AUTOINCREMENT,
110 : seq_num INTEGER NOT NULL,
111 : sender_comp_id TEXT NOT NULL,
112 : target_comp_id TEXT NOT NULL,
113 : msg_type TEXT NOT NULL,
114 : raw_message TEXT NOT NULL,
115 : timestamp INTEGER NOT NULL
116 : )
117 : )";
118 :
119 : // 账户表
120 1136 : const char* createAccounts = R"(
121 : CREATE TABLE IF NOT EXISTS accounts (
122 : account_id TEXT PRIMARY KEY,
123 : balance REAL NOT NULL DEFAULT 0,
124 : available REAL NOT NULL DEFAULT 0,
125 : frozen_margin REAL NOT NULL DEFAULT 0,
126 : used_margin REAL NOT NULL DEFAULT 0,
127 : position_profit REAL NOT NULL DEFAULT 0,
128 : close_profit REAL NOT NULL DEFAULT 0,
129 : update_time INTEGER NOT NULL
130 : )
131 : )";
132 :
133 : // 持仓表
134 1136 : const char* createPositions = R"(
135 : CREATE TABLE IF NOT EXISTS positions (
136 : account_id TEXT NOT NULL,
137 : instrument_id TEXT NOT NULL,
138 : long_position INTEGER NOT NULL DEFAULT 0,
139 : long_avg_price REAL NOT NULL DEFAULT 0,
140 : long_profit REAL NOT NULL DEFAULT 0,
141 : long_margin REAL NOT NULL DEFAULT 0,
142 : short_position INTEGER NOT NULL DEFAULT 0,
143 : short_avg_price REAL NOT NULL DEFAULT 0,
144 : short_profit REAL NOT NULL DEFAULT 0,
145 : short_margin REAL NOT NULL DEFAULT 0,
146 : update_time INTEGER NOT NULL,
147 : PRIMARY KEY (account_id, instrument_id)
148 : )
149 : )";
150 :
151 : // 创建索引
152 1136 : const char* createIndexes = R"(
153 : CREATE INDEX IF NOT EXISTS idx_orders_symbol ON orders(symbol);
154 : CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status);
155 : CREATE INDEX IF NOT EXISTS idx_orders_account ON orders(account_id);
156 : CREATE INDEX IF NOT EXISTS idx_trades_cl_ord_id ON trades(cl_ord_id);
157 : CREATE INDEX IF NOT EXISTS idx_trades_symbol ON trades(symbol);
158 : CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(sender_comp_id, target_comp_id, seq_num);
159 : CREATE INDEX IF NOT EXISTS idx_positions_account ON positions(account_id);
160 : )";
161 :
162 : // 兼容旧数据库:为 orders 表补齐 account_id 字段(用于按用户隔离查询订单历史)。
163 : // SQLite 不支持 IF NOT EXISTS,因此这里容错“重复列名”错误。
164 1136 : auto addOrderAccountIdColumn = [&]() -> bool {
165 1136 : if (!db_) return false;
166 1136 : char* errMsg = nullptr;
167 1136 : const char* sql = "ALTER TABLE orders ADD COLUMN account_id TEXT NOT NULL DEFAULT ''";
168 1136 : int rc = sqlite3_exec(db_, sql, nullptr, nullptr, &errMsg);
169 1136 : if (rc == SQLITE_OK) {
170 0 : return true;
171 : }
172 2272 : const std::string err = errMsg ? std::string(errMsg) : "";
173 1136 : sqlite3_free(errMsg);
174 1136 : if (err.find("duplicate column name") != std::string::npos) {
175 1136 : return true;
176 : }
177 0 : LOG() << "[SqliteStore] SQL 执行失败: " << err;
178 0 : return false;
179 1136 : };
180 :
181 6816 : return execute(createOrders) && addOrderAccountIdColumn() && execute(createTrades) &&
182 5680 : execute(createSessions) && execute(createMessages) &&
183 10224 : execute(createAccounts) && execute(createPositions) && execute(createIndexes);
184 : }
185 :
186 11360 : bool SqliteStore::execute(const std::string& sql) {
187 11360 : if (!db_) {
188 0 : LOG() << "[SqliteStore] SQL 执行失败: 数据库未打开";
189 0 : return false;
190 : }
191 11360 : char* errMsg = nullptr;
192 11360 : int rc = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &errMsg);
193 11360 : if (rc != SQLITE_OK) {
194 0 : LOG() << "[SqliteStore] SQL 执行失败: " << errMsg;
195 0 : sqlite3_free(errMsg);
196 0 : return false;
197 : }
198 11360 : return true;
199 : }
200 :
201 : // =============================================================================
202 : // 辅助函数:从 SQLite 结果行提取对象
203 : // =============================================================================
204 :
205 14 : Order SqliteStore::extractOrder(sqlite3_stmt* stmt) {
206 14 : Order order;
207 14 : const char* clOrdID = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
208 14 : const char* orderID = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
209 14 : const char* symbol = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
210 14 : order.clOrdID = clOrdID ? clOrdID : "";
211 14 : order.orderID = orderID ? orderID : "";
212 14 : order.symbol = symbol ? symbol : "";
213 14 : order.side = static_cast<OrderSide>(sqlite3_column_int(stmt, 3));
214 14 : order.ordType = static_cast<OrderType>(sqlite3_column_int(stmt, 4));
215 14 : order.timeInForce = static_cast<TimeInForce>(sqlite3_column_int(stmt, 5));
216 14 : order.price = sqlite3_column_double(stmt, 6);
217 14 : order.orderQty = sqlite3_column_int64(stmt, 7);
218 14 : order.cumQty = sqlite3_column_int64(stmt, 8);
219 14 : order.leavesQty = sqlite3_column_int64(stmt, 9);
220 14 : order.avgPx = sqlite3_column_double(stmt, 10);
221 14 : order.status = static_cast<OrderStatus>(sqlite3_column_int(stmt, 11));
222 14 : return order;
223 0 : }
224 :
225 2 : StoredTrade SqliteStore::extractTrade(sqlite3_stmt* stmt) {
226 2 : StoredTrade trade;
227 2 : const char* tradeId = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
228 2 : const char* clOrdID = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
229 2 : const char* symbol = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
230 2 : trade.tradeId = tradeId ? tradeId : "";
231 2 : trade.clOrdID = clOrdID ? clOrdID : "";
232 2 : trade.symbol = symbol ? symbol : "";
233 2 : trade.side = static_cast<OrderSide>(sqlite3_column_int(stmt, 3));
234 2 : trade.price = sqlite3_column_double(stmt, 4);
235 2 : trade.quantity = sqlite3_column_int64(stmt, 5);
236 2 : trade.timestamp = sqlite3_column_int64(stmt, 6);
237 2 : const char* cp = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7));
238 2 : trade.counterpartyOrderId = cp ? cp : "";
239 2 : return trade;
240 0 : }
241 :
242 : // =============================================================================
243 : // 订单存储
244 : // =============================================================================
245 :
246 10 : bool SqliteStore::saveOrder(const Order& order) {
247 30 : return saveOrderForAccount(order, "");
248 : }
249 :
250 16 : bool SqliteStore::saveOrderForAccount(const Order& order, const std::string& accountId) {
251 16 : std::lock_guard<std::mutex> lock(mutex_);
252 16 : if (!db_) return false;
253 :
254 16 : const char* sql = R"(
255 : INSERT INTO orders (cl_ord_id, order_id, account_id, symbol, side, order_type, time_in_force,
256 : price, order_qty, cum_qty, leaves_qty, avg_px, status, create_time, update_time)
257 : VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
258 : )";
259 :
260 16 : sqlite3_stmt* stmt = nullptr;
261 16 : int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
262 16 : if (rc != SQLITE_OK) {
263 0 : LOG() << "[SqliteStore] 准备语句失败: " << sqlite3_errmsg(db_);
264 0 : return false;
265 : }
266 :
267 16 : auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
268 32 : std::chrono::system_clock::now().time_since_epoch()).count();
269 :
270 16 : sqlite3_bind_text(stmt, 1, order.clOrdID.c_str(), -1, SQLITE_TRANSIENT);
271 16 : sqlite3_bind_text(stmt, 2, order.orderID.c_str(), -1, SQLITE_TRANSIENT);
272 16 : sqlite3_bind_text(stmt, 3, accountId.c_str(), -1, SQLITE_TRANSIENT);
273 16 : sqlite3_bind_text(stmt, 4, order.symbol.c_str(), -1, SQLITE_TRANSIENT);
274 16 : sqlite3_bind_int(stmt, 5, static_cast<int>(order.side));
275 16 : sqlite3_bind_int(stmt, 6, static_cast<int>(order.ordType));
276 16 : sqlite3_bind_int(stmt, 7, static_cast<int>(order.timeInForce));
277 16 : sqlite3_bind_double(stmt, 8, order.price);
278 16 : sqlite3_bind_int64(stmt, 9, order.orderQty);
279 16 : sqlite3_bind_int64(stmt, 10, order.cumQty);
280 16 : sqlite3_bind_int64(stmt, 11, order.leavesQty);
281 16 : sqlite3_bind_double(stmt, 12, order.avgPx);
282 16 : sqlite3_bind_int(stmt, 13, static_cast<int>(order.status));
283 16 : sqlite3_bind_int64(stmt, 14, now);
284 16 : sqlite3_bind_int64(stmt, 15, now);
285 :
286 16 : rc = sqlite3_step(stmt);
287 16 : sqlite3_finalize(stmt);
288 :
289 16 : if (rc != SQLITE_DONE) {
290 0 : LOG() << "[SqliteStore] 保存订单失败: " << sqlite3_errmsg(db_);
291 0 : return false;
292 : }
293 16 : return true;
294 16 : }
295 :
296 3 : bool SqliteStore::updateOrder(const Order& order) {
297 3 : std::lock_guard<std::mutex> lock(mutex_);
298 3 : if (!db_) return false;
299 :
300 3 : const char* sql = R"(
301 : UPDATE orders SET
302 : -- 仅在新值非空时更新 order_id:
303 : -- 该行为使 updateOrder() 幂等且避免“错误清空”订单号;
304 : -- 如需显式清空字段,请提供单独的维护接口(当前暂不支持)。
305 : order_id = COALESCE(NULLIF(?, ''), order_id),
306 : cum_qty = ?,
307 : leaves_qty = ?,
308 : avg_px = ?,
309 : status = ?,
310 : update_time = ?
311 : WHERE cl_ord_id = ?
312 : )";
313 :
314 3 : sqlite3_stmt* stmt = nullptr;
315 3 : int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
316 3 : if (rc != SQLITE_OK) {
317 0 : return false;
318 : }
319 :
320 3 : auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
321 6 : std::chrono::system_clock::now().time_since_epoch()).count();
322 :
323 3 : sqlite3_bind_text(stmt, 1, order.orderID.c_str(), -1, SQLITE_TRANSIENT);
324 3 : sqlite3_bind_int64(stmt, 2, order.cumQty);
325 3 : sqlite3_bind_int64(stmt, 3, order.leavesQty);
326 3 : sqlite3_bind_double(stmt, 4, order.avgPx);
327 3 : sqlite3_bind_int(stmt, 5, static_cast<int>(order.status));
328 3 : sqlite3_bind_int64(stmt, 6, now);
329 3 : sqlite3_bind_text(stmt, 7, order.clOrdID.c_str(), -1, SQLITE_TRANSIENT);
330 :
331 3 : rc = sqlite3_step(stmt);
332 3 : sqlite3_finalize(stmt);
333 :
334 3 : return rc == SQLITE_DONE;
335 3 : }
336 :
337 7 : std::optional<Order> SqliteStore::loadOrder(const std::string& clOrdID) {
338 7 : std::lock_guard<std::mutex> lock(mutex_);
339 7 : if (!db_) return std::nullopt;
340 :
341 7 : const char* sql = R"(
342 : SELECT cl_ord_id, order_id, symbol, side, order_type, time_in_force,
343 : price, order_qty, cum_qty, leaves_qty, avg_px, status
344 : FROM orders WHERE cl_ord_id = ?
345 : )";
346 :
347 7 : sqlite3_stmt* stmt = nullptr;
348 7 : int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
349 7 : if (rc != SQLITE_OK) {
350 0 : return std::nullopt;
351 : }
352 :
353 7 : sqlite3_bind_text(stmt, 1, clOrdID.c_str(), -1, SQLITE_TRANSIENT);
354 :
355 7 : if (sqlite3_step(stmt) == SQLITE_ROW) {
356 7 : Order order = extractOrder(stmt);
357 7 : sqlite3_finalize(stmt);
358 7 : return order;
359 7 : }
360 :
361 0 : sqlite3_finalize(stmt);
362 0 : return std::nullopt;
363 7 : }
364 :
365 2 : std::vector<Order> SqliteStore::loadOrdersBySymbol(const std::string& symbol) {
366 2 : std::lock_guard<std::mutex> lock(mutex_);
367 2 : std::vector<Order> orders;
368 2 : if (!db_) return orders;
369 :
370 2 : const char* sql = R"(
371 : SELECT cl_ord_id, order_id, symbol, side, order_type, time_in_force,
372 : price, order_qty, cum_qty, leaves_qty, avg_px, status
373 : FROM orders WHERE symbol = ?
374 : )";
375 :
376 2 : sqlite3_stmt* stmt = nullptr;
377 2 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
378 0 : return orders;
379 : }
380 :
381 2 : sqlite3_bind_text(stmt, 1, symbol.c_str(), -1, SQLITE_TRANSIENT);
382 :
383 5 : while (sqlite3_step(stmt) == SQLITE_ROW) {
384 3 : orders.push_back(extractOrder(stmt));
385 : }
386 :
387 2 : sqlite3_finalize(stmt);
388 2 : return orders;
389 2 : }
390 :
391 3 : std::vector<Order> SqliteStore::loadOrdersByAccount(const std::string& accountId) {
392 3 : std::lock_guard<std::mutex> lock(mutex_);
393 3 : std::vector<Order> orders;
394 3 : if (!db_) return orders;
395 :
396 3 : const char* sql = R"(
397 : SELECT cl_ord_id, order_id, symbol, side, order_type, time_in_force,
398 : price, order_qty, cum_qty, leaves_qty, avg_px, status
399 : FROM orders WHERE account_id = ? ORDER BY create_time DESC
400 : )";
401 :
402 3 : sqlite3_stmt* stmt = nullptr;
403 3 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
404 0 : return orders;
405 : }
406 :
407 3 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
408 :
409 6 : while (sqlite3_step(stmt) == SQLITE_ROW) {
410 3 : orders.push_back(extractOrder(stmt));
411 : }
412 :
413 3 : sqlite3_finalize(stmt);
414 3 : return orders;
415 3 : }
416 :
417 1 : std::vector<Order> SqliteStore::loadActiveOrders() {
418 1 : std::lock_guard<std::mutex> lock(mutex_);
419 1 : std::vector<Order> orders;
420 1 : if (!db_) return orders;
421 :
422 : // 使用枚举值构建 SQL,避免硬编码魔术数字
423 : std::string sql = R"(
424 : SELECT cl_ord_id, order_id, symbol, side, order_type, time_in_force,
425 : price, order_qty, cum_qty, leaves_qty, avg_px, status
426 2 : FROM orders WHERE status IN ()" +
427 4 : std::to_string(static_cast<int>(OrderStatus::NEW)) + ", " +
428 4 : std::to_string(static_cast<int>(OrderStatus::PARTIALLY_FILLED)) + ", " +
429 3 : std::to_string(static_cast<int>(OrderStatus::PENDING_NEW)) + ")";
430 :
431 1 : sqlite3_stmt* stmt = nullptr;
432 1 : if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
433 0 : return orders;
434 : }
435 :
436 2 : while (sqlite3_step(stmt) == SQLITE_ROW) {
437 1 : orders.push_back(extractOrder(stmt));
438 : }
439 :
440 1 : sqlite3_finalize(stmt);
441 1 : return orders;
442 1 : }
443 :
444 0 : std::vector<Order> SqliteStore::loadAllOrders() {
445 0 : std::lock_guard<std::mutex> lock(mutex_);
446 0 : std::vector<Order> orders;
447 0 : if (!db_) return orders;
448 :
449 0 : const char* sql = R"(
450 : SELECT cl_ord_id, order_id, symbol, side, order_type, time_in_force,
451 : price, order_qty, cum_qty, leaves_qty, avg_px, status
452 : FROM orders ORDER BY create_time DESC
453 : )";
454 :
455 0 : sqlite3_stmt* stmt = nullptr;
456 0 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
457 0 : return orders;
458 : }
459 :
460 0 : while (sqlite3_step(stmt) == SQLITE_ROW) {
461 0 : orders.push_back(extractOrder(stmt));
462 : }
463 :
464 0 : sqlite3_finalize(stmt);
465 0 : return orders;
466 0 : }
467 :
468 : // =============================================================================
469 : // 成交存储
470 : // =============================================================================
471 :
472 2 : bool SqliteStore::saveTrade(const StoredTrade& trade) {
473 2 : std::lock_guard<std::mutex> lock(mutex_);
474 2 : if (!db_) return false;
475 :
476 2 : const char* sql = R"(
477 : INSERT INTO trades (trade_id, cl_ord_id, symbol, side, price, quantity,
478 : timestamp, counterparty_order_id)
479 : VALUES (?, ?, ?, ?, ?, ?, ?, ?)
480 : )";
481 :
482 2 : sqlite3_stmt* stmt = nullptr;
483 2 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
484 0 : return false;
485 : }
486 :
487 2 : sqlite3_bind_text(stmt, 1, trade.tradeId.c_str(), -1, SQLITE_TRANSIENT);
488 2 : sqlite3_bind_text(stmt, 2, trade.clOrdID.c_str(), -1, SQLITE_TRANSIENT);
489 2 : sqlite3_bind_text(stmt, 3, trade.symbol.c_str(), -1, SQLITE_TRANSIENT);
490 2 : sqlite3_bind_int(stmt, 4, static_cast<int>(trade.side));
491 2 : sqlite3_bind_double(stmt, 5, trade.price);
492 2 : sqlite3_bind_int64(stmt, 6, trade.quantity);
493 2 : sqlite3_bind_int64(stmt, 7, trade.timestamp);
494 2 : sqlite3_bind_text(stmt, 8, trade.counterpartyOrderId.c_str(), -1, SQLITE_TRANSIENT);
495 :
496 2 : int rc = sqlite3_step(stmt);
497 2 : sqlite3_finalize(stmt);
498 :
499 2 : return rc == SQLITE_DONE;
500 2 : }
501 :
502 2 : std::vector<StoredTrade> SqliteStore::loadTradesByOrder(const std::string& clOrdID) {
503 2 : std::lock_guard<std::mutex> lock(mutex_);
504 2 : std::vector<StoredTrade> trades;
505 2 : if (!db_) return trades;
506 :
507 2 : const char* sql = R"(
508 : SELECT trade_id, cl_ord_id, symbol, side, price, quantity,
509 : timestamp, counterparty_order_id
510 : FROM trades WHERE cl_ord_id = ? ORDER BY timestamp
511 : )";
512 :
513 2 : sqlite3_stmt* stmt = nullptr;
514 2 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
515 0 : return trades;
516 : }
517 :
518 2 : sqlite3_bind_text(stmt, 1, clOrdID.c_str(), -1, SQLITE_TRANSIENT);
519 :
520 4 : while (sqlite3_step(stmt) == SQLITE_ROW) {
521 2 : trades.push_back(extractTrade(stmt));
522 : }
523 :
524 2 : sqlite3_finalize(stmt);
525 2 : return trades;
526 2 : }
527 :
528 0 : std::vector<StoredTrade> SqliteStore::loadTradesBySymbol(const std::string& symbol) {
529 0 : std::lock_guard<std::mutex> lock(mutex_);
530 0 : std::vector<StoredTrade> trades;
531 0 : if (!db_) return trades;
532 :
533 0 : const char* sql = R"(
534 : SELECT trade_id, cl_ord_id, symbol, side, price, quantity,
535 : timestamp, counterparty_order_id
536 : FROM trades WHERE symbol = ? ORDER BY timestamp
537 : )";
538 :
539 0 : sqlite3_stmt* stmt = nullptr;
540 0 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
541 0 : return trades;
542 : }
543 :
544 0 : sqlite3_bind_text(stmt, 1, symbol.c_str(), -1, SQLITE_TRANSIENT);
545 :
546 0 : while (sqlite3_step(stmt) == SQLITE_ROW) {
547 0 : trades.push_back(extractTrade(stmt));
548 : }
549 :
550 0 : sqlite3_finalize(stmt);
551 0 : return trades;
552 0 : }
553 :
554 : // =============================================================================
555 : // 会话状态存储
556 : // =============================================================================
557 :
558 413 : bool SqliteStore::saveSessionState(const SessionState& state) {
559 413 : std::lock_guard<std::mutex> lock(mutex_);
560 413 : if (!db_) return false;
561 :
562 413 : const char* sql = R"(
563 : INSERT OR REPLACE INTO session_states
564 : (sender_comp_id, target_comp_id, send_seq_num, recv_seq_num, last_update_time)
565 : VALUES (?, ?, ?, ?, ?)
566 : )";
567 :
568 413 : sqlite3_stmt* stmt = nullptr;
569 413 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
570 0 : return false;
571 : }
572 :
573 413 : sqlite3_bind_text(stmt, 1, state.senderCompID.c_str(), -1, SQLITE_TRANSIENT);
574 413 : sqlite3_bind_text(stmt, 2, state.targetCompID.c_str(), -1, SQLITE_TRANSIENT);
575 413 : sqlite3_bind_int(stmt, 3, state.sendSeqNum);
576 413 : sqlite3_bind_int(stmt, 4, state.recvSeqNum);
577 413 : sqlite3_bind_int64(stmt, 5, state.lastUpdateTime);
578 :
579 413 : int rc = sqlite3_step(stmt);
580 413 : sqlite3_finalize(stmt);
581 :
582 413 : return rc == SQLITE_DONE;
583 413 : }
584 :
585 408 : std::optional<SessionState> SqliteStore::loadSessionState(
586 : const std::string& senderCompID, const std::string& targetCompID) {
587 408 : std::lock_guard<std::mutex> lock(mutex_);
588 408 : if (!db_) return std::nullopt;
589 :
590 408 : const char* sql = R"(
591 : SELECT sender_comp_id, target_comp_id, send_seq_num, recv_seq_num, last_update_time
592 : FROM session_states WHERE sender_comp_id = ? AND target_comp_id = ?
593 : )";
594 :
595 408 : sqlite3_stmt* stmt = nullptr;
596 408 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
597 0 : return std::nullopt;
598 : }
599 :
600 408 : sqlite3_bind_text(stmt, 1, senderCompID.c_str(), -1, SQLITE_TRANSIENT);
601 408 : sqlite3_bind_text(stmt, 2, targetCompID.c_str(), -1, SQLITE_TRANSIENT);
602 :
603 408 : if (sqlite3_step(stmt) == SQLITE_ROW) {
604 305 : SessionState state;
605 305 : const char* sender = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
606 305 : const char* target = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
607 305 : state.senderCompID = sender ? sender : "";
608 305 : state.targetCompID = target ? target : "";
609 305 : state.sendSeqNum = sqlite3_column_int(stmt, 2);
610 305 : state.recvSeqNum = sqlite3_column_int(stmt, 3);
611 305 : state.lastUpdateTime = sqlite3_column_int64(stmt, 4);
612 305 : sqlite3_finalize(stmt);
613 305 : return state;
614 305 : }
615 :
616 103 : sqlite3_finalize(stmt);
617 103 : return std::nullopt;
618 408 : }
619 :
620 : // =============================================================================
621 : // 消息存储
622 : // =============================================================================
623 :
624 1762 : bool SqliteStore::saveMessage(const StoredMessage& msg) {
625 1762 : std::lock_guard<std::mutex> lock(mutex_);
626 1762 : if (!db_) return false;
627 :
628 1762 : const char* sql = R"(
629 : INSERT INTO messages (seq_num, sender_comp_id, target_comp_id, msg_type, raw_message, timestamp)
630 : VALUES (?, ?, ?, ?, ?, ?)
631 : )";
632 :
633 1762 : sqlite3_stmt* stmt = nullptr;
634 1762 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
635 0 : return false;
636 : }
637 :
638 1762 : sqlite3_bind_int(stmt, 1, msg.seqNum);
639 1762 : sqlite3_bind_text(stmt, 2, msg.senderCompID.c_str(), -1, SQLITE_TRANSIENT);
640 1762 : sqlite3_bind_text(stmt, 3, msg.targetCompID.c_str(), -1, SQLITE_TRANSIENT);
641 1762 : sqlite3_bind_text(stmt, 4, msg.msgType.c_str(), -1, SQLITE_TRANSIENT);
642 1762 : sqlite3_bind_text(stmt, 5, msg.rawMessage.c_str(), -1, SQLITE_TRANSIENT);
643 1762 : sqlite3_bind_int64(stmt, 6, msg.timestamp);
644 :
645 1762 : int rc = sqlite3_step(stmt);
646 1762 : sqlite3_finalize(stmt);
647 :
648 1762 : return rc == SQLITE_DONE;
649 1762 : }
650 :
651 406 : std::vector<StoredMessage> SqliteStore::loadMessages(
652 : const std::string& senderCompID, const std::string& targetCompID,
653 : int beginSeqNum, int endSeqNum) {
654 406 : std::lock_guard<std::mutex> lock(mutex_);
655 406 : std::vector<StoredMessage> messages;
656 406 : if (!db_) return messages;
657 :
658 406 : const char* sql = R"(
659 : SELECT seq_num, sender_comp_id, target_comp_id, msg_type, raw_message, timestamp
660 : FROM messages
661 : WHERE sender_comp_id = ? AND target_comp_id = ? AND seq_num >= ? AND seq_num <= ?
662 : ORDER BY seq_num
663 : )";
664 :
665 406 : sqlite3_stmt* stmt = nullptr;
666 406 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
667 0 : return messages;
668 : }
669 :
670 406 : sqlite3_bind_text(stmt, 1, senderCompID.c_str(), -1, SQLITE_TRANSIENT);
671 406 : sqlite3_bind_text(stmt, 2, targetCompID.c_str(), -1, SQLITE_TRANSIENT);
672 406 : sqlite3_bind_int(stmt, 3, beginSeqNum);
673 406 : sqlite3_bind_int(stmt, 4, endSeqNum);
674 :
675 1440 : while (sqlite3_step(stmt) == SQLITE_ROW) {
676 1034 : StoredMessage msg;
677 1034 : msg.seqNum = sqlite3_column_int(stmt, 0);
678 1034 : const char* sender = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
679 1034 : const char* target = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
680 1034 : const char* msgType = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));
681 1034 : const char* rawMsg = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
682 1034 : msg.senderCompID = sender ? sender : "";
683 1034 : msg.targetCompID = target ? target : "";
684 1034 : msg.msgType = msgType ? msgType : "";
685 1034 : msg.rawMessage = rawMsg ? rawMsg : "";
686 1034 : msg.timestamp = sqlite3_column_int64(stmt, 5);
687 1034 : messages.push_back(msg);
688 1034 : }
689 :
690 406 : sqlite3_finalize(stmt);
691 406 : return messages;
692 406 : }
693 :
694 1 : bool SqliteStore::deleteMessagesOlderThan(int64_t timestamp) {
695 1 : std::lock_guard<std::mutex> lock(mutex_);
696 1 : if (!db_) return false;
697 :
698 1 : const char* sql = "DELETE FROM messages WHERE timestamp < ?";
699 :
700 1 : sqlite3_stmt* stmt = nullptr;
701 1 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
702 0 : return false;
703 : }
704 :
705 1 : sqlite3_bind_int64(stmt, 1, timestamp);
706 :
707 1 : int rc = sqlite3_step(stmt);
708 1 : sqlite3_finalize(stmt);
709 :
710 1 : return rc == SQLITE_DONE;
711 1 : }
712 :
713 1 : bool SqliteStore::deleteMessagesForSession(const std::string& senderCompID, const std::string& targetCompID) {
714 1 : std::lock_guard<std::mutex> lock(mutex_);
715 1 : if (!db_) return false;
716 :
717 1 : const char* sql = "DELETE FROM messages WHERE sender_comp_id = ? AND target_comp_id = ?";
718 :
719 1 : sqlite3_stmt* stmt = nullptr;
720 1 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
721 0 : return false;
722 : }
723 :
724 1 : sqlite3_bind_text(stmt, 1, senderCompID.c_str(), -1, SQLITE_TRANSIENT);
725 1 : sqlite3_bind_text(stmt, 2, targetCompID.c_str(), -1, SQLITE_TRANSIENT);
726 :
727 1 : int rc = sqlite3_step(stmt);
728 1 : sqlite3_finalize(stmt);
729 :
730 1 : return rc == SQLITE_DONE;
731 1 : }
732 :
733 : // =============================================================================
734 : // 辅助函数:提取 Account 和 Position
735 : // =============================================================================
736 :
737 209 : Account SqliteStore::extractAccount(sqlite3_stmt* stmt) {
738 209 : Account account;
739 209 : const char* accountId = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
740 209 : account.accountId = accountId ? accountId : "";
741 209 : account.balance = sqlite3_column_double(stmt, 1);
742 209 : account.available = sqlite3_column_double(stmt, 2);
743 209 : account.frozenMargin = sqlite3_column_double(stmt, 3);
744 209 : account.usedMargin = sqlite3_column_double(stmt, 4);
745 209 : account.positionProfit = sqlite3_column_double(stmt, 5);
746 209 : account.closeProfit = sqlite3_column_double(stmt, 6);
747 209 : int64_t updateTimeMs = sqlite3_column_int64(stmt, 7);
748 209 : account.updateTime = std::chrono::system_clock::time_point(
749 209 : std::chrono::milliseconds(updateTimeMs));
750 418 : return account;
751 0 : }
752 :
753 312 : Position SqliteStore::extractPosition(sqlite3_stmt* stmt) {
754 312 : Position position;
755 312 : const char* accountId = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
756 312 : const char* instrumentId = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
757 312 : position.accountId = accountId ? accountId : "";
758 312 : position.instrumentId = instrumentId ? instrumentId : "";
759 312 : position.longPosition = sqlite3_column_int64(stmt, 2);
760 312 : position.longAvgPrice = sqlite3_column_double(stmt, 3);
761 312 : position.longProfit = sqlite3_column_double(stmt, 4);
762 312 : position.longMargin = sqlite3_column_double(stmt, 5);
763 312 : position.shortPosition = sqlite3_column_int64(stmt, 6);
764 312 : position.shortAvgPrice = sqlite3_column_double(stmt, 7);
765 312 : position.shortProfit = sqlite3_column_double(stmt, 8);
766 312 : position.shortMargin = sqlite3_column_double(stmt, 9);
767 312 : int64_t updateTimeMs = sqlite3_column_int64(stmt, 10);
768 312 : position.updateTime = std::chrono::system_clock::time_point(
769 312 : std::chrono::milliseconds(updateTimeMs));
770 624 : return position;
771 0 : }
772 :
773 : // =============================================================================
774 : // 账户存储
775 : // =============================================================================
776 :
777 321 : bool SqliteStore::saveAccount(const Account& account) {
778 321 : std::lock_guard<std::mutex> lock(mutex_);
779 321 : if (!db_) return false;
780 :
781 321 : const char* sql = R"(
782 : INSERT OR REPLACE INTO accounts
783 : (account_id, balance, available, frozen_margin, used_margin,
784 : position_profit, close_profit, update_time)
785 : VALUES (?, ?, ?, ?, ?, ?, ?, ?)
786 : )";
787 :
788 321 : sqlite3_stmt* stmt = nullptr;
789 321 : int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
790 321 : if (rc != SQLITE_OK) {
791 0 : LOG() << "[SqliteStore] 准备账户保存语句失败: " << sqlite3_errmsg(db_);
792 0 : return false;
793 : }
794 :
795 321 : auto updateTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(
796 642 : account.updateTime.time_since_epoch()).count();
797 :
798 321 : sqlite3_bind_text(stmt, 1, account.accountId.c_str(), -1, SQLITE_TRANSIENT);
799 321 : sqlite3_bind_double(stmt, 2, account.balance);
800 321 : sqlite3_bind_double(stmt, 3, account.available);
801 321 : sqlite3_bind_double(stmt, 4, account.frozenMargin);
802 321 : sqlite3_bind_double(stmt, 5, account.usedMargin);
803 321 : sqlite3_bind_double(stmt, 6, account.positionProfit);
804 321 : sqlite3_bind_double(stmt, 7, account.closeProfit);
805 321 : sqlite3_bind_int64(stmt, 8, updateTimeMs);
806 :
807 321 : rc = sqlite3_step(stmt);
808 321 : sqlite3_finalize(stmt);
809 :
810 321 : if (rc != SQLITE_DONE) {
811 0 : LOG() << "[SqliteStore] 保存账户失败: " << sqlite3_errmsg(db_);
812 0 : return false;
813 : }
814 321 : return true;
815 321 : }
816 :
817 106 : std::optional<Account> SqliteStore::loadAccount(const std::string& accountId) {
818 106 : std::lock_guard<std::mutex> lock(mutex_);
819 106 : if (!db_) return std::nullopt;
820 :
821 106 : const char* sql = R"(
822 : SELECT account_id, balance, available, frozen_margin, used_margin,
823 : position_profit, close_profit, update_time
824 : FROM accounts WHERE account_id = ?
825 : )";
826 :
827 106 : sqlite3_stmt* stmt = nullptr;
828 106 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
829 0 : return std::nullopt;
830 : }
831 :
832 106 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
833 :
834 106 : if (sqlite3_step(stmt) == SQLITE_ROW) {
835 104 : Account account = extractAccount(stmt);
836 104 : sqlite3_finalize(stmt);
837 104 : return account;
838 104 : }
839 :
840 2 : sqlite3_finalize(stmt);
841 2 : return std::nullopt;
842 106 : }
843 :
844 109 : std::vector<Account> SqliteStore::loadAllAccounts() {
845 109 : std::lock_guard<std::mutex> lock(mutex_);
846 109 : std::vector<Account> accounts;
847 109 : if (!db_) return accounts;
848 :
849 109 : const char* sql = R"(
850 : SELECT account_id, balance, available, frozen_margin, used_margin,
851 : position_profit, close_profit, update_time
852 : FROM accounts ORDER BY account_id
853 : )";
854 :
855 109 : sqlite3_stmt* stmt = nullptr;
856 109 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
857 0 : return accounts;
858 : }
859 :
860 214 : while (sqlite3_step(stmt) == SQLITE_ROW) {
861 105 : accounts.push_back(extractAccount(stmt));
862 : }
863 :
864 109 : sqlite3_finalize(stmt);
865 109 : return accounts;
866 109 : }
867 :
868 1 : bool SqliteStore::deleteAccount(const std::string& accountId) {
869 1 : std::lock_guard<std::mutex> lock(mutex_);
870 1 : if (!db_) return false;
871 :
872 1 : const char* sql = "DELETE FROM accounts WHERE account_id = ?";
873 :
874 1 : sqlite3_stmt* stmt = nullptr;
875 1 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
876 0 : return false;
877 : }
878 :
879 1 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
880 :
881 1 : int rc = sqlite3_step(stmt);
882 1 : sqlite3_finalize(stmt);
883 :
884 1 : return rc == SQLITE_DONE;
885 1 : }
886 :
887 : // =============================================================================
888 : // 持仓存储
889 : // =============================================================================
890 :
891 417 : bool SqliteStore::savePosition(const Position& position) {
892 417 : std::lock_guard<std::mutex> lock(mutex_);
893 417 : if (!db_) return false;
894 :
895 417 : const char* sql = R"(
896 : INSERT OR REPLACE INTO positions
897 : (account_id, instrument_id, long_position, long_avg_price, long_profit, long_margin,
898 : short_position, short_avg_price, short_profit, short_margin, update_time)
899 : VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
900 : )";
901 :
902 417 : sqlite3_stmt* stmt = nullptr;
903 417 : int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
904 417 : if (rc != SQLITE_OK) {
905 0 : LOG() << "[SqliteStore] 准备持仓保存语句失败: " << sqlite3_errmsg(db_);
906 0 : return false;
907 : }
908 :
909 417 : auto updateTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(
910 834 : position.updateTime.time_since_epoch()).count();
911 :
912 417 : sqlite3_bind_text(stmt, 1, position.accountId.c_str(), -1, SQLITE_TRANSIENT);
913 417 : sqlite3_bind_text(stmt, 2, position.instrumentId.c_str(), -1, SQLITE_TRANSIENT);
914 417 : sqlite3_bind_int64(stmt, 3, position.longPosition);
915 417 : sqlite3_bind_double(stmt, 4, position.longAvgPrice);
916 417 : sqlite3_bind_double(stmt, 5, position.longProfit);
917 417 : sqlite3_bind_double(stmt, 6, position.longMargin);
918 417 : sqlite3_bind_int64(stmt, 7, position.shortPosition);
919 417 : sqlite3_bind_double(stmt, 8, position.shortAvgPrice);
920 417 : sqlite3_bind_double(stmt, 9, position.shortProfit);
921 417 : sqlite3_bind_double(stmt, 10, position.shortMargin);
922 417 : sqlite3_bind_int64(stmt, 11, updateTimeMs);
923 :
924 417 : rc = sqlite3_step(stmt);
925 417 : sqlite3_finalize(stmt);
926 :
927 417 : if (rc != SQLITE_DONE) {
928 0 : LOG() << "[SqliteStore] 保存持仓失败: " << sqlite3_errmsg(db_);
929 0 : return false;
930 : }
931 417 : return true;
932 417 : }
933 :
934 307 : std::optional<Position> SqliteStore::loadPosition(
935 : const std::string& accountId, const std::string& instrumentId) {
936 307 : std::lock_guard<std::mutex> lock(mutex_);
937 307 : if (!db_) return std::nullopt;
938 :
939 307 : const char* sql = R"(
940 : SELECT account_id, instrument_id, long_position, long_avg_price, long_profit, long_margin,
941 : short_position, short_avg_price, short_profit, short_margin, update_time
942 : FROM positions WHERE account_id = ? AND instrument_id = ?
943 : )";
944 :
945 307 : sqlite3_stmt* stmt = nullptr;
946 307 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
947 0 : return std::nullopt;
948 : }
949 :
950 307 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
951 307 : sqlite3_bind_text(stmt, 2, instrumentId.c_str(), -1, SQLITE_TRANSIENT);
952 :
953 307 : if (sqlite3_step(stmt) == SQLITE_ROW) {
954 205 : Position position = extractPosition(stmt);
955 205 : sqlite3_finalize(stmt);
956 205 : return position;
957 205 : }
958 :
959 102 : sqlite3_finalize(stmt);
960 102 : return std::nullopt;
961 307 : }
962 :
963 2 : std::vector<Position> SqliteStore::loadPositionsByAccount(const std::string& accountId) {
964 2 : std::lock_guard<std::mutex> lock(mutex_);
965 2 : std::vector<Position> positions;
966 2 : if (!db_) return positions;
967 :
968 2 : const char* sql = R"(
969 : SELECT account_id, instrument_id, long_position, long_avg_price, long_profit, long_margin,
970 : short_position, short_avg_price, short_profit, short_margin, update_time
971 : FROM positions WHERE account_id = ? ORDER BY instrument_id
972 : )";
973 :
974 2 : sqlite3_stmt* stmt = nullptr;
975 2 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
976 0 : return positions;
977 : }
978 :
979 2 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
980 :
981 4 : while (sqlite3_step(stmt) == SQLITE_ROW) {
982 2 : positions.push_back(extractPosition(stmt));
983 : }
984 :
985 2 : sqlite3_finalize(stmt);
986 2 : return positions;
987 2 : }
988 :
989 109 : std::vector<Position> SqliteStore::loadAllPositions() {
990 109 : std::lock_guard<std::mutex> lock(mutex_);
991 109 : std::vector<Position> positions;
992 109 : if (!db_) return positions;
993 :
994 109 : const char* sql = R"(
995 : SELECT account_id, instrument_id, long_position, long_avg_price, long_profit, long_margin,
996 : short_position, short_avg_price, short_profit, short_margin, update_time
997 : FROM positions ORDER BY account_id, instrument_id
998 : )";
999 :
1000 109 : sqlite3_stmt* stmt = nullptr;
1001 109 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1002 0 : return positions;
1003 : }
1004 :
1005 214 : while (sqlite3_step(stmt) == SQLITE_ROW) {
1006 105 : positions.push_back(extractPosition(stmt));
1007 : }
1008 :
1009 109 : sqlite3_finalize(stmt);
1010 109 : return positions;
1011 109 : }
1012 :
1013 101 : bool SqliteStore::deletePosition(const std::string& accountId, const std::string& instrumentId) {
1014 101 : std::lock_guard<std::mutex> lock(mutex_);
1015 101 : if (!db_) return false;
1016 :
1017 101 : const char* sql = "DELETE FROM positions WHERE account_id = ? AND instrument_id = ?";
1018 :
1019 101 : sqlite3_stmt* stmt = nullptr;
1020 101 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1021 0 : return false;
1022 : }
1023 :
1024 101 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
1025 101 : sqlite3_bind_text(stmt, 2, instrumentId.c_str(), -1, SQLITE_TRANSIENT);
1026 :
1027 101 : int rc = sqlite3_step(stmt);
1028 101 : sqlite3_finalize(stmt);
1029 :
1030 101 : return rc == SQLITE_DONE;
1031 101 : }
1032 :
1033 1 : bool SqliteStore::deletePositionsByAccount(const std::string& accountId) {
1034 1 : std::lock_guard<std::mutex> lock(mutex_);
1035 1 : if (!db_) return false;
1036 :
1037 1 : const char* sql = "DELETE FROM positions WHERE account_id = ?";
1038 :
1039 1 : sqlite3_stmt* stmt = nullptr;
1040 1 : if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1041 0 : return false;
1042 : }
1043 :
1044 1 : sqlite3_bind_text(stmt, 1, accountId.c_str(), -1, SQLITE_TRANSIENT);
1045 :
1046 1 : int rc = sqlite3_step(stmt);
1047 1 : sqlite3_finalize(stmt);
1048 :
1049 1 : return rc == SQLITE_DONE;
1050 1 : }
1051 :
1052 : } // namespace fix40
|