1. 概述

对数据库进行合理的分区能够明显下降体系呼应推迟,进步数据吞吐量。合理的分区规划需要归纳考虑数据分布的特征、查询和核算的典型场景、数据更新的频率等方方面面。

本文为入门级教程,针对几种常见的金融数据给出了较为通用的分区计划和示例脚本,以帮助初度体验 DolphinDB 的用户快速完成建库建表。

本文扩展阅读:

2. 数据存储计划总览

存储计划包括金融数据存储计划和因子库存储计划两大部分。

2.1 金融数据存储计划

针对不同金融数据,给出以下的分区存储计划:

下降推迟、进步吞吐…一文详解金融数据分区存储最佳实践

下降推迟、进步吞吐…一文详解金融数据分区存储最佳实践

2.2 因子库窄表存储计划

因子发掘是量化买卖的必备环节之一。随着量化买卖和AI模型训练规划的发展,量化出资团队在投研环节必然需要处理很多因子数据。因子的存储也是一个关键问题,本文推荐运用窄表存储因子库。

下降推迟、进步吞吐…一文详解金融数据分区存储最佳实践

(窄表存储模型)

下降推迟、进步吞吐…一文详解金融数据分区存储最佳实践

(宽表存储模型)

相较于宽表,窄表存储有以下优势:

  • 愈加高效地删去过期失效因子

    • 宽表的计划是删去全表的某一列,相比窄表计划功率低下
  • 愈加高效地增加新因子

    • 宽表的计划是先增加列,然后更新新增列的值,相比窄表计划功率低下
  • 愈加高效地依照因子名更新指定因子的值

    • 宽表的计划是 update 全表的某一列,相比窄表功率低下
  • 单次多因子面板数据的查询功率和宽表近似

    • DolphinDB 经过对 pivot by 办法的并行优化,确保了窄表存储计划的多因子数据查询功率

针对不同频率的因子数据,给出以下的分区存储计划,均选用 TSDB 存储引擎

下降推迟、进步吞吐…一文详解金融数据分区存储最佳实践

3. 金融数据存储计划实践

依据上一章的分区计划,本章将供给对应的 DolphinDB 脚本。

3.1 股票数据

3.1.1 Levle-2 行情数据

股票 Levle-2 行情数据包括 Levle-2 快照数据、逐笔托付数据、逐笔成交数据,由于在分布式数据库中,如果多个分区的数据表要连接(join)通常非常耗时,由于涉及到的分区可能在不同的节点上,需要在不同节点之间仿制数据。为处理这个问题,DolphinDB 推出了共存储方位的分区机制,确保同一个分布式数据库里一切表在相同分区的数据存储在相同的节点上。这样的安排,确保了这些表在连接的时候非常高效。因而在本计划中,把 Levle-2 快照数据、逐笔托付数据、逐笔成交数据这些分区计划共同的数据表存入同一个数据库中。

上交所和深交所两个买卖所的数据在字段结构上略有不同,用户在树立库表时能够考虑是否将两个买卖所的数据进行兼并,如果选择存为一张表,则表中的字段是两个买卖所数据字段的并集,并新增字段 Market 用于标识数据来自哪个买卖所。level-1 的分区计划选用 level-2 的即可。

如果您希望将通联数据导入 DolphinDB 数据库,能够参考如下教程,运用封装好的模块即可完成建库建表和 level-2 行情数据导入:

下面将依据是否将沪深买卖所分隔存储介绍不同建库建表的分区规矩。

3.1.1.1 Levle-2快照(沪深分表)

深交所

create database "dfs://split_SZ_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 25])
engine='TSDB'
create table "dfs://split_SZ_TB"."split_SZ_snapshotTB"(
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    MDStreamID SYMBOL
    SecurityID SYMBOL
    SecurityIDSource SYMBOL
    TradingPhaseCode SYMBOL
    PreCloPrice DOUBLE
    NumTrades LONG
    TotalVolumeTrade LONG
    TotalValueTrade DOUBLE
    LastPrice DOUBLE
    OpenPrice DOUBLE
    HighPrice DOUBLE
    LowPrice DOUBLE
    DifPrice1 DOUBLE
    DifPrice2 DOUBLE
    PE1 DOUBLE
    PE2 DOUBLE
    PreCloseIOPV DOUBLE
    IOPV DOUBLE
    TotalBidQty LONG
    WeightedAvgBidPx DOUBLE
    TotalOfferQty LONG
    WeightedAvgOfferPx DOUBLE
    UpLimitPx DOUBLE
    DownLimitPx DOUBLE
    OpenInt INT
    OptPremiumRatio DOUBLE
    OfferPrice DOUBLE[]
    BidPrice DOUBLE[]
    OfferOrderQty LONG[]
    BidOrderQty LONG[]
    BidNumOrders INT[]
    OfferNumOrders INT[]
    LocalTime TIME
    SeqNo INT
    OfferOrders LONG[]
    BidOrders LONG[]
)
partitioned by TradeTime, SecurityID,
sortColumns=[`SecurityID,`TradeTime],
keepDuplicates=ALL

