# CTP Rust SDK
一个为CTP (综合交易平台) 提供的安全、现代化的Rust绑定库,支持Linux和macOS系统。
## ✨ 特性
- 🔒 **类型安全**: 使用Rust的类型系统确保内存安全和线程安全
- 🌍 **跨平台支持**: 原生支持Linux和macOS (x86_64/ARM64)
- 📝 **编码自动转换**: 自动处理GB18030到UTF-8的编码转换
- ⚡ **高性能**: 零拷贝设计,最小化性能开销
- 🛡️ **安全FFI**: 安全的C++库绑定,避免内存泄露和悬空指针
- 🐛 **调试支持**: 内置Debug日志功能,可配置日志输出
## 🚀 快速开始
### 项目结构
直接克隆并使用本项目:
```bash
git clone <repository-url>
cd ctp-rust
```
### 基本使用示例
整体架构流程
Rust Application
↓ 调用API
Rust FFI (ffi.rs)
↓ 调用C函数
C++ Wrapper (ctp_wrapper.cpp)
↓ 调用C++类方法
CTP C++ API (libthostmduserapi_se.dylib)
↓ 回调事件
C++ Bridge (spi_bridge.cpp)
↓ 转发回调
Rust Callback Functions
↓ 处理业务逻辑
Rust Application
#### 行情订阅
```rust
use ctp_rust::*;
use ctp_rust::api::{MdApi, CtpApi};
use ctp_rust::api::md_api::{MdSpiHandler, DepthMarketDataField};
use ctp_rust::types::{ReqUserLoginField, RspUserLoginField, RspInfoField};
// 实现行情回调处理器
struct MyMdHandler;
impl MdSpiHandler for MyMdHandler {
fn on_front_connected(&mut self) {
println!("行情前置已连接");
}
fn on_rsp_user_login(
&mut self,
user_login: Option<RspUserLoginField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
if let Some(rsp) = rsp_info {
if rsp.is_success() {
println!("登录成功");
} else {
if let Ok(msg) = rsp.get_error_msg() {
println!("登录失败: {}", msg);
}
}
}
}
fn on_rtn_depth_market_data(&mut self, market_data: DepthMarketDataField) {
println!("收到行情数据,最新价: {}", market_data.last_price);
}
}
#[tokio::main]
async fn main() -> CtpResult<()> {
// 创建行情API
let mut md_api = MdApi::new(Some("./flow"), false, false)?;
// 注册回调处理器
md_api.register_spi(MyMdHandler)?;
// 注册前置机地址
md_api.register_front("tcp://180.168.146.187:10131")?;
// 初始化
md_api.init()?;
// 创建登录请求
let login_req = ReqUserLoginField::new("9999", "投资者账号", "密码")?
.with_product_info("MyApp")?;
// 发送登录请求
md_api.req_user_login(&login_req)?;
// 订阅行情
md_api.subscribe_market_data(&["rb2501", "i2501"])?;
// 等待API退出
md_api.join()?;
Ok(())
}
```
#### 交易接口(同步)
```rust
use ctp_rust::api::{TraderApi, CtpApi};
use ctp_rust::api::trader_api::{TraderSpiHandler, ReqAuthenticateField};
struct MyTraderHandler;
impl TraderSpiHandler for MyTraderHandler {
fn on_front_connected(&mut self) {
println!("交易前置已连接");
}
fn on_rsp_authenticate(
&mut self,
rsp_authenticate: Option<ctp_rust::api::trader_api::RspAuthenticateField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
if let Some(rsp) = rsp_info {
if rsp.is_success() {
println!("认证成功");
}
}
}
}
#[tokio::main]
async fn main() -> CtpResult<()> {
// 创建交易API
let mut trader_api = TraderApi::new(Some("./flow"))?;
// 注册回调处理器
trader_api.register_spi(MyTraderHandler)?;
// 注册前置机地址
trader_api.register_front("tcp://180.168.146.187:10130")?;
// 初始化
trader_api.init()?;
// 客户端认证
let auth_req = ReqAuthenticateField {
broker_id: [0; 11], // 填入实际的经纪公司代码
user_id: [0; 16], // 填入实际的用户代码
// ... 其他字段
..Default::default()
};
trader_api.req_authenticate(&auth_req)?;
Ok(())
}
```
#### 异步交易接口
```rust
use ctp_rust::api::AsyncTraderApi;
use ctp_rust::api::async_trader_api::AsyncTraderEvent;
use ctp_rust::types::{QryTradingAccountField, ReqUserLoginField};
#[tokio::main]
async fn main() -> CtpResult<()> {
// 创建异步交易API
let async_trader = AsyncTraderApi::new(Some("./flow"), Some(true)).await?;
// 注册前置机并初始化
async_trader.register_front("tcp://180.168.146.187:10130").await?;
async_trader.init().await?;
// 等待连接
async_trader.wait_connected(30).await?;
// 异步登录
let login_req = ReqUserLoginField::new("9999", "投资者账号", "密码")?;
let login_info = async_trader.login(&login_req, 30).await?;
println!("登录成功: {:?}", login_info);
// 异步查询资金账户
let account_query = QryTradingAccountField::new("9999", "投资者账号")?;
let accounts = async_trader.qry_trading_account(&account_query, 10).await?;
for account in accounts {
println!("可用资金: {:.2}", account.available);
println!("当前余额: {:.2}", account.balance);
}
// 监听事件
while let Some(event) = async_trader.recv_event().await {
match event {
AsyncTraderEvent::OrderReturn(order) => {
println!("收到报单回报: {:?}", order);
}
AsyncTraderEvent::TradeReturn(trade) => {
println!("收到成交回报: {:?}", trade);
}
_ => {}
}
}
Ok(())
}
```
## 📖 详细文档
### 系统要求
- **操作系统**: Linux (x86_64) 或 macOS (x86_64/ARM64)
- **Rust版本**: 1.70+
- **CTP库**: 需要相应平台的CTP动态库
### 目录结构
```
ctp-rust/
├── src/
│ ├── lib.rs # 主库入口
│ ├── error.rs # 错误定义
│ ├── encoding.rs # 编码转换
│ ├── types.rs # 数据类型定义
│ ├── ffi.rs # FFI绑定声明
│ └── api/
│ ├── mod.rs # API模块
│ ├── md_api.rs # 行情API
│ └── trader_api.rs # 交易API
├── libs/ctp/
│ ├── common/
│ │ ├── debug_logger.h # 调试日志头文件
│ │ └── debug_logger.cpp # 调试日志实现
│ ├── linux/
│ │ ├── include/ # Linux CTP头文件
│ │ ├── lib/ # Linux动态库
│ │ └── wrapper/ # Linux C++包装器
│ └── mac64/
│ ├── include/ # macOS CTP头文件
│ ├── thostmduserapi_se.framework/ # macOS框架
│ ├── thosttraderapi_se.framework/
│ └── wrapper/ # macOS C++包装器
├── examples/ # 示例代码
└── build.rs # 构建脚本
```
### 编码处理
CTP库使用GB18030编码,而Rust默认使用UTF-8。本SDK自动处理两种编码之间的转换:
```rust
use ctp_rust::encoding::GbkConverter;
// UTF-8 转 GB18030
let gb_bytes = GbkConverter::utf8_to_gb18030("期货合约")?;
// GB18030 转 UTF-8
let utf8_string = GbkConverter::gb18030_to_utf8(&gb_bytes)?;
// 固定长度字节数组转换
use ctp_rust::types::{InstrumentIdType, StringConvert};
let instrument_id = InstrumentIdType::from_utf8_string("rb2501")?;
let back_to_string = instrument_id.to_utf8_string()?;
```
### 错误处理
SDK提供了完整的错误处理机制:
```rust
use ctp_rust::error::{CtpError, CtpResult};
match some_ctp_function() {
Ok(result) => println!("操作成功: {:?}", result),
Err(CtpError::ConnectionError(msg)) => println!("连接错误: {}", msg),
Err(CtpError::AuthenticationError(msg)) => println!("认证错误: {}", msg),
Err(CtpError::BusinessError(code, msg)) => {
println!("业务错误 [{}]: {}", code, msg);
}
Err(e) => println!("其他错误: {}", e),
}
```
### 平台支持
#### Linux
```bash
# 确保系统有必要的库
sudo apt-get install build-essential
# 设置库文件路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./libs/ctp/linux/lib
# 运行程序
cargo run
```
#### macOS
```bash
# 设置库文件路径
export DYLD_FRAMEWORK_PATH=$DYLD_FRAMEWORK_PATH:./libs/ctp/mac64
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./libs/ctp/mac64/wrapper
# 在Apple Silicon Mac上可能需要Rosetta
# 如果遇到架构问题,可以用Rosetta运行:
arch -x86_64 cargo run
```
## 🔧 构建配置
### 构建和调试日志
项目内置了调试日志功能,可以帮助排查问题:
```rust
use ctp_rust::ffi::{CTP_InitializeDebugLogging, CtpLogConfig};
use std::ffi::CString;
// 启用控制台日志输出
let log_path = CString::new("").unwrap();
let config = CtpLogConfig {
enable_debug: 1,
log_file_path: std::ptr::null(), // 使用null输出到控制台
max_file_size_mb: 10,
max_backup_files: 5,
};
unsafe {
CTP_InitializeDebugLogging(&config);
}
// 或者输出到文件
let log_path = CString::new("./ctp_debug.log").unwrap();
let config = CtpLogConfig {
enable_debug: 1,
log_file_path: log_path.as_ptr(),
max_file_size_mb: 10,
max_backup_files: 5,
};
```
### 编译和运行
```bash
# 构建项目(会自动编译C++包装器)
cargo build
# 运行示例
cargo run --example trader_basic
```
### 自定义构建
如果你需要自定义CTP库的位置,可以设置环境变量:
```bash
export CTP_LIB_PATH=/path/to/your/ctp/libs
export CTP_INCLUDE_PATH=/path/to/your/ctp/headers
```
### 功能特性
项目使用条件编译,根据可用的CTP库自动启用相应功能:
- `md_api`: 当找到行情API库时自动启用
- `trader_api`: 当找到交易API库时自动启用
- `test_mode`: 当没有CTP库时启用测试模式
## 📋 API参考
### 主要类型
- `MdApi`: 同步行情API接口
- `AsyncMdApi`: 异步行情API接口
- `TraderApi`: 同步交易API接口
- `AsyncTraderApi`: 异步交易API接口
- `ReqUserLoginField`: 用户登录请求
- `RspUserLoginField`: 用户登录响应
- `DepthMarketDataField`: 深度行情数据
- `OrderField`: 报单信息
- `TradeField`: 成交信息
### 回调接口
- `MdSpiHandler`: 行情回调处理接口(同步)
- `TraderSpiHandler`: 交易回调处理接口(同步)
- `AsyncMdEvent`: 异步行情事件
- `AsyncTraderEvent`: 异步交易事件
### 编码工具
- `GbkConverter`: GB18030/UTF-8编码转换器
- `StringConvert`: 字符串转换特质
## 🧪 测试
运行所有测试:
```bash
cargo test
```
运行编码测试:
```bash
cargo test --test encoding_tests
```
运行集成测试(需要CTP库):
```bash
cargo test --features integration
```
## 📚 示例
更多示例请查看 `examples/` 目录:
- `md_basic.rs`: 基础行情订阅(同步)
- `async_md_basic.rs`: 基础行情订阅(异步)
- `trader_basic.rs`: 基础交易功能,包含资金账户和持仓查询(同步)
- `async_trader_basic.rs`: 基础交易功能(异步)
- `encoding_demo.rs`: 编码转换示例
- `error_handling.rs`: 错误处理示例
- `debug_logger.rs`: 调试日志功能示例
### 运行示例
```bash
# 设置环境变量(以实际配置为准)
export CTP_BROKER_ID="9999"
export CTP_INVESTOR_ID="your_investor_id"
export CTP_PASSWORD="your_password"
export CTP_MD_FRONT="tcp://180.168.146.187:10131"
export CTP_TRADER_FRONT="tcp://180.168.146.187:10130"
export CTP_FLOW_PATH="./ctp_flow"
# 运行交易示例(macOS)
DYLD_FRAMEWORK_PATH=libs/ctp/mac64 DYLD_LIBRARY_PATH=libs/ctp/mac64/wrapper cargo run --example trader_basic
# 运行交易示例(Linux)
LD_LIBRARY_PATH=libs/ctp/linux/lib:libs/ctp/linux/wrapper cargo run --example trader_basic
```
## 🛠️ 开发指南
### 项目架构
```
Rust应用程序
↓ 调用API
Rust FFI层 (ffi.rs)
↓ 调用C函数
C++ Wrapper层 (ctp_wrapper.cpp)
↓ 调用C++方法
CTP C++ API (Framework/动态库)
↓ SPI回调
C++ Bridge层 (spi_bridge.cpp)
↓ 转发回调
Rust回调函数
↓ 业务逻辑处理
Rust应用程序
```
架构特点:
- **跨平台兼容**: Linux使用.so动态库,macOS使用.framework
- **调试日志**: 内置debug_logger提供详细的调用跟踪
- **内存安全**: 使用RAII和智能指针管理资源
### 添加新的 API 方法
1. **更新 C++ wrapper**
```cpp
int CThostFtdcTraderApi_ReqNewFunction(void* api, void* req, int request_id);
int CThostFtdcTraderApi_ReqNewFunction(void* api, void* req, int request_id) {
if (api) {
return static_cast<CThostFtdcTraderApi*>(api)->ReqNewFunction(
static_cast<RequestStruct*>(req), request_id);
}
return -1;
}
```
2. **更新 Rust FFI 声明**
```rust
extern "C" {
pub fn CThostFtdcTraderApi_ReqNewFunction(
api: *mut c_void,
req: *const c_void,
request_id: c_int,
) -> c_int;
}
```
3. **更新 Rust API**
```rust
pub fn req_new_function(&mut self, req: &RequestStruct) -> CtpResult<i32> {
}
```
4. **重新编译项目**
```bash
cargo build
```
### 添加新的回调
1. **更新 SPI Bridge**
```cpp
typedef void (*OnNewCallbackFunction)(void* user_data, void* data, int param);
OnNewCallbackFunction on_new_callback;
virtual void OnNewCallback(DataStruct* data, int param) override {
if (callbacks.on_new_callback) {
callbacks.on_new_callback(callbacks.user_data, data, param);
}
}
```
2. **更新 Rust 回调处理**
```rust
fn on_new_callback(&mut self, data: DataStruct, param: i32) {
}
extern "C" fn on_new_callback_impl(
user_data: *mut c_void,
data: *mut c_void,
param: c_int,
) {
}
```
### 调试技巧
1. **启用调试日志**
```rust
env_logger::init();
log::debug!("调试信息");
```
2. **使用 gdb/lldb 调试 C++ 部分**
```bash
lldb target/debug/examples/trader_basic
gdb target/debug/examples/trader_basic
```
3. **内存安全检查**
```bash
cargo valgrind run --example trader_basic
```
## 🤝 贡献
欢迎贡献代码!请遵循以下步骤:
1. Fork本仓库
2. 创建feature分支 (`git checkout -b feature/amazing-feature`)
3. 提交你的修改 (`git commit -m 'Add some amazing feature'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 开启Pull Request
## ⚠️ 注意事项
1. **库文件**: 需要获取相应平台的CTP库文件并放置在正确位置
2. **网络环境**: 连接CTP服务器需要稳定的网络环境
3. **账户权限**: 需要有效的CTP账户和相应的交易权限
4. **风险提示**: 期货交易有风险,请谨慎使用
## 📄 许可证
本项目采用MIT或Apache-2.0双重许可证。详见 [LICENSE-MIT](LICENSE-MIT) 和 [LICENSE-APACHE](LICENSE-APACHE) 文件。
## 🔗 相关链接
- [CTP官网](http://www.sfit.com.cn/)
- [Rust官网](https://www.rust-lang.org/)
- [CTP开发者社区](https://www.zhihu.com/topic/20015421)
## 📞 联系方式
如有问题或建议,请通过以下方式联系:
- GitHub Issues: 通过项目仓库提交问题
---
**免责声明**: 本软件仅供学习和研究使用,作者不对因使用本软件导致的任何损失承担责任。期货投资有风险,入市需谨慎。