LCOV - code coverage report
Current view: top level - src/storage - sqlite_store.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.7 % 588 504
Test Date: 2025-12-19 03:13:09 Functions: 91.9 % 37 34

            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
        

Generated by: LCOV version 2.0-1