Levle-2行情数据运用”时刻维度按天 股票维度 HASH25”的分区规矩,运用存储引擎TSDB,运用“股票代码 买卖时刻”作为排序列。下面对上述脚本进行说明:

  • TSDB 引擎只支撑创立分布式数据库,库名前必须增加”dfs://”;
  • 在此处树立分区表时对某些列运用了指定紧缩算法,对TradeTime列运用了“delta”紧缩算法,其他列则默许运用“lz4”紧缩算法;
  • 建表时指定 OfferPrice 为 DOUBLE[] 类型, 表明将 10 档卖价数据存储在一个字段中,该字段类型为 DOUBLE 类型的数组向量(arrray vector),更详细的 array vector 介绍见:DolphinDB 中有关 array vector 的最佳实践指南
  • sortColumns 参数用于将写入的数据依照指定字段进行排序,体系默许 sortColumns (指定多列时) 最终一列为时刻列,其他列字段作为排序的索引列,称作 sort key。频繁查询的字段适合设置为 sortColumns,且主张优先把查询频率高的字段作为 sortColumns 中方位靠前的列;
  • keepDuplicates 参数表明在每个分区内怎么处理一切 sortColumns 之值皆相同的数据,在两个函数中该参数的值均为“ALL”表明保留一切数据。

上交所

create database "dfs://split_SH_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 25])
engine='TSDB'
create table "dfs://split_SH_TB"."split_SH_snapshotTB"(
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    SecurityID SYMBOL
    ImageStatus INT
    PreCloPrice DOUBLE
    OpenPrice DOUBLE
    HighPrice DOUBLE
    LowPrice DOUBLE
    LastPrice DOUBLE
    ClosePrice DOUBLE
    TradingPhaseCode SYMBOL
    NumTrades LONG
    TotalVolumeTrade LONG
    TotalValueTrade DOUBLE
    TotalBidQty LONG
    WeightedAvgBidPx DOUBLE
    AltWAvgBidPri DOUBLE
    TotalOfferQty LONG
    WeightedAvgOfferPx DOUBLE
    AltWAvgAskPri DOUBLE
    ETFBuyNumber INT
    ETFBuyAmount LONG
    ETFBuyMoney DOUBLE
    ETFSellNumber INT
    ETFSellAmount LONG
    ETFSellMoney DOUBLE
    YieldToMatu DOUBLE
    TotWarExNum DOUBLE
    UpLimitPx DOUBLE
    DownLimitPx DOUBLE
    WithdrawBuyNumber INT
    WithdrawBuyAmount LONG
    WithdrawBuyMoney DOUBLE
    WithdrawSellNumber INT
    WithdrawSellAmount LONG
    WithdrawSellMoney DOUBLE
    TotalBidNumber INT
    TotalOfferNumber INT
    MaxBidDur INT
    MaxSellDur INT
    BidNum INT
    SellNum INT
    IOPV DOUBLE
    OfferPrice DOUBLE[]
    BidPrice DOUBLE[]
    OfferOrderQty LONG[]
    BidOrderQty LONG[]
    BidNumOrders INT[]
    OfferNumOrders INT[]
    LocalTime TIME
    SeqNo INT
    OfferOrders LONG[]
    BidOrders LONG[]
)
partitioned by TradeTime, SecurityID,
sortColumns=[`SecurityID,`TradeTime],
keepDuplicates=ALL

上交所的数据格式与深交所略有不同,但分区计划共同。

3.1.1.2 逐笔托付(沪深分表)

深交所

create database "dfs://split_SZ_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 25])
engine='TSDB'
create table "dfs://split_SZ_TB"."split_SZ_entrustTB"(
    ChannelNo INT
    ApplSeqNum LONG
    MDStreamID SYMBOL
    SecurityID SYMBOL
    SecurityIDSource SYMBOL
    Price DOUBLE
    OrderQty LONG
    Side SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    OrderType SYMBOL
    LocalTime TIME
    SeqNo INT
)
partitioned by TradeTime, SecurityID,
sortColumns=[`SecurityID,`TradeTime],
keepDuplicates=ALL

用户能够运用上述代码以创立存储深交所逐笔托付数据的数据库表,分区规矩选用了“时刻维度按日 股票代码HASH25”的组合分区方法存储,运用存储引擎TSDB, 运用 “股票代码 买卖时刻” 作为排序列。

上交所

create database "dfs://split_SH_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 25])
engine='TSDB'
create table "dfs://split_SH_TB"."split_SH_entrustTB"(
    DataStatus INT
    ApplSeqNum LONG
    ChannelNo INT
    SecurityID SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    OrderType SYMBOL
    OrderNO INT
    Price DOUBLE
    OrderQty LONG
    Side SYMBOL
    BizIndex INT
    LocalTime TIME
    SeqNo INT
)
partitioned by TradeTime, SecurityID,
sortColumns=[`SecurityID,`TradeTime],
keepDuplicates=ALL

