小 T 导读:如果我们要做行情 tick 数据的存储,怎样的数据结构查找起来才会比较快?在加入 TDengine 之前,本文作者丁博在弘源泰平量化投资做量化工程师,曾经遇到过这一类存储行情 tick 数据的问题,本文会就此问题进行详细的技术解读。
01
内存存储方案
1
两级 map 方案
#include "ThostFtdcUserApiStruct.h"#include "ThostFtdcUserApiDataType.h"#include <map>#include <unordered_map>using namespace std;int main(){unordered_map<TThostFtdcInstrumentIDType, map<long, CThostFtdcDepthMarketDataField>*> tickData;}
2
map + array
交易策略通常会依赖标准化的行情计算交易信号,收行情和标准化并作一步会更节省时间。 可以直接用数组下标索引对应时间的行情,查找的时间复杂度为 O(1)。
#include "ThostFtdcUserApiStruct.h"#include "ThostFtdcUserApiDataType.h"#include <unordered_map>#include <array>using namespace std;int main(){unordered_map<TThostFtdcInstrumentIDType, array<CThostFtdcDepthMarketDataField, 28800>> tickData;}
02
持久化存储方案
1
下载 TDengine Database Server
2
安装并启动
sudo dpkg -i TDengine-server-2.4.0.7-Linux-x64.deb
sudo rpm -ivh TDengine-server-2.4.0.7-Linux-x64.rpm
3
建行情表
进入 taos 命令行
bo@RDBB:~$ taosWelcome to the TDengine shell from Linux, Client Version:2.4.0.12Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.
执行下面的语句
create database marketdata;use marketdata;create stable tick( ts timestamp, updatetime binary(9), updatemillisec int, askprice1 double, bidprice1 double, askvolume1 int, bidvolume1 int) tags (exchangeid binary(9));
查看表结构
taos> desc tick;Field | Type | Length | Note |=================================================================================ts | TIMESTAMP | 8 | |updatetime | BINARY | 9 | |updatemillisec | INT | 4 | |askprice1 | DOUBLE | 8 | |bidprice1 | DOUBLE | 8 | |askvolume1 | INT | 4 | |bidvolume1 | INT | 4 | |exchangeid | BINARY | 9 | TAG |Query OK, 8 row(s) in set (0.000378s)
4
写入行情
#include "ThostFtdcUserApiStruct.h"#include "ThostFtdcUserApiDataType.h"#include "taos.h"#include "taoserror.h"#include <iostream>#include <sstream>using namespace std;void insertTickData(TAOS* taos, CThostFtdcDepthMarketDataField &tick) {stringstream sql;// 会自动创建子表tick.InstrumentIDsql << "insert into " << tick.InstrumentID << " using tick tags("<< tick.ExchangeID << ") values(now, '" << tick.UpdateTime << "', "<< tick.UpdateMillisec << "," << tick.AskPrice1 << "," << tick.BidPrice1<< "," << tick.AskVolume1 << "," << tick.BidVolume1 << ")";TAOS_RES *res = taos_query(taos, sql.str().c_str());if (res == nullptr || taos_errno(res) != 0) {cerr << "insertTitckData failed," << taos_errno(res) << ", " << taos_errstr(res) << endl;}}int main(){TAOS *taos = taos_connect("localhost", "root", "taosdata", "marketdata", 6030);// 构造测试数据CThostFtdcDepthMarketDataField tick;strcpy_s(tick.InstrumentID, "IH2209");strcpy_s(tick.UpdateTime, "14:10:32");strcpy_s(tick.ExchangeID, "DEC");tick.UpdateMillisec = 500;tick.AskPrice1 = 123.8;tick.BidPrice1 = 123.4;tick.AskVolume1 = 10;tick.BidVolume1 = 9;// 写入测试数据insertTickData(taos, tick);taos_close(taos);}

5
查询最新的行情
#include "ThostFtdcUserApiStruct.h"#include "ThostFtdcUserApiDataType.h"#include "taos.h"#include "taoserror.h"#include <string>#include <iostream>using namespace std;CThostFtdcDepthMarketDataField* getLastTick(TAOS* taos, const char* instrumentID) {string sql("select last(*) from ");sql += instrumentID;TAOS_RES* res = taos_query(taos, sql.c_str());if (res == nullptr || taos_errno(res) != 0) {cerr << "getLastTick failed," << taos_errno(res) << ", " << taos_errstr(res) << endl;return nullptr;}TAOS_ROW row = taos_fetch_row(res);if (row == nullptr) {return nullptr;}CThostFtdcDepthMarketDataField* tick = new CThostFtdcDepthMarketDataField();//int64_t ts = *((int64_t*)row[0]);memcpy(tick->UpdateTime, row[1], 9);tick->UpdateMillisec = *(int*)row[2];tick->AskPrice1 = *((double *)row[3]);tick->BidPrice1 = *((double*)row[4]);taos_free_result(res);return tick;}int main() {TAOS* taos = taos_connect("localhost", "root", "taosdata", "marketdata", 6030);CThostFtdcDepthMarketDataField* tick = getLastTick(taos, "IH2209");cout << "askPrice1=" << tick->AskPrice1 << " bidPrice1=" << tick->BidPrice1 << endl;delete tick;taos_close(taos);}

03
从实际业务出发的实践经验分享
依赖多,稳定性较差:PMS作为多品种的投后分析服务, 需要使用到各种日线数据、当天实时行情数据、当天分钟数据等,在数据获取方面需要依赖Http以及Postgres、LevelDB等数据库。过于多的数据获取链路会导致平台可靠性降低,同时依赖于其他各个服务,导致查询问题过于复杂。
性能不能满足需求:PMS作为多品种投后分析,在算法分析层面需要大量的行情获取,而且对行情获取的性能也有较大的要求,当前所有行情会占据大量分析的性能。

文章转载自TDengine,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




