Skip to content

QA Protocol 是一套标准化的金融市场数据接口协议,专为量化交易系统设计

Notifications You must be signed in to change notification settings

sun-rs/qaprotocol

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QA Protocol

语言无关的金融市场数据交换协议

License Version Arrow


📋 项目简介

QA Protocol 是一套标准化的金融市场数据接口协议,专为量化交易系统设计。该协议解耦于编程语言,可无缝转换为 C++、Python、Rust 等主流语言的数据结构,并原生支持 Apache Arrow/Parquet 列式存储格式。

核心特性

  • QIFI/DIFF 协议兼容: 与中国量化交易生态主流协议 100% 兼容
  • 多语言绑定生成: 自动生成 Python、Rust、C++、TypeScript 代码绑定
  • 零开销设计: 数据结构与Arrow Schema分离,按需加载无性能损耗
  • Arrow Schema 静态定义: 每种语言提供预定义 Arrow Schema 常量
  • Arrow/Parquet 原生: 列式存储优化,高效查询与压缩
  • 完整数据模型: 覆盖行情、账户、持仓、订单、成交、信号等 11 种数据类型
  • 零拷贝序列化: 支持 rkyv 零拷贝,性能提升 25 倍
  • 冲突已解决: 明确处理 CTP、QIFI、qaexchange-rs 间的数据模型差异

🎯 项目起源

背景

在中国量化交易领域,主流的数据接口包括:

  • CTP API: 期货交易所官方接口(C++ 原生)
  • QIFI 协议: Quantaxis 生态的标准化接口
  • DIFF 协议: 快期科技的金融数据流协议

这些接口在数据建模、命名规范、消息格式上存在差异,导致系统集成时需要大量适配工作。

设计目标

QA Protocol 通过分析以下开源项目的实现:

  • qaexchange-rs: DIFF 协议的 Rust 实现,含 K-Line 聚合系统
  • qautlra-rs: 市场数据结构与 Actor 并发模型
  • open-trade-gateway: CTP 到 DIFF 的转换网关
  • QIFI: Quantaxis 的账户/持仓/订单标准格式

提炼出一套统一的数据模型,在保持 QIFI 核心兼容的基础上,解决了以下关键冲突:


⚠️ 已解决的关键冲突

1. K-Line Period 编号冲突

问题: 不同项目对 K线周期使用不同的 ID 编号方式 解决方案: 采用 qaexchange-rs 的 HQChart 格式(ID: 0, 3-8),保证与现有系统兼容 详见: docs/DESIGN.md Section 1

2. Position 数据模型差异

问题: CTP 返回双记录(多/空分离),QIFI 使用单记录(多空合并) 解决方案: 采用 QIFI 单记录模型,提供 CTP 双记录合并算法 详见: docs/DESIGN.md Section 2(含完整 Python 转换代码)

3. QIFI 字段命名重复