上交所的数据格式与深交所略有不同,但分区计划共同。

3.1.1.3 逐笔成交(沪深分表)

深交所

create database "dfs://split_SZ_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 25])
engine='TSDB'
create table "dfs://split_SZ_TB"."split_SZ_tradeTB"(
    ChannelNo INT
    ApplSeqNum LONG
    MDStreamID SYMBOL
    BidApplSeqNum LONG
    OfferApplSeqNum LONG
    SecurityID SYMBOL
    SecurityIDSource SYMBOL
    TradePrice DOUBLE
    TradeQty INT
    ExecType SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    LocalTime TIME
    SeqNo INT
    OrderKind SYMBOL
)
partitioned by TradeTime, SecurityID,
sortColumns=[`SecurityID,`TradeTime],
keepDuplicates=ALL

用户能够运用上述代码以创立存储深交所逐笔托付数据的数据库表,分区规矩选用了“时刻维度按日 股票代码HASH25”的组合分区方法存储,运用存储引擎TSDB,运用“股票代码 买卖时刻”作为排序列。

上交所

create database "dfs://split_SH_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 25])
engine='TSDB'
create table "dfs://split_SH_TB"."split_SH_tradeTB"(
    DataStatus INT
    ApplSeqNum INT
    ChannelNo INT
    SecurityID SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    TradePrice DOUBLE
    TradeQty LONG
    TradeMoney DOUBLE
    BidApplSeqNum LONG
    OfferApplSeqNum LONG
    TradeBSFlag SYMBOL
    BizIndex LONG
    LocalTime TIME
    SeqNo INT
)
partitioned by TradeTime, SecurityID,
sortColumns=[`SecurityID,`TradeTime],
keepDuplicates=ALL

上交所的数据格式与深交所略有不同,但分区计划共同。

3.1.1.4 Levle-2快照(沪深兼并)

create database "dfs://merge_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 50])
engine='TSDB'
create table "dfs://merge_TB"."merge_snapshotTB"(
	Market SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"],
    MDStreamID SYMBOL
    SecurityID SYMBOL
    SecurityIDSource SYMBOL
    TradingPhaseCode SYMBOL
    ImageStatus INT
    PreCloPrice DOUBLE
    NumTrades LONG
    TotalVolumeTrade LONG
    TotalValueTrade DOUBLE
    LastPrice DOUBLE
    OpenPrice DOUBLE
    HighPrice DOUBLE
    LowPrice DOUBLE
    ClosePrice DOUBLE
    DifPrice1 DOUBLE
    DifPrice2 DOUBLE
    PE1 DOUBLE
    PE2 DOUBLE
    PreCloseIOPV DOUBLE
    IOPV DOUBLE
    TotalBidQty LONG
    WeightedAvgBidPx DOUBLE
    AltWAvgBidPri DOUBLE
    TotalOfferQty LONG
    WeightedAvgOfferPx DOUBLE
    AltWAvgAskPri DOUBLE
    UpLimitPx DOUBLE
    DownLimitPx DOUBLE
    OpenInt INT
    OptPremiumRatio DOUBLE
    OfferPrice DOUBLE[]
    BidPrice DOUBLE[]
    OfferOrderQty LONG[]
    BidOrderQty LONG[]
    BidNumOrders INT[]
    OfferNumOrders INT[]
    ETFBuyNumber INT
    ETFBuyAmount LONG
    ETFBuyMoney DOUBLE
    ETFSellNumber INT
    ETFSellAmount LONG
    ETFSellMoney DOUBLE
    YieldToMatu DOUBLE
    TotWarExNum DOUBLE
    WithdrawBuyNumber INT
    WithdrawBuyAmount LONG
    WithdrawBuyMoney DOUBLE
    WithdrawSellNumber INT
    WithdrawSellAmount LONG
    WithdrawSellMoney DOUBLE
    TotalBidNumber INT
    TotalOfferNumber INT
    MaxBidDur INT
    MaxSellDur INT
    BidNum INT
    SellNum INT
    LocalTime TIME
    SeqNo INT
    OfferOrders LONG[]
    BidOrders LONG[]
)
partitioned by TradeTime, SecurityID,
sortColumns=[`Market,`SecurityID,`TradeTime],
keepDuplicates=ALL

用户能够运用上述代码树立一起存储沪深Levle-2行情数据的数据库表,运用”时刻维度按天 股票维度 HASH50”的分区规矩,运用存储引擎TSDB, 运用 “买卖所类型 股票代码 买卖时刻” 作为排序列。与沪深分隔存储的建库建表的分区规矩相似,仅在HASH数量和排序列方面有所区别。

3.1.1.5 逐笔托付(沪深兼并)

create database "dfs://merge_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 50])
engine='TSDB'
create table "dfs://merge_TB"."merge_entrustTB"(
    ChannelNo INT
    ApplSeqNum LONG
    MDStreamID SYMBOL
    SecurityID SYMBOL
    SecurityIDSource SYMBOL
    Price DOUBLE
    OrderQty LONG
    Side SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    OrderType SYMBOL
    LocalTime TIME
    SeqNo LONG
    OrderNO LONG
    DataStatus INT
    BizIndex LONG
    Market SYMBOL
)
partitioned by TradeTime, SecurityID,
sortColumns=[`Market,`SecurityID,`TradeTime],
keepDuplicates=ALL

