ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

NautilusTrader Python 指南:基于 PyO3 理解 Rust 核心之上的交易控制面

NautilusTrader Python 指南:基于 PyO3 理解 Rust 核心之上的交易控制面 NautilusTrader Python 指南基于 PyO3 理解 Rust 核心之上的交易控制面【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_traderNautilusTrader 采用Rust 核心 Python 控制面的双层架构完整的交易运行时引擎、节点、缓存、组合、消息总线、适配器、持久化由 Rust 实现而 Python 通过 PyO3 绑定获得配置、组合与用户组件开发能力。本文以 docs/concepts/python.md 为主线系统梳理运行时模型、用户组件回调契约、run()/run_async()异步执行模式、公开 API 契约与所有权生命周期边界并穿插源码级证据帮助你在底层确定性交给 Rust、上层业务用 Python 表达之间建立正确的边界认知。若你面向的是纯 Rust 原生应用请阅读 Rust 指南安装方式与受支持的 Python 版本见 安装指南。运行时模型三层职责一份状态Python 包由两部分组成nautilus_trader命名空间下的 Python 外观层以及编译后的nautilus_trader._libnautilus扩展即python/nautilus_trader/_libnautilus/__init__.pyi所描述的二进制接口。预编译 wheel 已内置该扩展运行时不需要Rust 工具链。层职责Python 应用层配置、组合、用户组件、分析以及与 Python 生态服务的集成PyO3 绑定层类型转换、参数校验、异常映射以及对 Rust 状态的所有权安全包装Rust 核心层领域类型、引擎、节点、缓存、组合、消息总线、适配器、持久化Python 中的Cache、Portfolio等对象本质上是 Rust 持有状态的包装器。节点与引擎将内部运行时对象保持私有只对外暴露受限的检查与控制方法例如node.cache、node.portfolio、node.handle()。这样做保证了系统中只存在一份权威状态同时允许 Python 配置系统、读取结果而不会产生对同一运行时状态的多重所有权。在源码层面这一边界体现在 crates/live/src/python/node.rsPyLiveNode内部持有一个RcRefCellOptionLiveNode所有状态访问都经由node()/node_mut()借用守卫完成借用失败会返回明确的错误node_busy_err/node_consumed_err而不是静默地暴露可变内部结构。用户组件继承公开基类重写回调Python 用户组件通过继承公开的 PyO3 基类并重写其文档化的回调方法来实现四类组件各司其职组件用途DataActor订阅数据、处理事件运行非交易类工作流Strategy实现交易决策并提交订单ExecutionAlgorithm通过执行引擎拆分或调度路由订单Controller通过ImportableControllerConfig创建并管理 actor 与策略应用代码负责构造配置Config、注册官方适配器工厂并把组件添加到BacktestNode、BacktestEngine或LiveNode而路由、引擎状态、订单管理、会计核算与交易所客户端全部由 Rust 承担。这与 Rust 能力矩阵 相互印证Strategy、Actor、各引擎、BacktestNode、LiveNode等组件在 Rust 与 Python 两条路径上均可使用而Controller的受支持注册路径可导入控制器配置目前仅面向 Python。回调执行契约务必遵守所有回调都在事件处理线程上同步执行必须尽快返回。阻塞 I/O、模型推理或长时间计算会拖延行情数据处理与订单执行。此类工作应卸载到 executor 或独立进程。详细的实盘规则见 配置实盘交易节点例如LiveNodeConfig、LiveDataEngineConfig、LiveExecutionEngineConfig、LiveRiskEngineConfig、LoggerConfig、CacheConfig、MessageBusConfig等配置项的组装方式。从源码看这些基类位于crates/common/src/python/actor.rsPyDataActor与crates/trading/src/python/strategy.rs、crates/trading/src/python/algorithm.rsPyStrategy、PyExecutionAlgorithm并通过pyo3_stub_gen宏生成对应的.pyi类型桩。异步执行run()与run_async()两种模式Rust 适配器网络层运行在 Tokio 之上Python 异步库运行在 asyncio 事件循环上——PyO3 不会把 Python 协程变成 Tokio 任务。两者是两个独立的运行时。LiveNode支持两种执行模式方法执行上下文信号所有者完成时机run()调用线程阻塞LiveNode协调关闭完成后返回run_async()Python 宿主事件循环宿主应用走完相同的协调关闭路径后 resolverun_async()允许 asyncio 或 ASGI 应用在既有事件循环上托管节点。它驱动与run()完全相同的 Rust 生命周期并把SIGINT/SIGTERM处理留给宿主。项目在 CI 中针对默认 asyncio 循环、uvloop 以及由 Uvicorn 托管的 ASGI lifespan 做了兼容性测试Python wheel不会安装 uvloop 或 Uvicorn由应用自行提供所选循环与服务器。构造节点的 ASGI 应用必须以单 worker运行且关闭热重载见 托管事件循环 的警告说明。托管运行的正确打开方式在启动run_async()之前捕获node.cache、node.portfolio与node.handle()协程在运行期间拥有节点而捕获的这些对象保持可用通过LiveNodeHandle.stop()停止托管运行然后 await 运行任务等待完整关闭取消Cancellation会先请求同样的优雅关闭待完成后才向外传播任务结束后调用node.dispose()释放节点资源宿主必须在 handle 报告Running之后才能宣告启动完成并在任务生命周期内持续监督若任务意外结束应视为服务失败。一个可落地的托管生命周期骨架取自 实盘概念文档node.run_async()返回原生协程可直接asyncio.create_taskimport asyncio from nautilus_trader.live import LiveNode from nautilus_trader.live import LiveNodeHandle async def wait_until_running( handle: LiveNodeHandle, task: asyncio.Task[None], ) - None: while not handle.is_running: if task.done(): await task raise RuntimeError(LiveNode stopped during startup) await asyncio.sleep(0.01) async def serve_with_node(node: LiveNode) - None: cache, portfolio, handle node.cache, node.portfolio, node.handle() run_task: asyncio.Task[None] | None None service_task: asyncio.Task[None] | None None try: run_task asyncio.create_task(node.run_async()) await wait_until_running(handle, run_task) service_task asyncio.create_task(serve_requests(cache, portfolio, handle)) done, _ await asyncio.wait( (run_task, service_task), return_whenasyncio.FIRST_COMPLETED, ) if run_task in done: await run_task raise RuntimeError(LiveNode stopped while the service was running) await service_task finally: if service_task is not None and not service_task.done(): service_task.cancel() await asyncio.gather(service_task, return_exceptionsTrue) try: if run_task is not None: handle.stop() await run_task finally: node.dispose()源码层面对托管模式的支撑同样在 crates/live/src/python/node.rsrun_async要求存在正在运行的 asyncio 循环否则报错提示改用run()约 L957-L967每个线程只允许一个托管运行HOSTED_RUN_ACTIVE线程局部守卫约 L211-L217第二个托管节点在同一事件循环上会被直接拒绝PyNodeRun通过宿主循环回调轮询 Rust 运行 future并借助HostWakePump线程把唤醒信号经call_soon_threadsafe安全调度回 Python 侧约 L359-L475throw()把注入的异常先转换为优雅关闭、待关闭完成后再重新抛出约 L710-L731配置了缓存数据库后端的节点会被run_async()拒绝——这类后端会阻塞调用线程等待 worker 任务从而卡死宿主循环须改用run()见py_run_async内的校验。公开 API 契约以生成式类型桩为准python/nautilus_trader/下的生成式类型桩.pyi定义了受支持的 Python 接口面它们记录了 Rust 绑定源码中的公开类、方法、属性、参数与返回类型Python API 参考 渲染的正是同一批公开模块及其文档。由此引出三条契约规则运行时属性若不在生成桩中就不属于受支持契约——不要依赖文档之外的动态属性PyO3 在进入 Rust 代码之前就完成绑定参数校验并把可失败操作映射为 Python 异常代码应处理文档化的异常类型而不是依赖内部 Rust 错误表示生成桩是源码派生产物绑定变更会更新 Rust 源码并重新生成桩检入仓库的.pyi文件不是独立的 API 定义手工修改会被重新生成覆盖。特别提醒一个兼容性陷阱原文以 warning 标注Side 枚举兼容别名OrderSide.NO_ORDER_SIDE与PositionSide.NO_POSITION_SIDE目前仍作为None的兼容别名存在但它们不是枚举成员可能在未来的版本中被移除。可选 side 值请使用None。所有权与生命周期节点边界上的 Rust 语义Rust 的所有权语义在节点边界清晰可见这既是一种约束也是防止 Python 引用暴露可变引擎内部、或对同一运行时状态产生多个持有者的设计保证BacktestNode的引擎是内部的。需要保留引擎做后续分析时以dispose_on_completionFalse运行再通过节点的 cache、portfolio、statistics 与 report 方法检查结果。该配置项在 crates/backtest/src/config.rs 中定义并在 crates/backtest/src/node.rs 决定运行完成后是否释放引擎。LiveNode.run_async()是出借而非共享。运行期间通过节点本身访问状态会抛错而is_running与handle()始终保持可用二者都走线程安全的 handle见PyLiveNodeHandle的实现约 L167-L203运行期间的dispose()调用是 no-op 而非延迟请求须在运行结束后再次调用运行前捕获的对象在运行期间一直可用。同一进程内不支持并发LiveNode/BacktestNode实例因为它们的运行时状态并未隔离。必须先 dispose 一个节点再启动下一个需要并行时请使用独立进程。这也解释了为什么run_async会拒绝同一事件循环上的第二个托管节点。支持边界适配器与扩展路径官方适配器全部在 Rust 中实现并通过nautilus_trader.adapters下的 Python 配置、工厂、客户端与数据类型暴露出来各交易所的能力边界以其集成指南为准见 适配器 与 集成文档目录其中包含 Architect AX、Betfair、Binance、BitMEX、Blockchain、Bybit、Coinbase、Databento、Deribit、Derive、dYdX、Hyperliquid、Interactive Brokers、Kraken、Lighter、OKX、Polymarket、Sandbox、Tardis 等。需要明确的两点限制公开 Python API 目前尚未定义完全用 Python 实现 out-of-tree 适配器的接口。官方适配器可在 Python 中使用自定义交易所接入当前走 Rust 适配器 trait各适配器 crate 位于 crates/adapters/例如crates/adapters/okx、crates/adapters/binance。纯 Python 适配器接口仍在规划中对应上游 issue 4694。托管式LiveNode执行让 Python 服务得以与节点共享 asyncio 循环但这本身并不新增 Python 适配器接口。如何选择 Python 还是 Rust选择是场景驱动的选 Python当应用组合、策略快速迭代、分析工具或与 Python 生态集成是首要诉求时选 Rust当应用必须脱离 Python 运行时运行或需要原生 trait 与直接的 crate 级控制时详见 Rust 指南 的工程搭建、feature 标志与内存分配器说明。两条路径共享同一套 Rust 领域模型与引擎。Rust 能力矩阵 给出了每个组件与官方适配器在两条路径上的暴露情况可作为技术选型的核对清单。迁移视角可参考 v1 到 v2 迁移文档。相关指南架构 — 核心组件、线程模型与依赖流向Rust — 原生 Rust API 与运行时使用实盘交易 —LiveNode生命周期与托管事件循环回测 — 回测引擎、节点、数据与交易场所适配器 — 官方适配器配置与路由安装指南 — Python 3.12-3.14 支持矩阵与 PyPI / Nautech 包索引 / 源码构建三种安装方式【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表