以下是针对 存储10档买卖盘行情数据 的完整实现方案,包含 SQLite内存数据库表结构设计、回调函数数据处理 和 高性能存储优化:
一、SQLite表结构设计(存储10档数据)
// 创建包含10档买卖盘的表结构
const char* create_table_sql =
"CREATE TABLE IF NOT EXISTS market_data ("
"timestamp INTEGER, " // 时间戳
"ticker TEXT, " // 股票代码
"last_price REAL, " // 最新价
// 买盘10档
"bid_price1 REAL, bid_qty1 INTEGER, "
"bid_price2 REAL, bid_qty2 INTEGER, "
"bid_price3 REAL, bid_qty3 INTEGER, "
"bid_price4 REAL, bid_qty4 INTEGER, "
"bid_price5 REAL, bid_qty5 INTEGER, "
"bid_price6 REAL, bid_qty6 INTEGER, "
"bid_price7 REAL, bid_qty7 INTEGER, "
"bid_price8 REAL, bid_qty8 INTEGER, "
"bid_price9 REAL, bid_qty9 INTEGER, "
"bid_price10 REAL, bid_qty10 INTEGER, "
// 卖盘10档
"ask_price1 REAL, ask_qty1 INTEGER, "
"ask_price2 REAL, ask_qty2 INTEGER, "
"ask_price3 REAL, ask_qty3 INTEGER, "
"ask_price4 REAL, ask_qty4 INTEGER, "
"ask_price5 REAL, ask_qty5 INTEGER, "
"ask_price6 REAL, ask_qty6 INTEGER, "
"ask_price7 REAL, ask_qty7 INTEGER, "
"ask_price8 REAL, ask_qty8 INTEGER, "
"ask_price9 REAL, ask_qty9 INTEGER, "
"ask_price10 REAL, ask_qty10 INTEGER"
");";
二、回调函数处理10档数据
1. 修改后的回调函数实现
void OnDepthMarketData(
XTPMD *market_data,
int64_t bid1_qty[], // 参数根据实际情况调整(若需要)
int32_t bid1_count,
int32_t max_bid1_count,
int64_t ask1_qty[],
int32_t ask1_count,
int32_t max_ask1_count
) override {
// 生成SQL插入语句(包含10档买卖盘字段)
const char* insert_sql =
"INSERT INTO market_data VALUES ("
"?, ?, ?, " // timestamp, ticker, last_price
"?,?, ?,?, ?,?, ?,?, ?,?, ?,?, " // bid_price1~10 + bid_qty1~10
"?,?, ?,?, ?,?, ?,?, ?,?, ?,?" // ask_price1~10 + ask_qty1~10
");";
sqlite3_stmt* stmt;
if (sqlite3_prepare_v2(db, insert_sql, -1, &stmt, 0) != SQLITE_OK) {
std::cerr << "SQL编译错误: " << sqlite3_errmsg(db) << std::endl;
return;
}
// 绑定基础字段
sqlite3_bind_int64(stmt, 1, market_data->data_time);
sqlite3_bind_text(stmt, 2, market_data->ticker, -1, SQLITE_STATIC);
sqlite3_bind_double(stmt, 3, market_data->last_price);
// 绑定买盘10档数据
for (int i = 0; i < 10; ++i) {
sqlite3_bind_double(stmt, 4 + 2*i, market_data->bid[i].price); // bid_price1~10
sqlite3_bind_int64(stmt, 5 + 2*i, market_data->bid[i].qty); // bid_qty1~10
}
// 绑定卖盘10档数据
for (int i = 0; i < 10; ++i) {
sqlite3_bind_double(stmt, 24 + 2*i, market_data->ask[i].price); // ask_price1~10
sqlite3_bind_int64(stmt, 25 + 2*i, market_data->ask[i].qty); // ask_qty1~10
}
// 执行插入
if (sqlite3_step(stmt) != SQLITE_DONE) {
std::cerr << "插入失败: " << sqlite3_errmsg(db) << std::endl;
}
sqlite3_finalize(stmt);
}
三、性能优化策略
1. 批量事务提交
// 在开始接收数据前开启事务
sqlite3_exec(db, "BEGIN TRANSACTION;", 0, 0, 0);
// 在数据接收完成后提交事务
sqlite3_exec(db, "COMMIT;", 0, 0, 0);
2. SQLite配置优化
// 禁用磁盘同步(内存数据库无需持久化)
sqlite3_exec(db, "PRAGMA synchronous = OFF;", 0, 0, 0);
// 启用内存映射
sqlite3_exec(db, "PRAGMA mmap_size = 268435456;", 0, 0, 0);
3. 数据压缩存储(可选)
若磁盘空间有限,可将数据序列化为二进制格式:
// 使用Protocol Buffers定义数据结构
message MarketData {
int64 timestamp = 1;
string ticker = 2;
double last_price = 3;
repeated double bid_prices = 4; // 10 elements
repeated int64 bid_qtys = 5; // 10 elements
repeated double ask_prices = 6; // 10 elements
repeated int64 ask_qtys = 7; // 10 elements
}
// 存储为BLOB字段
sqlite3_bind_blob(stmt, 1, serialized_data.data(), serialized_data.size(), SQLITE_STATIC);
四、数据查询示例
1. 查询买五档数据
const char* query_sql =
"SELECT timestamp, ticker, bid_price5, bid_qty5 "
"FROM market_data "
"WHERE ticker = '600519.SH';";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, query_sql, -1, &stmt, 0);
while (sqlite3_step(stmt) == SQLITE_ROW) {
int64_t timestamp = sqlite3_column_int64(stmt, 0);
const char* ticker = (const char*)sqlite3_column_text(stmt, 1);
double bid_price5 = sqlite3_column_double(stmt, 2);
int64_t bid_qty5 = sqlite3_column_int64(stmt, 3);
std::cout << "时间: " << timestamp
<< " 代码: " << ticker
<< " 买五价: " << bid_price5
<< " 买五量: " << bid_qty5 << std::endl;
}
2. 统计卖一档总量
const char* agg_sql =
"SELECT SUM(ask_qty1) FROM market_data "
"WHERE timestamp BETWEEN 1620000000 AND 1620086400;";
// 执行并获取结果...
五、注意事项
-
数据结构验证
确保XTPMD
结构体中bid
和ask
数组长度至少为10:static_assert(sizeof(market_data->bid) >= 10 * sizeof(XTPOB), "bid数组长度不足10档");
-
空值处理
若某档无数据,存储为NULL
更规范:if (market_data->bid[i].price <= 0) { sqlite3_bind_null(stmt, 4 + 2*i); } else { sqlite3_bind_double(stmt, 4 + 2*i, market_data->bid[i].price); }
-
高频场景优化
-
使用 连接池 管理多个数据库连接
-
采用 环形缓冲区 分离数据接收与存储线程
-
六、完整代码整合
// 1. 初始化数据库
sqlite3* db;
sqlite3_open(":memory:", &db);
sqlite3_exec(db, create_table_sql, 0, 0, 0);
sqlite3_exec(db, "PRAGMA synchronous=OFF;", 0, 0, 0);
// 2. 初始化XTP API
XTP::API::QuoteAPI* api = XTP::API::QuoteAPI::CreateQuoteApi("client_id", "./log");
MyQuoteSpi spi;
api->RegisterSpi(&spi);
api->Login("127.0.0.1", 6001, "user", "pass", XTP_PROTOCOL_TCP);
// 3. 订阅全市场数据
api->SubscribeAllMarketData(XTP_EXCHANGE_SH);
// 4. 主循环(示例)
std::thread storage_thread([](){
while (running) {
std::this_thread::sleep_for(std::chrono::seconds(1));
sqlite3_exec(db, "BEGIN; COMMIT;", 0, 0, 0); // 定时提交事务
}
});
// 5. 退出时持久化数据
sqlite3* disk_db;
sqlite3_open("historical_data.db", &disk_db);
sqlite3_backup* backup = sqlite3_backup_init(disk_db, "main", db, "main");
sqlite3_backup_step(backup, -1);
sqlite3_backup_finish(backup);
sqlite3_close(disk_db);