3. 数据模型与存储设计:信用曲线数据、交易数据、风险敞口数据、历史行情数据

做信用衍生品做市系统,数据模型是地基。地基没打好,上层再漂亮的策略都是空中楼阁。我这些年踩过的坑,十有八九都跟数据模型设计有关。今天咱们就聊聊这四类核心数据怎么建模、怎么存。

3.1 信用曲线数据:定价的生命线

信用曲线,说白了就是市场对某个实体违约概率的定价。它直接影响你报出来的买卖价差。

核心字段设计

字段名 类型 说明
curve_id VARCHAR(32) 曲线唯一标识,如 CDX.NA.IG.202503
entity_name VARCHAR(64) 参考实体名称
tenor INT 期限,单位月
spread DECIMAL(12,6) 信用利差,单位bps
recovery_rate DECIMAL(5,4) 回收率假设
update_time DATETIME(6) 更新时间,精确到微秒

关键点:信用曲线是时序数据,每条曲线在不同时间点有不同形态。我建议用curve_id + update_time作为联合主键,方便做时间旅行查询。

存储方案

我个人习惯用ClickHouse存曲线数据。为什么?因为信用曲线查询模式很固定——按时间范围查、按实体查、按期限查。ClickHouse的列式存储和稀疏索引正好对口。

-- 建表语句示例
CREATE TABLE credit_curve (
    curve_id String,
    entity_name String,
    tenor Int32,
    spread Float64,
    recovery_rate Float64,
    update_time DateTime64(6)
) ENGINE = MergeTree()
ORDER BY (curve_id, update_time, tenor)
PARTITION BY toYYYYMM(update_time);

避坑指南:我曾经把曲线数据存在MySQL里,结果查询历史曲线回放时,一张表几亿行数据,查询要几十秒。后来换成ClickHouse,同样的查询降到毫秒级。嗯,选对存储引擎太重要了。

3.2 交易数据:做市系统的血液

交易数据是实时性要求最高的。每一笔成交、每一个报价,都直接影响风险敞口计算。

交易数据分类

  • 报价数据:你报出去的买卖价,别人不一定成交
  • 成交数据:实际达成的交易,这是真金白银
  • 撤销数据:报价被撤销的记录

核心字段设计

字段名 类型 说明
trade_id VARCHAR(64) 交易唯一ID
trade_type ENUM('QUOTE','EXECUTION','CANCEL') 交易类型
side ENUM('BID','ASK') 买卖方向
notional DECIMAL(18,2) 名义本金
price DECIMAL(12,6) 成交价格
trade_time DATETIME(6) 交易时间

注意:交易数据不能丢。我建议用Kafka做消息队列,同时写两份——一份到Redis做实时计算,一份到数据库做持久化。你想想看,如果系统重启后交易数据丢了,那风险敞口算出来就是错的。

3.3 风险敞口数据:风控的命门

风险敞口数据是实时计算出来的,不是直接存进去的。它反映的是当前持仓面临的市场风险。

核心指标

  • Delta:信用利差变化1bp,组合价值变化多少
  • Gamma:Delta的变化率
  • Vega:波动率变化的影响
  • CS01:信用利差变化1bp的损益

存储设计

风险敞口数据更新频率极高——每次报价变动、每笔成交都要重新算。我建议用Redis存实时数据,用InfluxDB存历史快照。

// Redis存储结构示例
// Key: risk:exposure:{portfolio_id}
// Value: Hash
{
  "delta": 1250000.50,
  "gamma": -35000.00,
  "vega": 78000.00,
  "cs01_1y": 25000.00,
  "cs01_5y": 45000.00,
  "cs01_10y": 32000.00,
  "update_time": "2025-03-15 14:30:00.123456"
}

经验之谈:风险敞口数据要按投资组合维度聚合。我曾经见过一个系统,每笔交易都单独算敞口,结果风控页面打开要等5秒。后来改成按组合聚合,查询速度提升了100倍。

3.4 历史行情数据:回测和归因的基石

历史行情数据是做回测、归因分析、压力测试的基础。没有历史数据,你根本没法验证策略好不好用。

数据粒度

粒度 保留周期 用途
Tick级 7天 高频回测、微观结构分析
分钟级 90天 日内策略回测
日级 5年 长期策略回测、压力测试

存储方案

历史行情数据量巨大。一条信用曲线一天就能产生几万条数据。我建议用时序数据库,比如TimescaleDB或InfluxDB。

-- TimescaleDB hypertable示例
CREATE TABLE historical_quotes (
    time TIMESTAMPTZ NOT NULL,
    symbol VARCHAR(32) NOT NULL,
    bid_price DOUBLE PRECISION,
    ask_price DOUBLE PRECISION,
    mid_price DOUBLE PRECISION,
    volume BIGINT
);

SELECT create_hypertable('historical_quotes', 'time');

-- 按symbol和时间创建索引
CREATE INDEX idx_symbol_time 
ON historical_quotes (symbol, time DESC);

小技巧:历史行情数据要做降采样。比如tick级数据保留7天,然后聚合成分钟级数据。我曾经犯过错误——把所有tick数据永久保留,结果存储成本一个月涨了10倍。后来做了分层存储策略,成本降下来了,查询速度反而更快了。

3.5 数据模型整体架构

这四类数据不是孤立的。它们之间的关系,我画了张图来说明。

信用衍生品做市系统数据模型架构 数据源层 交易所行情 | 做市商报价 | 内部定价引擎 | 外部数据供应商 数据处理层 数据清洗 | 曲线构建 | 风险计算 | 聚合降采样 信用曲线数据 ClickHouse 时序存储 交易数据 Kafka + Redis 实时+持久化 风险敞口数据 Redis + InfluxDB 实时+快照 历史行情数据 TimescaleDB 分层存储 应用层 实时定价 | 风险监控 | 回测系统 | 归因分析 | 报表生成

从图上你能看到,数据从源端进来,经过清洗和计算,分流到四个存储模块。每个模块的存储方案都不一样——因为它们的查询模式完全不同。

核心原则:数据模型设计要「因材施教」。别想着用一个数据库搞定所有事情。信用曲线适合列存,交易数据需要消息队列,风险敞口要实时,历史行情要分层。你想想看,如果非要用MySQL存所有数据,那系统迟早会出问题。

嗯,数据模型这块就聊到这儿。记住一句话:数据模型设计没有银弹,只有最适合你业务场景的方案。

专注资料整理