nautilus_trader 中的 CFD 差价合约:字段模型、校验规则与实战构建指南
【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader
本文是 nautilus_trader 仪器(Instrument)体系中 CFD(Contract for Difference,差价合约)的完整技术指南。CFD 是追踪标的资产价格、但并不转移标的资产所有权的衍生合约,交易所在其中定义报价货币、精度、最小变动价位、限价、保证金与手续费。读完本文,你将掌握Cfd仪器在 Rust 与 Python 双侧的完整字段语义、builder/构造器用法、源码级校验规则,以及 Interactive Brokers 适配器如何将 CFD 合约映射到该模型。
CFD 是什么:追踪标的但不持有标的
在 nautilus_trader 的模型设计中,Cfd表示一份差价合约:它跟踪某个基础资产的价格走势,但交易双方不进行标的资产的实物交割或所有权转移。合约的报价货币(quote currency)、价格/数量精度、最小变动价位、上下限、保证金比率与手续费率,全部由交易场所(venue)定义。
典型的 CFD 标的包括:
- 外汇(FX)差价合约,例如 AUD/USD CFD;
- 股票差价合约;
- 指数(Index)差价合约;
- 大宗商品(Commodity)差价合约,例如黄金 CFD。
在 nautilus_trader 中,Cfd的类型定义位于 crates/model/src/instruments/cfd.rs,并通过#[repr(C)]与pyo3桥接暴露给 Python,Python 侧的类型签名位于 python/nautilus_trader/model/init.pyi 的class Cfd声明。
字段全解:从 Rust 结构体到 Python 构造器
Cfd的核心字段与 Rust/Python 类型、必填性与默认值如下表(完整继承自 docs/concepts/instruments/cfd.md,并补充源码注释):
| 字段 | Rust 类型 | Python 类型 | 必填/默认 | 说明 |
|---|---|---|---|---|
instrument_id | InstrumentId | InstrumentId | 必填 | 仪器唯一标识,Rust 侧存储为id |
raw_symbol | Symbol | Symbol | 必填 | 交易场所原生的本地符号 |
asset_class | AssetClass | AssetClass | 必填 | 标的资产的资产类别(如 FX、Commodity) |
base_currency | Option<Currency> | Currency \| None | None | 当 CFD 跟踪单一币种时的基础币种(可选) |
quote_currency | Currency | Currency | 必填 | 用于报价与计价的货币 |
price_precision | u8 | int | 必填 | 价格允许的小数位数 |
size_precision | u8 | int | 必填 | 订单数量允许的小数位数 |
price_increment | Price | Price | 必填 | 最小合法价格步进(tick size) |
size_increment | Quantity | Quantity | 必填 | 最小合法数量步进 |
lot_size | Option<Quantity> | Quantity \| None | None | 取整后的手数/板面大小 |
max_quantity | Option<Quantity> | Quantity \| None | None | 最大订单数量 |
min_quantity | Option<Quantity> | Quantity \| None | None | 最小订单数量 |
max_notional | Option<Money> | Money \| None | None | 最大订单名义价值 |
min_notional | Option<Money> | Money \| None | None | 最小订单名义价值 |
max_price | Option<Price> | Price \| None | None | 最大合法报价/订单价格 |
min_price | Option<Price> | Price \| None | None | 最小合法报价/订单价格 |
margin_init | Option<Decimal> | Decimal \| None | 0 | 初始保证金比率 |
margin_maint | Option<Decimal> | Decimal \| None | 0 | 维持保证金比率 |
maker_fee | Option<Decimal> | Decimal \| None | 0 | 挂单(maker)费率,负值表示返佣 |
taker_fee | Option<Decimal> | Decimal \| None | 0 | 吃单(taker)费率,负值表示返佣 |
tick_scheme | Option<Ustr> | str \| None | None | 已注册的可变 tick scheme 名称 |
info | Option<Params> | dict \| None | None | 适配器附加的元数据 |
ts_event | UnixNanos | int | 必填 | 事件时间戳(纳秒) |
ts_init | UnixNanos | int | 必填 | 初始化时间戳(纳秒) |
注意:Python 构造器使用
instrument_id参数名,而 Rust 结构体中将同一值存储为id字段(见 crates/model/src/instruments/cfd.rs 中pub id: InstrumentId的注释)。
行为特征:Cfd 在 Instrument 抽象中的语义
从Cfd对Instrumenttrait 的实现(crates/model/src/instruments/cfd.rs)可以确认以下行为:
- 仪器类别:
instrument_class()恒返回InstrumentClass::Cfd; - 非反向合约:
is_inverse()恒为false; - 乘数为 1:
multiplier()恒返回Quantity::from(1); - 无期权属性:
option_kind()、strike_price()均返回None; - 无时间窗:
activation_ns()与expiration_ns()均返回None; - 结算币种:
settlement_currency()直接返回quote_currency; - 无标的代码:
underlying()、isin()、exchange()均返回None。
一个值得注意的实践建议:当同一交易场所同时提供现货(cash)工具与 CFD 时,应优先使用来源市场类型(source market type)进行区分,而不是仅依赖asset_class。
构建 Cfd:Rust Builder 与 Python 构造器实战
Rust:fluent builder
Rust 侧推荐使用Cfd::builder(),必填字段由编译器在构建期强制,可选字段可省略并沿用与new_checked相同的默认值,build()时执行与校验构造完全一致的完整性检查:
use nautilus_core::UnixNanos; use nautilus_model::{ enums::AssetClass, identifiers::{InstrumentId, Symbol}, instruments::Cfd, types::{Currency, Price, Quantity}, }; use rust_decimal_macros::dec; let audusd = Cfd::builder() .instrument_id(InstrumentId::from("AUDUSD.OANDA")) .raw_symbol(Symbol::from("AUD/USD")) .asset_class(AssetClass::FX) .base_currency(Currency::from("AUD")) .quote_currency(Currency::from("USD")) .price_precision(5) .size_precision(0) .price_increment(Price::from("0.00001")) .size_increment(Quantity::from("1")) .lot_size(Quantity::from("1000")) .margin_init(dec!(0.03)) .margin_maint(dec!(0.03)) .maker_fee(dec!(0.00002)) .taker_fee(dec!(0.00002)) .ts_event(UnixNanos::default()) .ts_init(UnixNanos::default()) .build() .unwrap();该示例在 OANDA 风格的 AUD/USD CFD 上设置了 5 位价格精度(0.00001tick)、整手数量精度、1000 手的手数、3% 的初始/维持保证金以及双边 0.002% 的手续费率。
Python:关键字构造器
Python 侧直接调用Cfd(...)构造器,参数名与 Rust builder 一一对应:
from decimal import Decimal from nautilus_trader.model import AssetClass from nautilus_trader.model import Cfd from nautilus_trader.model import Currency from nautilus_trader.model import InstrumentId from nautilus_trader.model import Price from nautilus_trader.model import Quantity from nautilus_trader.model import Symbol audusd = Cfd( instrument_id=InstrumentId.from_str("AUDUSD.OANDA"), raw_symbol=Symbol("AUD/USD"), asset_class=AssetClass.FX, quote_currency=Currency.from_str("USD"), price_precision=5, price_increment=Price.from_str("0.00001"), size_precision=0, size_increment=Quantity.from_int(1), ts_event=0, ts_init=0, base_currency=Currency.from_str("AUD"), lot_size=Quantity.from_int(1000), margin_init=Decimal("0.03"), margin_maint=Decimal("0.03"), maker_fee=Decimal("0.00002"), taker_fee=Decimal("0.00002"), )注意 Python 构造器中instrument_id为关键字参数,base_currency、lot_size以及全部保证金/费率参数都是带默认值的可选参数,可以按需省略。
源码级校验:构造时到底检查了什么
Cfd::new_checked的校验逻辑位于 crates/model/src/instruments/cfd.rs,build()最终也会走同一路径。校验项包括:
- 精度一致性:
check_equal_u8要求price_precision == price_increment.precision,同时要求size_precision == size_increment.precision。也就是说,Price::from("0.00001")携带的精度必须与price_precision(5)声明一致,否则直接返回错误; - 正数约束:
check_positive_price(price_increment)与check_positive_quantity(size_increment)强制 tick 与数量步进为正;若提供了lot_size,同样通过check_positive_quantity校验其必须为正; - tick scheme 校验:
check_tick_scheme验证tick_scheme必须是已注册的可变 tick scheme 名称; - 默认值落盘:
margin_init、margin_maint、maker_fee、taker_fee在传入None时统一落为0(unwrap_or_default)。
这些校验行为都有单元测试佐证(同文件mod tests):
test_trait_accessors验证GOLD-CFD.SIM的instrument_class() == InstrumentClass::Cfd、is_inverse() == false、price_precision == 2、size_precision == 0;test_new_checked_price_precision_mismatch验证价格精度与 tick 精度不一致时构造失败;test_new_checked_rejects_non_positive_lot_size验证非正手数被拒绝;test_serialization_roundtrip验证serde_json序列化/反序列化往返一致;test_builder_matches_new_checked验证 builder 构建结果与位置参数new_checked完全等价。
测试用标准 CFG 样例同样定义在 crates/model/src/instruments/stubs.rs 的cfd_goldfixture 中(GOLD-CFD.SIM、Commodity 类别、USD 报价、0.01tick),可作为快速理解字段取值的最佳参考。
适配器实践:Interactive Brokers 如何产出 Cfd
文档明确指出 Interactive Brokers 是代表性的 CFD 消费/生产适配器。在 crates/adapters/interactive_brokers/src/providers/parse.rs 中,parse_cfd_contract负责把 IB 合约详情(ContractDetails)映射为Cfd:
price_precision由tick_size_to_precision(details.min_tick)推导;size_precision由tick_size_to_precision(details.min_size)推导;price_increment/size_increment分别由min_tick、size_increment构造;base_currency的启发式规则:当 IB 的local_symbol包含.时,取contract.symbol作为基础币种;- 其余字段(
raw_symbol、asset_class、quote_currency、info元数据、ts_event/ts_init时间戳)均从 IB 合约数据填充后经Cfd::builder().build()产出。
这意味着当你通过 IB 适配器连接 CFD 合约时,nautilus_trader 会自动完成上述换算与模型构建,无需手工拼装。更完整的集成说明见 Interactive Brokers 集成文档。
相关仪器对比
Cfd是 nautilus_trader 仪器家族的一员,与以下类型存在语义边界,可根据合约结构选择正确的类型:
- Currency Pair(货币对):覆盖现货外汇与加密货币现货对,属于
BASE/QUOTE现货市场,与 CFD 最大的区别是标的资产直接成交; - Commodity(现货商品):覆盖现货商品仪器,用于非杠杆的现货标的建模。
选择原则很简单:若合约不转移标的资产所有权、以杠杆保证金方式跟踪标的(外汇、股票、指数、商品),则使用Cfd;若标的为现货/现金市场直接成交,则选择CurrencyPair或Commodity。
【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考