问题: QIFI 对同一概念使用多种命名(如 volume_long_his / volume_long_yd / pos_long_his解决方案: 这是 QIFI 有意设计,用于兼容不同生态。本协议全部保留,并说明推荐用法 详见: docs/DESIGN.md Section 3

4. Arrow Schema 缺失

问题: 现有项目未提供标准 Arrow schema 定义 解决方案: 基于源代码分析,推导出完整的 Arrow JSON schema(11 种数据类型) 位置: schemas/*.json


📦 数据类型

市场数据 (3 种)

  • Tick: 实时逐笔行情(8 字段)
  • Snapshot: Level 2 市场快照,10 档深度(35+ 字段)
  • K-Line: OHLC 蜡烛图,7 种周期(13 字段)

交易数据 (5 种,QIFI 兼容)

  • Account: 账户资金与风险(19 字段)
  • Position: 持仓多空分离(32 字段)
  • Order: 订单生命周期(17 字段)
  • Trade: 成交记录(13 字段)
  • Transfer: 出入金流水(10 字段)

策略与事件 (3 种,协议扩展)

  • Signal: 策略信号(11 字段)
  • Event: 系统事件日志(7 字段)
  • Notification: 用户通知(8 字段)

🚀 快速开始

1. 生成语言绑定

# 生成所有语言(Python, Rust, C++, TypeScript)
./scripts/generate_bindings.sh

# 只生成特定语言
./scripts/generate_bindings.sh --lang python
./scripts/generate_bindings.sh --lang rust,cpp

# 指定输出目录
./scripts/generate_bindings.sh --output ./my_bindings

生成的代码位于 bindings/ 目录:

bindings/
├── python/               # Python bindings
│   ├── __init__.py       # 重新导出 models
│   ├── models/           # 数据结构(无 Arrow 依赖)
│   │   ├── __init__.py
│   │   ├── tick.py
│   │   └── ... (11 个文件)
│   └── schemas/          # Arrow schemas(按需导入)
│       ├── __init__.py
│       ├── tick_schema.py
│       └── ... (11 个文件)
│
├── rust/                 # Rust bindings
│   ├── Cargo.toml
│   └── src/
│       ├── lib.rs
│       ├── models/       # 数据结构(无 Arrow 依赖)
│       │   ├── mod.rs
│       │   ├── tick.rs
│       │   └── ... (11 个文件)
│       └── schemas/      # Arrow schemas(feature-gated)
│           ├── mod.rs
│           ├── tick_schema.rs
│           └── ... (11 个文件)
│
├── cpp/                  # C++ bindings
│   └── include/qa_protocol/
│       ├── qa_protocol.h # 主头文件(只含 models)
│       ├── models/       # 数据结构(无 Arrow 依赖)
│       │   ├── models.h
│       │   ├── tick.h
│       │   └── ... (11 个文件)
│       └── schemas/      # Arrow schemas(按需 include)
│           ├── schemas.h
│           ├── tick_schema.h
│           └── ... (11 个文件)
│
└── typescript/           # TypeScript bindings
    ├── package.json
    ├── index.ts          # 重新导出 models
    ├── models/           # 数据结构(无 Arrow 依赖)
    │   ├── index.ts
    │   ├── tick.ts
    │   └── ... (11 个文件)
    └── schemas/          # Arrow schemas(按需导入)
        ├── index.ts
        ├── tick_schema.ts
        └── ... (11 个文件)

🎯 零开销设计 - models/ + schemas/ 分离架构

  • models/ - 数据结构,无 Arrow 依赖,零加载开销
  • schemas/ - Arrow Schema 定义,按需导入

优势

  • 只用数据结构?→ 导入 models,无 Arrow 库加载,启动更快
  • 需要列式存储?→ 按需导入 schemas,精确控制依赖

2. Python 使用示例

# 场景1: 只用数据结构(无Arrow加载,零开销)
from qa_protocol.models import Tick  # ✅ 无pyarrow依赖
from datetime import datetime

tick = Tick(
    instrument_id=b'SHFE.rb2501',
    exchange_id=b'SHFE',
    timestamp=datetime.now(),
    trading_day=b'20250109',
    last_price=3500.0,
    volume=1000,
    amount=3500000.0
)

# 场景2: 需要Arrow Schema时才导入(按需加载)
from qa_protocol.schemas.tick_schema import get_tick_schema, ticks_to_arrow

# 批量转换为 Arrow Table
ticks = [tick, ...]  # 大量tick数据
table = ticks_to_arrow(ticks)  # 使用预定义Schema

# 场景3: 写入 Parquet 文件
import pyarrow.parquet as pq
pq.write_table(table, "ticks.parquet", compression='snappy')

# 场景4: 用 Polars 读取 Parquet
import polars as pl
df = pl.scan_parquet("data/tick/**/*.parquet") \
    .filter(pl.col("instrument_id") == b"SHFE.rb2501") \
    .sort("timestamp", descending=True) \
    .limit(100) \
    .collect()

3. Rust 使用示例

// 场景1: 只用数据结构(无Arrow依赖,零开销)
use qa_protocol::models::Tick;  // ✅ 默认无arrow依赖

let tick = Tick {
    instrument_id: b"SHFE.rb2501".to_vec(),
    exchange_id: b"SHFE".to_vec(),
    timestamp: 1704729600000000000,
    trading_day: b"20250109".to_vec(),
    last_price: 3500.0,
    volume: 1000,
    amount: 3500000.0,
    open_interest: Some(50000),
};

// 场景2: 需要Arrow Schema时启用feature(按需加载)
// Cargo.toml: qa_protocol = { version = "1.0", features = ["arrow"] }
#[cfg(feature = "arrow")]
{
    use qa_protocol::schemas::tick_schema::TICK_SCHEMA;
    use arrow::array::RecordBatch;

    let schema = &*TICK_SCHEMA;  // 引用静态schema
    println!("Fields: {:?}", schema.fields());

    // 使用TICK_SCHEMA构建列式数据
    let batch = RecordBatch::try_new(schema.clone(), vec![/* columns */])?;
}

4. TypeScript 使用示例

// 场景1: 只用数据结构(无Arrow导入,零开销)
import { Tick } from 'qa-protocol';  // ✅ 无apache-arrow依赖

const tick: Tick = {
  instrumentId: new Uint8Array([0x53, 0x48, 0x46, 0x45]),
  exchangeId: new Uint8Array([0x53, 0x48, 0x46, 0x45]),
  timestamp: 1704729600000000000,
  tradingDay: new Uint8Array([0x32, 0x30, 0x32, 0x35]),
  lastPrice: 3500.0,
  volume: 1000,
  amount: 3500000.0,
};

// 场景2: 需要Arrow Schema时才导入(按需加载)
import { TICK_SCHEMA } from 'qa-protocol/schemas/tick_schema';
import { tableFromArrays } from 'apache-arrow';

console.log('Schema fields:', TICK_SCHEMA.fields);

// 场景3: 创建 Arrow Table(列式存储)
const table = tableFromArrays({
  instrumentId: [tick.instrumentId],
  exchangeId: [tick.exchangeId],
  // ... 其他字段
}, TICK_SCHEMA);

完整示例: 参见 docs/IMPLEMENTATION.md


📚 文档导航

新手入门

  1. 阅读本文档了解项目背景
  2. 查看 docs/SPECIFICATION.md 理解数据结构
  3. 阅读 docs/IMPLEMENTATION.md 学习代码实现

按需查阅

我想... 查看文档
了解 Position 有哪些字段 docs/SPECIFICATION.md → Section 4.2
理解为什么用 HQChart period docs/DESIGN.md → Section 1
学习 Python 读写 Parquet docs/IMPLEMENTATION.md → Section 3
转换 CTP 双记录为 QIFI docs/DESIGN.md → Section 2(含算法)
查看 Arrow schema 定义 schemas/*.json + schemas/index.json

核心文档


🗂️ 目录结构

qaprotocol/
├── README.md                     # 本文档(项目入口)
├── CLAUDE.md                     # 开发约束与贡献指南
├── VERSION                       # 📌 项目版本号(单一真相源)
├── CHANGELOG.md                  # 版本变更历史
├── .gitignore
│
├── docs/                         # 📚 完整技术文档
│   ├── README.md                 # 文档导航中心
│   ├── SPECIFICATION.md          # 协议技术规范
│   ├── DESIGN.md                 # 设计决策与冲突解决
│   ├── IMPLEMENTATION.md         # 实现指南(代码示例)
│   └── FIELD_REQUIREMENTS.md     # 字段要求规范
│
├── schemas/                      # 📊 Arrow Schema 定义
│   ├── index.json                # Schema 元数据目录(引用 VERSION)
│   ├── tick.json                 # Tick 数据 schema
│   ├── kline.json                # K-Line schema
│   ├── account.json              # 账户 schema
│   ├── position.json             # 持仓 schema
│   └── ... (共 11 个数据类型)
│
├── scripts/                      # 🔧 自动化脚本
│   ├── generate_bindings.sh      # 主生成脚本(调用所有语言生成器)
│   ├── generate_python.py        # Python 绑定生成器
│   ├── generate_rust.py          # Rust 绑定生成器
│   ├── generate_cpp.py           # C++ 绑定生成器
│   ├── generate_typescript.py    # TypeScript 绑定生成器
│   └── update_version.sh         # 版本号自动更新脚本
│
└── bindings/                     # 🎯 生成的语言绑定(自动生成)
    ├── python/                   # Python dataclass (11 模块)
    ├── rust/                     # Rust struct + Cargo.toml
    ├── cpp/                      # C++ headers (11 文件)
    └── typescript/               # TypeScript interfaces + package.json

📊 性能指标

基于 qaexchange-rs 项目的实测数据:

操作 延迟 吞吐量
JSON 序列化 ~500 ns 2M ops/s
rkyv 零拷贝 ~20 ns 50M ops/s ⚡
Arrow 零拷贝 ~50 ns 20M ops/s
Parquet 写入 (Snappy) - 1.2 GB/s
Parquet 读取 - 1.5 GB/s

🔧 技术栈

  • 数据格式: Apache Arrow, Apache Parquet
  • 序列化: JSON (DIFF 协议), rkyv (零拷贝), Protobuf (QIFI)
  • 语言绑定:
    • Python: dataclass + typing
    • Rust: struct + serde (可选)
    • C++: struct + std::optional (C++17)
    • TypeScript: interface + optional properties
  • 代码生成: 基于 Arrow Schema JSON 自动生成
  • 压缩: Snappy (实时), Zstd (批处理)

🤝 贡献指南

开发约束

本项目遵循严格的代码复用原则,详见 CLAUDE.md

  • ✅ 优先扩展现有结构,而非创建新文件
  • ✅ 所有设计决策需引用源项目代码
  • ✅ 新增字段需明确标注为"协议扩展"

提交问题

发现文档错误或有改进建议?请在 GitHub Issues 提交反馈。


📖 参考项目

本协议基于以下开源项目的分析与整合:

项目 贡献内容 源码位置
qaexchange-rs K-Line 聚合、DIFF 协议、Arrow 存储 /solars_notes/top_project/qaexchange-rs/
qautlra-rs 市场数据结构、Actor 模型 /solars_notes/top_project/qautlra-rs/
open-trade-gateway CTP 转 DIFF、WebSocket 网关 /solars_notes/top_project/open-trade-gateway-master/
QIFI 账户/持仓/订单标准格式 /solars_notes/base_project/QIFI-master/

🎨 代码生成器

QA Protocol 提供自动化代码生成器,从 Arrow Schema 定义生成多语言类型绑定。

支持的语言

语言 类型系统 可选字段处理 输出格式
Python dataclass Optional[T] .py 模块
Rust struct Option<T> .rs 模块 + Cargo.toml
C++ struct std::optional<T> .h 头文件 (C++17)
TypeScript interface field?: .ts 接口 + package.json

使用方法

# 生成所有语言到默认目录 (bindings/)
./scripts/generate_bindings.sh

# 只生成特定语言
./scripts/generate_bindings.sh --lang python          # 只生成 Python
./scripts/generate_bindings.sh --lang rust,cpp        # 生成 Rust 和 C++

# 指定自定义输出目录
./scripts/generate_bindings.sh --output ./my_output

# 组合使用
./scripts/generate_bindings.sh --lang typescript --output ~/my_project/types

生成的文件

Python (bindings/python/)

python/
├── __init__.py              # 重新导出 models
├── models/                  # 数据结构(无 Arrow 依赖)
│   ├── __init__.py
│   ├── tick.py
│   ├── account.py
│   └── ... (共 11 个模块)
└── schemas/                 # Arrow schemas(按需导入)
    ├── __init__.py
    ├── tick_schema.py
    ├── account_schema.py
    └── ... (共 11 个模块)

Rust (bindings/rust/)

rust/
├── Cargo.toml              # 包配置(含 arrow feature)
└── src/
    ├── lib.rs              # 导出 models 和 schemas
    ├── models/             # 数据结构(无 Arrow 依赖)
    │   ├── mod.rs
    │   ├── tick.rs
    │   └── ... (共 11 个模块)
    └── schemas/            # Arrow schemas(feature-gated)
        ├── mod.rs
        ├── tick_schema.rs
        └── ... (共 11 个模块)

C++ (bindings/cpp/)

cpp/
└── include/qa_protocol/
    ├── qa_protocol.h       # 主头文件(只含 models)
    ├── models/             # 数据结构(无 Arrow 依赖)
    │   ├── models.h
    │   ├── tick.h
    │   └── ... (共 11 个头文件)
    └── schemas/            # Arrow schemas(按需 include)
        ├── schemas.h
        ├── tick_schema.h
        └── ... (共 11 个头文件)

TypeScript (bindings/typescript/)

typescript/
├── package.json            # npm 包配置
├── tsconfig.json           # TypeScript 配置
├── index.ts                # 重新导出 models
├── models/                 # 数据结构(无 Arrow 依赖)
│   ├── index.ts
│   ├── tick.ts
│   └── ... (共 11 个文件)
└── schemas/                # Arrow schemas(按需导入)
    ├── index.ts
    ├── tick_schema.ts
    └── ... (共 11 个文件)

类型映射

Arrow 类型 Python Rust C++ TypeScript
binary bytes Vec<u8> std::vector<uint8_t> Uint8Array
utf8 str String std::string string
int/long int i32/i64 int32_t/int64_t number
double float f64 double number
bool bool bool bool boolean
timestamp datetime i64 (ns) int64_t (ns) number (ns)
struct 嵌套 dataclass 嵌套 struct 嵌套 struct 嵌套 interface

Schema 更新工作流

当 schemas/*.json 文件更新后,重新生成绑定:

# 1. 修改 schema 文件
vim schemas/tick.json

# 2. 更新版本号(如果是不兼容变更)
./scripts/update_version.sh 2.0.0

# 3. 重新生成所有语言绑定
./scripts/generate_bindings.sh

# 4. 提交变更
git add schemas/ VERSION
git commit -m "feat: add new field to Tick schema"

🔢 版本管理

版本号体系

QA Protocol 采用 语义化版本 2.0.0 规范:

主版本号.次版本号.修订号 (MAJOR.MINOR.PATCH)
例如: 1.0.0

递增规则

  • 主版本号(MAJOR):不兼容的 API 修改(如字段删除、类型变更)
  • 次版本号(MINOR):向下兼容的功能新增(如新增 schema、新增可选字段)
  • 修订号(PATCH):向下兼容的问题修正(如文档修正、性能优化)

统一版本策略

📌 单一真相源(Single Source of Truth)

QA Protocol 所有 schema 使用 统一的项目版本号,版本号定义在根目录的 VERSION 文件中。

VERSION 文件 (1.0.0)
    ↓ 被引用
schemas/index.json
    ↓ 被引用
各个 schema 文件(不包含独立 version 字段)

为什么采用统一版本?

  • ✅ schemas 作为整体发布(Account/Position/Order 高度耦合)
  • ✅ 简化版本管理,避免兼容性矩阵爆炸
  • ✅ 单一真相源,避免版本号不一致
  • ✅ 版本更新只需修改 1 个文件

版本更新流程

1. 自动更新(推荐)

# 更新到新版本(如 1.1.0)
./scripts/update_version.sh 1.1.0

脚本会自动更新:

  • VERSION 文件
  • schemas/index.json
  • README.md 版本徽章

2. 手动更新

然后手动更新以下文件:

  • CHANGELOG.md - 添加新版本变更记录
  • README.md - 更新版本历史表

📝 版本历史

版本 日期 变更说明
1.0.0 2025-01-08 初始版本发布,包含 11 种数据类型完整规范

详细变更记录请查看 CHANGELOG.md


📄 许可证

本项目采用 MIT 许可证。详见 LICENSE 文件。


🙏 致谢

感谢 Quantaxis、快期科技、qaexchange-rs 等开源社区的贡献。本协议旨在推动中国量化交易生态的标准化进程。


维护团队: QA Protocol Team 最后更新: 2025-01-08 联系方式: 参见 GitHub Issues

About

QA Protocol 是一套标准化的金融市场数据接口协议,专为量化交易系统设计

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published