TQSDK-RS
天勤量化交易平台的 Rust SDK - 高性能、类型安全的期货交易接口
核心特性
- 类型安全 - 使用 Rust 强类型系统,90+ 字段完整定义,编译时消除运行时错误
- 并发安全 - 基于 Arc + RwLock 设计,确保多线程环境下的数据安全,无数据竞争
- 异步优化 - 基于 tokio 异步运行时,高效处理 I/O 操作,零成本抽象
- DIFF 协议 - 完整实现天勤 DIFF 协议,支持增量数据更新和递归合并
- 灵活接口 - 支持 Channel、Callback、Stream 三种数据订阅方式,满足不同场景需求
- 零竞态条件 - 支持延迟启动模式,确保回调注册完成后再启动监听,避免数据丢失
- 零拷贝回调 - 使用 Arc 参数优化,多回调场景下性能提升 50-100x
- Polars 集成 - 高性能列式数据分析,支持 K线/Tick 数据转换为 DataFrame(可选功能)
- 灵活日志系统 - 支持 Layer 组合,本地时区显示,可与业务层日志集成
功能模块
行情数据
- 实时行情订阅(Quote)- 支持多合约同时订阅
- K线数据订阅(单合约/多合约对齐)- 支持任意周期
- Tick 数据订阅 - 逐笔成交数据
- 历史数据获取(支持 left_kline_id 和 focus_datetime 两种方式)
- ViewWidth 限制和二分查找优化 - 高效处理大数据集
- Polars DataFrame 集成 - 高性能数据分析(可选功能)
交易功能
- 实盘交易(TradeSession)- 支持期货公司实盘和 SimNow 模拟
- 账户信息查询 - 实时资金、权益、保证金等
- 持仓/委托单/成交查询 - 完整的交易数据
- 下单/撤单操作 - 支持限价单、市价单等
- 自动重连机制 - 网络断开自动恢复
数据管理
- DIFF 协议数据合并 - 递归合并嵌套对象
- 路径监听(Watch/UnWatch)- 精确监听指定路径的数据变化
- 版本追踪(Epoch)- 追踪每次数据更新
- 数据类型转换 - JSON 到强类型结构体的自动转换
性能优化
- 零拷贝回调设计 - Arc 参数优化,避免数据深拷贝
- 高性能缓冲区 - KlineBuffer/TickBuffer 支持 O(1) 更新
- 列式数据分析 - Polars DataFrame 集成(可选)
开发体验
- 灵活日志系统 - 支持 Layer 组合和本地时区
- 完整示例 - 8+ 示例程序覆盖所有功能
- 详细文档 - 完整的 API 文档和使用指南
快速开始
安装依赖
在 Cargo.toml 中添加:
[]
= "0.1.0"
= { = "1", = ["full"] }
# 可选:启用 Polars DataFrame 支持
= { = "0.1.0", = ["polars"] }
基础示例 - 行情订阅
use ;
async
使用 ClientBuilder(推荐)
ClientBuilder 提供了更灵活的配置方式:
use Client;
async
核心功能详解
1. 行情订阅
Quote 订阅 - 实时行情
Quote 订阅支持多合约同时订阅,提供三种数据接收方式:
// 订阅多个合约的实时行情
let quote_sub = client.subscribe_quote.await?;
// 方式 1: 使用回调函数(推荐)
quote_sub.on_quote.await;
// 方式 2: 使用 Channel(支持多个消费者)
let rx = quote_sub.quote_channel;
spawn;
// 启动订阅(延迟启动模式)
quote_sub.start.await?;
// 动态添加合约
quote_sub.add_symbols.await?;
// 动态移除合约
quote_sub.remove_symbols.await?;
K线订阅 - 单合约
K线订阅支持任意周期,使用延迟启动模式避免数据丢失:
use Duration;
// 获取 Series API
let series_api = client.series?;
// 订阅 1 分钟 K线,获取最近 100 根
let sub = series_api.kline.await?;
// 先注册回调(重要:避免丢失初始数据)
// 注意:data 和 info 都是 Arc 包装的,零拷贝共享
sub.on_update.await;
// 最后启动订阅
sub.start.await?;
// 常用周期示例
// Duration::from_secs(60) // 1 分钟
// Duration::from_secs(300) // 5 分钟
// Duration::from_secs(900) // 15 分钟
// Duration::from_secs(3600) // 1 小时
// Duration::from_secs(86400) // 1 天
多合约对齐 K线
多合约订阅会自动进行时间对齐,适用于跨品种分析:
// 订阅多个合约的 K线(自动时间对齐)
let symbols = vec!;
let sub = series_api.kline_multi.await?;
sub.on_update.await;
sub.start.await?;
Tick 订阅 - 逐笔成交
Tick 数据提供最细粒度的市场数据:
// 订阅 Tick 数据
let sub = series_api.tick.await?;
sub.on_update.await;
sub.start.await?;
历史数据获取
支持两种方式获取历史数据:
use Utc;
// 方式 1: 使用 left_kline_id(精确定位)
// 从指定 K线 ID 开始获取
let sub = series_api.kline_history.await?;
// 方式 2: 使用 focus_datetime(时间定位)
// 从指定时间点开始获取
let focus_time = now - days; // 7天前
let sub = series_api.kline_history_with_focus.await?;
// 注册回调处理历史数据
sub.on_update.await;
sub.start.await?;
2. 交易功能
创建交易会话
TradeSession 使用延迟连接模式,避免消息丢失:
// 创建交易会话(不自动连接)
let session = client.create_trade_session.await?;
// 步骤 1: 先注册所有回调(重要:避免丢失初始数据)
// 监听账户变化
session.on_account.await;
// 监听持仓变化
session.on_position.await;
// 监听委托单变化
session.on_order.await;
// 监听成交记录
session.on_trade.await;
// 步骤 2: 最后连接服务器
session.connect.await?;
下单操作
支持限价单、市价单等多种下单方式:
// 限价开多仓
let order_id = session.insert_order.await?;
println!;
// 市价平仓
let order_id = session.insert_order.await?;
// 撤单
session.cancel_order.await?;
println!;
查询交易数据
提供完整的交易数据查询接口:
// 查询账户信息
let account = session.get_account.await?;
println!;
println!;
println!;
println!;
// 查询持仓
let position = session.get_position.await?;
println!;
println!;
println!;
// 查询委托单
let order = session.get_order.await?;
println!;
println!;
// 查询成交记录
let trade = session.get_trade.await?;
println!;
println!;
3. 数据管理器(DataManager)
DataManager 是底层数据存储,实现了 DIFF 协议:
直接访问数据
// 获取 DataManager 实例(需要先初始化 client)
let dm = client.dm.clone;
// 获取 Quote 数据
let quote = dm.get_quote_data?;
println!;
println!;
println!;
// 获取 K线数据
// 参数:合约代码, 周期(纳秒), 数量, right_id(-1表示最新)
let klines = dm.get_klines_data?;
println!;
// 路径访问(灵活访问任意数据)
if let Some = dm.get_by_path
// 检查数据是否在最近一次更新中发生变化
if dm.is_changing
// 获取当前版本号
let epoch = dm.get_epoch;
println!;
路径监听(Watch/UnWatch)
精确监听指定路径的数据变化:
// 监听指定路径的数据变化
let rx = dm.watch;
// 在另一个任务中接收更新
spawn;
// 监听多个路径
let symbols = vec!;
for symbol in &symbols
// 取消监听
dm.unwatch?;
数据更新回调
注册全局数据更新回调:
// 注册数据更新回调(每次数据更新时触发)
dm.on_data;
// 可以注册多个回调
dm.on_data;
dm.on_data;
4. Polars DataFrame 集成(可选功能)
启用 polars 功能后,可以将 K线和 Tick 数据转换为 Polars DataFrame 进行高性能分析。
使用 KlineBuffer 进行实时数据分析
use ;
use Duration;
async
直接转换 SeriesData
// 单合约 K线
subscription.on_update.await;
// 多合约 K线(长表格式)
multi_subscription.on_update.await;
// 多合约 K线(宽表格式)
multi_subscription.on_update.await;
技术指标计算
use *;
// 计算移动平均线
// 在回调中使用
subscription.on_update.await;
详细文档: 查看 POLARS_INTEGRATION.md 了解完整的 Polars 集成指南。
5. 认证管理
切换账号(运行时)
支持在运行时动态切换账号:
use TqAuth;
// 创建新的认证器
let mut new_auth = new;
new_auth.login.await?;
// 切换认证器
client.set_auth.await;
// 重新初始化行情(使用新账号)
client.init_market.await?;
权限检查
在订阅前自动检查权限,也可以手动检查:
// 获取认证器
let auth = client.get_auth.await;
// 检查功能权限
if auth.has_feature
if auth.has_feature
// 检查行情权限(多个合约)
match auth.has_md_grants
// 检查交易权限(单个合约)
match auth.has_td_grants
// 获取认证信息
println!;
println!;
示例程序
项目提供了完整的示例程序,涵盖所有核心功能:
运行示例
# 行情订阅示例(Quote、K线、Tick)
# 历史数据获取示例
# 交易操作示例(下单、撤单、查询)
# DataManager 高级功能示例
# 认证功能示例
# 账号切换示例
# ClientBuilder 使用示例
# Polars DataFrame 集成示例(需要启用 polars 功能)
# 自定义日志 Layer 组合示例
环境变量配置
运行示例前需要设置环境变量:
# 天勤账号(必需)
# SimNow 模拟账号(仅交易示例需要)
示例说明
| 示例文件 | 功能说明 | 适用场景 |
|---|---|---|
| quote.rs | Quote、K线、Tick 订阅 | 学习行情订阅 |
| history.rs | 历史数据获取 | 回测、数据分析 |
| trade.rs | 下单、撤单、查询 | 实盘交易 |
| datamanager.rs | 数据管理器高级用法 | 自定义数据处理 |
| auth_demo.rs | 认证和权限检查 | 了解认证机制 |
| auth_switch.rs | 运行时切换账号 | 多账号管理 |
| client_builder.rs | ClientBuilder 用法 | 灵活配置客户端 |
| polars_demo.rs | Polars DataFrame 集成 | 数据分析和技术指标 |
| custom_logger.rs | 自定义日志 Layer | 日志系统集成 |
技术栈
| 依赖 | 版本 | 用途 |
|---|---|---|
| tokio | 1.48 | 异步运行时 |
| yawc | 0.2.7 | WebSocket 客户端(支持 deflate 压缩) |
| reqwest | 0.12 | HTTP 客户端 |
| serde | 1.0 | 序列化/反序列化 |
| serde_json | 1.0 | JSON 处理 |
| jsonwebtoken | 10.2 | JWT 认证 |
| thiserror | 2.0 | 错误处理 |
| tracing | 0.1 | 结构化日志 |
| chrono | 0.4 | 时间处理 |
| async-channel | 2.3 | 异步通道 |
| polars | 0.44 | 数据分析(可选) |
项目结构
tqsdk-rs/
├── src/
│ ├── lib.rs # 库入口和模块导出
│ ├── client.rs # 客户端和 ClientBuilder
│ ├── auth.rs # 认证模块(TqAuth)
│ ├── websocket.rs # WebSocket 封装
│ ├── datamanager.rs # 数据管理器(DIFF 协议)
│ ├── types.rs # 数据结构定义(90+ 字段)
│ ├── quote.rs # Quote 订阅
│ ├── series.rs # Series API(K线/Tick)
│ ├── trade_session.rs # 交易会话
│ ├── utils.rs # 工具函数
│ ├── logger.rs # 日志系统
│ └── errors.rs # 错误类型
├── examples/
│ ├── quote.rs # 行情订阅示例
│ ├── history.rs # 历史数据示例
│ ├── trade.rs # 交易示例
│ ├── datamanager.rs # DataManager 示例
│ ├── auth_demo.rs # 认证示例
│ ├── auth_switch.rs # 切换账号示例
│ └── client_builder.rs # ClientBuilder 示例
└── README.md
核心设计
DIFF 协议实现
完整实现天勤 DIFF 协议,这是本项目的核心技术亮点:
- 递归合并 - 支持嵌套对象的增量更新,高效处理复杂数据结构
- ViewWidth 限制 - 使用二分查找优化大数据集,避免内存溢出
- Binding 对齐 - 多合约 K线时间对齐,支持跨品种分析
- 版本追踪 - Epoch 机制追踪每次数据变化,精确判断更新
- 路径监听 - Watch/UnWatch 精确监听指定路径的数据变化
- NaN 处理 - 正确处理 NaN 和特殊值
类型安全
Rust 的类型系统带来的优势:
- 90+ 字段的强类型定义 - Quote、Kline、Tick、Account 等完整定义
- 编译时类型检查 - 消除大量运行时错误
- 泛型和 trait 抽象 - Authenticator trait 支持自定义认证
- Result 类型统一错误处理 - 强制错误处理,避免遗漏
并发安全
多线程环境下的安全保证:
- Arc + RwLock - 保证线程安全的共享数据访问
- async-channel - 异步通信,支持多生产者多消费者
- AtomicI64 - 原子操作优化性能(Epoch 版本号)
- 无数据竞争 - 编译时保证,无需运行时检查
灵活接口
支持三种数据订阅方式,满足不同场景需求:
- Channel - 使用 async-channel,支持多个订阅者,适合多任务处理
- Callback - 注册回调函数,异步触发,适合事件驱动(零拷贝优化)
- Stream - 使用 async-stream,支持流式处理,适合函数式编程
零拷贝回调设计
所有回调函数使用 Arc<T> 参数,避免数据深拷贝:
// Quote 回调:Arc<Quote>
quote_sub.on_quote.await;
// Series 回调:Arc<SeriesData>, Arc<UpdateInfo>
series_sub.on_update.await;
性能优势:
- 多回调场景下内存节省 50-90%
- 克隆性能提升 500-1000x(只克隆 8 字节指针)
- 线程安全的数据共享
详细文档: 查看 ARC_OPTIMIZATION.md 和 ARC_QUOTE_OPTIMIZATION.md
零成本抽象
Rust 的零成本抽象理念:
- 编译时优化 - 泛型和 trait 在编译时展开,无运行时开销
- 无 GC 压力 - 所有权系统管理内存,无垃圾回收停顿
- 内联优化 - 小函数自动内联,减少函数调用开销
最佳实践
1. 延迟启动模式(强烈推荐)
避免竞态条件,确保不丢失初始数据:
// 推荐:先注册回调,再启动
let sub = series_api.kline.await?;
// 先注册所有回调
sub.on_update.await;
sub.on_new_bar.await;
// 最后启动订阅
sub.start.await?;
// 不推荐:启动后再注册回调(可能丢失初始数据)
// sub.start().await?;
// sub.on_update(...).await; // 可能错过初始数据
2. 错误处理
使用 Result 类型和模式匹配处理错误:
use ;
async
3. 资源清理
及时释放资源,避免内存泄漏:
// 使用完毕后关闭资源
quote_sub.close.await?;
series_sub.close.await?;
session.close.await?;
client.close.await?;
// 或使用 RAII 模式(推荐)
4. 日志配置
合理配置日志级别,便于调试。支持本地时区显示和 Layer 组合:
use ;
// 方式 1: 快速初始化(简单场景)
init_logger; // 级别: trace, debug, info, warn, error
// 方式 2: 使用 ClientBuilder(推荐)
let client = builder
.log_level // 开发时使用 debug
.build
.await?;
// 方式 3: Layer 组合(高级场景)
use ;
let tqsdk_layer = create_logger_layer;
// 可以与业务层的其他 Layer 组合
registry
.with
// .with(your_custom_layer)
.init;
// 生产环境建议使用 info 或 warn
let client = builder
.log_level
.build
.await?;
日志特性:
- 自动使用本地时区(如
2024-11-26T10:30:45.123+08:00) - 支持 Layer 组合,可与业务日志集成
- 详细的源文件和行号信息
详细文档: 查看 LOGGER_GUIDE.md 了解完整的日志配置指南。
5. 合约代码格式
使用完整的合约代码格式:
// 正确:使用完整格式
"SHFE.au2602" // 上期所黄金
"DCE.m2505" // 大商所豆粕
"CZCE.SR505" // 郑商所白糖
// 错误:不完整的格式
"au2602" // 缺少交易所
"SHFE.au" // 缺少月份
6. ViewWidth 设置
合理设置 ViewWidth,避免内存浪费:
// 实时监控:较小的 ViewWidth
let sub = series_api.kline.await?;
// 数据分析:较大的 ViewWidth
let sub = series_api.kline.await?;
// 注意:最大 10000,超过会自动调整
let sub = series_api.kline.await?;
// 实际会被调整为 10000
与 Go 版本对比
| 维度 | Go 版本 | Rust 版本 | 说明 |
|---|---|---|---|
| 代码行数 | ~8,000 | ~4,900 | Rust 更简洁 |
| 类型安全 | 弱类型 | 强类型 | Rust 优势 |
| 内存安全 | GC | 所有权 | Rust 优势 |
| 并发安全 | 运行时检查 | 编译时检查 | Rust 优势 |
| 性能 | 高 | 更高 | Rust 优势 |
| 零拷贝 | 部分支持 | Arc 优化 | Rust 优势 |
| 错误处理 | error | Result | Rust 优势 |
| 数据分析 | 需第三方库 | Polars 集成 | Rust 优势 |
| 学习曲线 | 低 | 中高 | Go 优势 |
| 开发速度 | 快 | 中 | Go 略优 |
注意事项
重要提示
- 合约代码格式 - 必须使用完整的合约代码格式,如
SHFE.au2602(交易所.合约代码) - 延迟启动模式 - 强烈推荐使用延迟启动模式,先注册回调再调用
start(),避免竞态条件 - 资源释放 - 使用完毕后记得调用
close()释放资源,避免连接泄漏 - 权限检查 - 订阅前会自动检查权限,确保账号有相应的行情或交易权限
- ViewWidth 限制 - 最大值为 10000,超过会自动调整为 10000
常见问题
Q: 为什么收不到数据?
- 检查是否调用了
start()方法 - 确认回调是在
start()之前注册 - 检查合约代码格式是否正确
- 确认账号有相应权限
Q: 如何处理网络断开?
- WebSocket 会自动重连
- TradeSession 支持自动重连
- 重连后会自动恢复订阅
Q: 多合约订阅如何优化?
- 使用单个
subscribe_quote()订阅多个合约 - 避免为每个合约创建单独的订阅
- 合理设置 ViewWidth,避免内存浪费
Q: 如何调试?
- 设置日志级别为
debug或trace - 使用
RUST_LOG环境变量:RUST_LOG=tqsdk_rs=debug cargo run - 检查 WebSocket 连接状态
- 日志自动显示本地时区,便于调试
Q: 如何集成业务层日志?
- 使用
create_logger_layer()获取 tqsdk-rs 的 Layer - 与业务层的其他 Layer 组合
- 详见 LOGGER_GUIDE.md
报告问题
如果发现 Bug 或有功能建议,请提交 GitHub Issue。
许可证
本项目采用 Apache License 2.0 许可证 - 详见 LICENSE 文件
相关项目
- tqsdk-go - Go 语言版本
- tqsdk-python - Python 官方版本
免责声明
重要提示:本项目仅供学习和研究使用。
本项目明确拒绝对产品做任何明示或暗示的担保。使用本项目进行交易和投资的一切风险由使用者自行承担。期货交易具有高风险,可能导致本金全部损失,请谨慎投资。
作者和贡献者不对使用本软件造成的任何直接或间接损失承担责任。