用户能够运用上述代码树立一起存储沪深Levle-2行情数据的数据库表,运用”时刻维度按天 股票维度 HASH50”的分区规矩,运用存储引擎TSDB,运用 “买卖所类型 股票代码 买卖时刻” 作为排序列。与沪深分隔存储的建库建表的分区规矩相似,仅在HASH数量和排序列方面有所区别。

3.1.1.6 逐笔成交(沪深兼并)

create database "dfs://merge_TB"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 50])
engine='TSDB'
create table "dfs://merge_TB"."merge_tradeTB"(
    ChannelNo INT
    ApplSeqNum LONG
    MDStreamID SYMBOL
    BidApplSeqNum LONG
    OfferApplSeqNum LONG
    SecurityID SYMBOL
    SecurityIDSource SYMBOL
    TradePrice DOUBLE
    TradeQty LONG
    ExecType SYMBOL
    TradeTime TIMESTAMP[comment="时刻列", compress="delta"]
    LocalTime TIME
    SeqNo LONG
    DataStatus INT
    TradeMoney DOUBLE
    TradeBSFlag SYMBOL
    BizIndex LONG
    OrderKind SYMBOL
    Market SYMBOL
)
partitioned by TradeTime, SecurityID,
sortColumns=[`Market,`SecurityID,`TradeTime],
keepDuplicates=ALL

用户能够运用上述代码树立一起存储沪深Levle-2行情数据的数据库表,运用”时刻维度按天 股票维度 HASH50”的分区规矩,运用存储引擎TSDB,运用 “买卖所类型 股票代码 买卖时刻” 作为排序列。与沪深分隔存储的建库建表的分区规矩相似,仅在HASH数量和排序列方面有所区别。

3.1.2 股票日K数据

create database "dfs://k_day_level"
partitioned by RANGE(2000.01M   (0..30)*12)
engine='OLAP'
create table "dfs://k_day_level"."k_day"(
	securityid SYMBOL  
	tradetime TIMESTAMP
	open DOUBLE        
	close DOUBLE       
	high DOUBLE        
	low DOUBLE
	vol INT
	val DOUBLE
	vwap DOUBLE
)
partitioned by tradetime

用户能够运用上述代码树立一起存储日K的数据库表,运用”时刻维度按年”的分区规矩,运用存储引擎OLAP。每个分区内都包括了这一年一切股票的日K数据。

3.1.3 股票分钟 K 数据

create database "dfs://k_minute_level"
partitioned by VALUE(2020.01.01..2021.01.01)
engine='OLAP'
create table "dfs://k_minute_level"."k_minute"(
	securityid SYMBOL  
	tradetime TIMESTAMP
	open DOUBLE        
	close DOUBLE       
	high DOUBLE        
	low DOUBLE
	vol INT
	val DOUBLE
	vwap DOUBLE
)
partitioned by tradetime

用户能够运用上述代码树立一起存储日K的数据库表,运用”时刻维度按天”的分区规矩,存储引擎运用OLAP。每个分区内都包括了当天一切股票的分钟K数据。

3.2 期权数据

3.2.1 期权快照数据

create database "dfs://ctp"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 20])
engine='TSDB'
create table "dfs://ctp"."options"(
    TradingDay DATE[comment="时刻列", compress="delta"]
    ExchangeID SYMBOL
    LastPrice DOUBLE
    PreSettlementPrice DOUBLE
    PreClosePrice DOUBLE
    PreOpenInterest DOUBLE
    OpenPrice DOUBLE
    HighestPrice DOUBLE
    LowestPrice DOUBLE
    Volume INT
    Turnover DOUBLE
    OpenInterest DOUBLE
    ClosePrice DOUBLE
    SettlementPrice DOUBLE
    UpperLimitPrice DOUBLE
    LowerLimitPrice DOUBLE
    PreDelta DOUBLE
    CurrDelta DOUBLE
    UpdateTime SECOND
    UpdateMillisec INT
    BidPrice DOUBLE[]
    BidVolume INT[]
    AskPrice DOUBLE[]
    AskVolume INT[]
    AveragePrice DOUBLE
    ActionDay DATE
    InstrumentID SYMBOL
    ExchangeInstID STRING
    BandingUpperPrice DOUBLE
    BandingLowerPrice DOUBLE
    tradeTime TIME
    receivedTime NANOTIMESTAMP
    perPenetrationTime LONG
)
partitioned by TradingDay, InstrumentID,
sortColumns=[`InstrumentID,`ReceivedTime],
keepDuplicates=ALL

用户能够运用上述代码以创立存储期权快照数据的数据库表,分区规矩选用了“时刻维度按天 期权代码维度 HASH20”的组合分区方法存储,运用存储引擎TSDB,运用 “期权代码 接收时刻” 作为排序列。经测验期货快照数据选用这种方法分区存储,归纳功能最佳。

3.3 期货数据

3.3.1 期货快照数据

create database "dfs://ctp"
partitioned by VALUE(2020.01.01..2021.01.01), HASH([SYMBOL, 10])
engine='TSDB'
create table "dfs://ctp"."futures"(
    TradingDay DATE[comment="时刻列", compress="delta"]
    ExchangeID SYMBOL
    LastPrice DOUBLE
    PreSettlementPrice DOUBLE
    PreClosePrice DOUBLE
    PreOpenInterest DOUBLE
    OpenPrice DOUBLE
    HighestPrice DOUBLE
    LowestPrice DOUBLE
    Volume INT
    Turnover DOUBLE
    OpenInterest DOUBLE
    ClosePrice DOUBLE
    SettlementPrice DOUBLE
    UpperLimitPrice DOUBLE
    LowerLimitPrice DOUBLE
    PreDelta DOUBLE
    CurrDelta DOUBLE
    UpdateTime SECOND
    UpdateMillisec INT
    BidPrice DOUBLE[]
    BidVolume INT[]
    AskPrice DOUBLE[]
    AskVolume INT[]
    AveragePrice DOUBLE
    ActionDay DATE
    InstrumentID SYMBOL
    ExchangeInstID STRING
    BandingUpperPrice DOUBLE
    BandingLowerPrice DOUBLE
    tradeTime TIME
    receivedTime NANOTIMESTAMP
    perPenetrationTime LONG
)
partitioned by TradingDay, InstrumentID,
sortColumns=[`InstrumentID,`ReceivedTime],
keepDuplicates=ALL

用户能够运用上述代码以创立存储期货快照数据的数据库表,分区规矩选用了“时刻维度按天 期货代码维度 HASH10”的组合分区方法存储,运用存储引擎TSDB,运用 “期货代码 接收时刻” 作为排序列。经测验期货快照数据选用这种方法分区存储,归纳功能最佳。

3.3.2 期货日 K 数据

由于期货K数据与股票K数据相似,因而能够运用股票K数据的表格结构作为期货K数据的表格结构

create database "dfs://ctp_k_day_level"
partitioned by RANGE(2000.01M   (0..30)*12)
engine='OLAP'
create table "dfs://ctp_k_day_level"."ctp_k_day"(
	securityid SYMBOL  
	tradetime TIMESTAMP
	open DOUBLE        
	close DOUBLE       
	high DOUBLE        
	low DOUBLE
	vol INT
	val DOUBLE
	vwap DOUBLE
)
partitioned by tradetime

用户能够运用上述代码以创立存储期货日K数据的数据库表,与股票日K数据的分区规矩相同,运用”时刻维度按年”的分区规矩,存储引擎运用OLAP。在一个分区中包括了这一年一切期货的日K数据。

3.3.3 期货分钟 K 数据

create database "dfs://ctp_k_minute_level"
partitioned by VALUE(2020.01.01..2021.01.01)
engine='OLAP'
create table "dfs://ctp_k_minute_level"."ctp_k_minute"(
	securityid SYMBOL  
	tradetime TIMESTAMP
	open DOUBLE        
	close DOUBLE       
	high DOUBLE        
	low DOUBLE
	vol INT
	val DOUBLE
	vwap DOUBLE
)
partitioned by tradetime

用户能够运用上述代码以创立存储期货分钟K数据的数据库表,与股票分钟K数据的分区规矩相同,运用”时刻维度按天”的分区规矩,存储引擎运用OLAP。每个分区内都包括了当天一切期货的分钟K数据。

3.4 银行间债券

3.4.1 X-Bond 报价

create database "dfs://XBondDepth"
partitioned by VALUE(2023.01.01..2023.12.31)
engine='TSDB'
create table "dfs://XBondDepth"."XBondDepthTable"(
    bondCodeVal SYMBOL
    createTime TIMESTAMP
    marketDepth LONG
    mdBookType LONG
    messageId LONG
    messageSource STRING
    msgSeqNum LONG
    msgType STRING
    bidmdEntryPrice DOUBLE[]
    offermdEntryPrice DOUBLE[]
    bidmdEntrySize LONG[]
    offermdEntrySize LONG[]
    bidsettlType LONG[]
    offersettlType LONG[]
    bidyield DOUBLE[]
    offeryield DOUBLE[]
    bid1yieldType STRING
    offer1yieldType STRING
    bid2yieldType STRING
    offer2yieldType STRING
    bid3yieldType STRING
    offer3yieldType STRING
    bid4yieldType STRING
    offer4yieldType STRING
    bid5yieldType STRING
    offer5yieldType STRING
    bid6yieldType STRING
    offer6yieldType STRING
    securityID SYMBOL
    senderCompID STRING
    senderSubID STRING
    sendingTime TIMESTAMP
)
partitioned by createTime,
sortColumns=[`securityID, `createTime]

用户能够运用上述代码以创立存储X-Bond报价数据的数据库表,运用”时刻维度按天”的分区规矩,运用存储引擎TSDB,运用 “债券代码 创立时刻” 作为排序列。每个分区内都包括了当天一切 X-Bond 报价数据。

3.4.2 X-Bond 成交

create database "dfs://XBondTrade"
partitioned by VALUE(2023.01.01..2023.12.31)
engine='TSDB'
create table "dfs://XBondTrade"."XBondTradetable"(
    createTime TIMESTAMP
    securityID SYMBOL
    beforeClosingPrice DOUBLE
    beforeClosingYield DOUBLE
    beforeWeightedAveragePrice DOUBLE
    beforeWeightedAverageYield DOUBLE
    fillSide LONG
    highestPrice DOUBLE
    highestYield DOUBLE
    lowestPrice DOUBLE
    lowestYield DOUBLE
    marketIndicator LONG
    mdSubType LONG
    mdType LONG
    messageId LONG
    messageSource STRING
    msgSeqNum LONG
    msgType STRING
    openingValence DOUBLE
    openingYield DOUBLE
    priceRiseFallAmplitude DOUBLE
    senderCompID STRING
    sendingTime TIMESTAMP
    settlType LONG
    symbol STRING
    tradeMethod LONG
    transactTime TIMESTAMP
    transactionNumber LONG
    uniqueOutputKey LONG
    upToDatePrice DOUBLE
    upToDateYield DOUBLE
    weightedAveragePrice DOUBLE
    weightedAverageYield DOUBLE
    yieldRiseFall DOUBLE
)
partitioned by createTime,
sortColumns=[`securityID, `createTime]

用户能够运用上述代码以创立存储X-Bond成交数据的数据库表,运用”时刻维度按天”的分区规矩,运用存储引擎TSDB,运用 “债券代码 创立时刻” 作为排序列。每个分区内都包括了当天一切 X-Bond 成交数据。

3.4.3 ESP 报价

create database "dfs://ESPDepth"
partitioned by VALUE(2023.01.01..2023.12.31)
engine='TSDB'
create table "dfs://ESPDepth"."ESPDepthtable"(
    createTime TIMESTAMP
    bondCodeVal SYMBOL
    marketDepth LONG
    marketIndicator LONG
    mdBookType LONG
    mdSubBookType LONG
    messageId LONG
    messageSource STRING
    msgSeqNum LONG
    msgType STRING
    askclearingMethod LONG[]
    bidclearingMethod LONG[]
    askdeliveryType LONG[]
    biddeliveryType LONG[]
    askinitAccountNumSixCode LONG[]
    bidinitAccountNumSixCode LONG[]
    asklastPx DOUBLE[]
    bidlastPx DOUBLE[]
    askmdEntryDate DATE[]
    bidmdEntryDate DATE[]
    askmdEntrySize LONG[]
    bidmdEntrySize LONG[]
    askmdEntryTime TIME[]
    bidmdEntryTime TIME[]
    askmdQuoteType LONG[]
    bidmdQuoteType LONG[]
    askquoteEntryID LONG[]
    bidquoteEntryID LONG[]
    asksettlType LONG[]
    bidsettlType LONG[]
    askyield DOUBLE[]
    bidyield DOUBLE[]
    ask1initPartyTradeCode STRING
    bid1initPartyTradeCode STRING
    ask2initPartyTradeCode STRING
    bid2initPartyTradeCode STRING
    ask3initPartyTradeCode STRING
    bid3initPartyTradeCode STRING
    ask4initPartyTradeCode STRING
    bid4initPartyTradeCode STRING
    ask5initPartyTradeCode STRING
    bid5initPartyTradeCode STRING
    ask6initPartyTradeCode STRING
    bid6initPartyTradeCode STRING
    ask7initPartyTradeCode STRING
    bid7initPartyTradeCode STRING
    ask8initPartyTradeCode STRING
    bid8initPartyTradeCode STRING
    ask9initPartyTradeCode STRING
    bid9initPartyTradeCode STRING
    ask10initPartyTradeCode STRING
    bid10initPartyTradeCode STRING
    securityID SYMBOL
    securityType STRING
    senderCompID STRING
    senderSubID STRING
    sendingTime TIMESTAMP
    symbol STRING
)
partitioned by createTime,
sortColumns=[`securityID, `createTime]

用户能够运用上述代码以创立存储ESP报价数据的数据库表,运用”时刻维度按天”的分区规矩,运用存储引擎TSDB,运用 “债券代码 创立时刻” 作为排序列。每个分区内都包括了当天一切 ESP 报价数据。

3.4.4 ESP 成交

create database "dfs://ESPTrade"
partitioned by VALUE(2023.01.01..2023.12.31)
engine='TSDB'
create table "dfs://ESPTrade"."ESPTradetable"(
    createTime TIMESTAMP
    securityID SYMBOL
    execId STRING
    execType STRING
    lastQty LONG
    marketIndicator LONG
    messageSource STRING
    msgSeqNum LONG
    msgType STRING
    price DOUBLE
    senderCompID STRING
    stipulationType STRING
    stipulationValue DOUBLE
    symbol STRING
    tradeDate DATE
    tradeMethod LONG
    tradeTime TIME
    tradeType LONG
    transactTime TIMESTAMP
)
partitioned by createTime,
sortColumns=[`securityID, `createTime]

用户能够运用上述代码以创立存储ESP成交数据的数据库表,运用”时刻维度按天”的分区规矩,运用存储引擎TSDB,运用 “债券代码 创立时刻” 作为排序列。每个分区内都包括了当天一切 ESP 成交数据。

3.4.5 QB 报价

create database "dfs://QB_QUOTE"
partitioned by VALUE(2023.10.01..2023.10.31)
engine='TSDB'
create table "dfs://QB_QUOTE"."qbTable"(
	SENDINGTIME TIMESTAMP
	CONTRIBUTORID SYMBOL
	MARKETDATATIME TIMESTAMP
	SECURITYID SYMBOL
	BONDNAME SYMBOL
	DISPLAYLISTEDMARKET SYMBOL
	BIDQUOTESTATUS INT
	BIDYIELD DOUBLE
	BIDPX DOUBLE
	BIDPRICETYPE INT
	BIDPRICE DOUBLE
	BIDDIRTYPRICE DOUBLE
	BIDVOLUME INT
	BIDPRICEDESC STRING
	ASKQUOTESTATUS INT
	ASKYIELD DOUBLE
	OFFERPX DOUBLE
	ASKPRICETYPE INT
	ASKPRICE DOUBLE
	ASKDIRTYPRICE DOUBLE
	ASKVOLUME INT
	ASKPRICEDESC STRING
)
partitioned by MARKETDATATIME,
sortColumns=[`SECURITYID,`MARKETDATATIME]

用户能够运用上述代码以创立存储QB报价数据的数据库表,运用”时刻维度按天”的分区规矩,运用存储引擎TSDB,运用 “债券代码 市场时刻” 作为排序列。每个分区内都包括了当天一切 QB 报价数据。

3.4.6 QB 成交

create database "dfs://QB_TRADE"
partitioned by VALUE(2023.10.01..2023.10.31)
engine='TSDB'
create table "dfs://QB_TRADE"."lastTradeTable"(
	SECURITYID SYMBOL
	BONDNAME SYMBOL
	SENDINGTIME TIMESTAMP
	CONTRIBUTORID SYMBOL
	MARKETDATATIME TIMESTAMP
	MODIFYTIME SECOND
	DISPLAYLISTEDMARKET SYMBOL
	EXECID STRING
	DEALSTATUS INT
	TRADEMETHOD INT
	YIELD DOUBLE
	TRADEPX DOUBLE
	PRICETYPE INT
	TRADEPRICE DOUBLE
	DIRTYPRICE DOUBLE
	SETTLSPEED STRING
)
partitioned by MARKETDATATIME,
sortColumns=[`SECURITYID,`MARKETDATATIME]

用户能够运用上述代码以创立存储QB买卖数据的数据库表,运用”时刻维度按天”的分区规矩,运用存储引擎TSDB,运用 “债券代码 市场时刻” 作为排序列。每个分区内都包括了当天一切 QB 买卖数据。

4 因子库窄表存储计划实践

4.1 日频因子库

create database "dfs://dayFactorDB"
partitioned by RANGE(date(datetimeAdd(1980.01M,0..80*12,'M'))), VALUE(`f1`f2), 
engine='TSDB'
create table "dfs://dayFactorDB"."dayFactorTB"(
    tradetime DATE[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL, 
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储日频因子库的数据库表,分区规矩选用了“时刻维度按年 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验日频因子数据选用这种方法分区存储,归纳功能最佳。

对于分区内的分组排序存储来说,DolphinDB 中的 TSDB 存储引擎供给排序键设置,每一个分区的数据写在一个或多个level file中。每一个level file内部的数据依照指定的列进行排序且创立块索引。排序列中除了最终一列的其他列通常为在点查中过滤条件会用到的列,其仅有值组合称为 SortKeys。为确保功能最优,每个分区的 SortKeys 主张不超过1000个。 如 SortKeys 较多可经过设置 sortKeyMappingFunction 对 SortKeys 降维。经测验日频因子数据选用“securityid tradetime”的方法进行排序,sortKeyMapping设置为500时,归纳功能最佳。

4.2 半小时频因子库

 create database "dfs://halfhourFactorDB"
partitioned by RANGE(date(datetimeAdd(1980.01M,0..80*12,'M'))), VALUE(`f1`f2),
engine='TSDB'
create table "dfs://halfhourFactorDB"."halfhourFactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"],
    securityid SYMBOL,
    value DOUBLE,
    factorname SYMBOL,
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime],
keepDuplicates=ALL,
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储半小时频因子库的数据库表,分区规矩选用了“时刻维度按年 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验半小时频因子数据选用这种方法分区存储,归纳功能最佳。

4.3 非常钟频因子库

create database "dfs://tenMinutesFactorDB"
partitioned by VALUE(2023.01M..2023.06M), 
VALUE(`f1`f2), 
engine='TSDB'
create table "dfs://tenMinutesFactorDB"."tenMinutesFactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL, 
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储非常钟频因子库的数据库表,分区规矩选用了“时刻维度按月 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验非常钟频因子数据选用这种方法分区存储,归纳功能最佳。

4.4 分钟频因子库

create database "dfs://minuteFactorDB"
partitioned by VALUE(2012.01.01..2021.12.31), VALUE(`f1`f2), 
engine='TSDB'
create table "dfs://minuteFactorDB"."minuteFactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL, 
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储分钟频因子库的数据库表,分区规矩选用了“时刻维度按日 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验分钟频因子数据选用这种方法分区存储,归纳功能最佳。

4.5 秒钟频因子库

create database "dfs://secondFactorDB" 
partitioned by VALUE(datehour(2022.01.01T00:00:00)..datehour(2022.01.31T00:00:00)), VALUE(`f1`f2), 
engine='TSDB'
create table "dfs://secondFactorDB"."secondFactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL, 
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储秒钟频因子库的数据库表,分区规矩选用了“时刻维度按小时 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验秒钟频因子数据选用这种方法分区存储,归纳功能最佳。

4.6 Level-2 快照频因子库

create database "dfs://level2FactorDB" partitioned by VALUE(2022.01.01..2022.12.31), VALUE(["f1", "f2"]),
engine='TSDB'
create table "dfs://level2FactorDB"."level2FactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL, 
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储Level-2快照频因子库的数据库表,分区规矩选用了“时刻维度按日 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验Level-2快照频因子数据选用这种方法分区存储,归纳功能最佳。

4.7 逐笔频因子库

create database "dfs://tickFactorDB" partitioned by VALUE(2022.01.01..2022.12.31), VALUE(["f1", "f2"]), HASH([SYMBOL,10])
engine='TSDB'
create table "dfs://tickFactorDB"."tickFactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,securityid,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL

用户能够运用上述代码以创立存储逐笔频因子库的数据库表,分区规矩选用了“时刻维度按日 因子名维度 股票维度 HASH10“的组合分区方法存储,运用存储引擎TSDB,运用 “股票代码 买卖时刻” 作为排序列。经测验逐笔频因子数据选用这种方法分区存储,归纳功能最佳。与上述因子的存储计划不同的当地在于没有对sortKey进行降维,由于1天数据股票代码维度HASH 10,每个最小分区内是500个股票,不需要再进行降维。

4.8 期货500ms频因子库

create database "dfs://futuresFactorDB"
partitioned by VALUE(2022.01.01..2023.01.01), VALUE(["f1", "f2"]), 
engine='TSDB' 
create table "dfs://futuresFactorDB"."futuresFactorTB"(
    tradetime TIMESTAMP[comment="时刻列", compress="delta"], 
    securityid SYMBOL, 
    value DOUBLE, 
    factorname SYMBOL
)
partitioned by tradetime, factorname,
sortColumns=[`securityid, `tradetime], 
keepDuplicates=ALL, 
sortKeyMappingFunction=[hashBucket{, 500}]

用户能够运用上述代码以创立存储L期货500ms频因子库的数据库表,分区规矩选用了“时刻维度按日 因子名”的组合分区方法存储,运用存储引擎TSDB,运用 “期货代码 买卖时刻” 作为排序列。经测验期货500ms频因子数据选用这种方法分区存储,归纳功能最佳。

5. 结语

针对常见的金融数据,咱们经过最佳实践,给出上述建库建表的推荐计划,用户能够依据实践事务场景,进行恰当调整和修正。

6. 常见问题与回答(FAQ)

6.1 创立数据库表时报错:已经存在重名库表

执行创立数据库表的代码后,报出如下过错:

create database partitioned by VALUE(["f1","f2"]), engine=TSDB => It is not allowed to overwrite an existing database.

处理办法: 主张运用其他名字或者删掉该数据库。

删去指定数据库的代码如下:

dropDatabase("dfs://dayFactorDB")

检查指定数据库是否存在的代码如下:

existsDatabase("dfs://dayFactorDB")