Skip to content

梳理并统一 Rust/Python 对外 API surface #20

Description

@zengbin93

背景

当前 wbt 的长期目标是:Rust 端和 Python 端提供统一的对外 API

本次检查发现:目前还没有做到完全一致。现状更像是:Rust crate 提供核心计算能力,Python 包在 Rust 核心之上提供更完整的用户层 API、绘图/report、mock 和辅助工具。

需要明确哪些 API 属于 Rust/Python 必须一致的 canonical API,哪些是 Python-only 展示层能力,哪些需要从 Python 迁移到 Rust 作为共享实现。

当前检查结论

1. Python 顶层 API 明显多于 Rust

Python 顶层 wbt.__all__ 当前暴露:

  • WeightBacktest
  • backtest
  • BacktestResult
  • daily_performance
  • top_drawdowns
  • rolling_daily_performance
  • cal_yearly_days
  • generate_backtest_report
  • mock_symbol_kline
  • mock_weights
  • weights_simple_ensemble
  • cal_trade_price
  • log_strategy_info
  • Curve / ReturnDist / MonthlyHeatmap / SymbolReturns / PairsDist / KeyTrade / KeyTrades

Rust 端目前主要暴露:

  • wbt::core::WeightBacktest
  • WeightType
  • daily_performance
  • top_drawdowns
  • rolling_daily_performance
  • cal_yearly_days
  • Report / StatsReport / SymbolsReport
  • 一批内部模块和结构:native_engineDailysSoAPairsSoADailyTotalskey_trades helper、trade_dirperiod_win_rates 等。

2. 同一能力的 API 形状不一致

例子:

  • Python WeightBacktest(data, ...) 支持 pandas / polars / 文件路径。
  • Rust WeightBacktest::new(df, ...) 接 Polars DataFramefrom_file(...) 单独处理文件。
  • Python 以属性暴露:wb.daily_returnwb.dailyswb.alphawb.pairs,返回 pandas DataFrame
  • Rust 以方法暴露:daily_return_df()dailys_df()alpha_df()pairs_df(),返回 Polars DataFrame / Option<DataFrame>

这些能力口径相近,但 API 名称、调用方式、返回类型都不完全一致。

3. Rust 暴露了不少内部实现细节

由于当前 src/lib.rs 直接 pub mod core;,而 core/mod.rs 里多个模块是 pub mod,导致 Rust public surface 包含不少内部实现:

  • native_engine::DailyTotals
  • native_engine::DailysSoA
  • native_engine::PairsSoA
  • native_engine::NativeEngine
  • key_trades 内部聚合函数
  • trade_dir
  • period_win_rates

这些更像内部实现细节,不一定应该成为稳定对外 API。

4. Rust 核心 + Python wrapper 的函数还不是“完全同形”

以下函数已有 Rust 核心和 Python wrapper:

  • daily_performance
  • top_drawdowns
  • rolling_daily_performance
  • cal_yearly_days

但 Python wrapper 的入参/返回更用户友好,Rust 端更底层。例如 Python 接 pandas / Series,Rust 接 slice / Polars DataFrame / Arrow IPC 字节。它们目前可认为“计算口径一致”,但不是“API 完全一致”。

已明确的边界

Python-only

以下能力只服务 Python 展示层,后续不要求 Rust 端提供完全同名 API:

  • wbt.plotting.*
  • wbt.report.*
  • generate_backtest_report
  • HtmlReportBuilder
  • plotly / HTML 相关能力

这些应明确标为 Python-only,不纳入 Rust/Python canonical API 对齐范围。

应迁移到 Rust 并共享

mock 应该在 Rust 中实现,然后 Python 和 Rust 共用一套生成逻辑:

  • mock_symbol_kline
  • mock_weights

原因:mock 数据用于示例、测试、benchmark。如果 Python/Rust 各自实现,随机序列、字段口径、日期生成逻辑容易分叉,影响跨语言验收。

建议的 canonical API 清单

后续建议以 Rust 为 canonical API 源头,Python 做薄封装和类型适配。

核心回测 API

  • WeightBacktest
  • backtest / WeightBacktest::backtest
  • BacktestResultCore / Python BacktestResult
  • stats
  • long_stats
  • short_stats
  • daily_return
  • dailys
  • alpha
  • pairs
  • aggregated_pairs
  • key_trades
  • segment_stats
  • long_alpha_stats
  • is_good_strategy
  • to_result
  • to_dict
  • to_msgpack

独立指标/工具 API

  • daily_performance
  • top_drawdowns
  • rolling_daily_performance
  • cal_yearly_days
  • weights_simple_ensemble(需评估是否迁到 Rust)
  • cal_trade_price(需评估是否迁到 Rust)
  • mock_symbol_kline(迁到 Rust)
  • mock_weights(迁到 Rust)

Python-only 展示 API

  • plot_cumulative_returns
  • plot_drawdown
  • plot_daily_return_dist
  • plot_monthly_heatmap
  • plot_symbol_returns
  • plot_yearly_returns
  • plot_rolling_metrics
  • plot_pairs_pnl_dist
  • plot_pairs_hold_dist
  • plot_colored_table
  • plot_stats_comparison
  • plot_segment_comparison
  • plot_key_trades
  • plot_drawdowns_table
  • plot_verdict
  • generate_backtest_report
  • HtmlReportBuilder

建议改造步骤

阶段 1:定义 API 分层文档

新增一份文档,例如 docs/api_surface.md,明确:

  • Canonical cross-language API
  • Python-only API
  • Rust internal API
  • Deprecated / transitional API

验收:文档中每个公开 API 都能对应到 Rust / Python 的暴露位置,或明确标注 Python-only / Rust-internal。

阶段 2:收窄 Rust public surface

把 Rust 内部模块从 public API 中收窄:

  • native_engine 改为 pub(crate) 或私有模块。
  • SoA 结构不再作为稳定 API 暴露。
  • key_trades 内部 helper 不直接暴露,改由 WeightBacktest / BacktestResultCore 方法承载。

验收:Rust docs 里只出现稳定用户 API;内部结构不进入用户文档。

阶段 3:引入 Rust canonical BacktestResultCore

配合 issue #19

  • Rust 定义 BacktestResultCore 作为结果对象 canonical API。
  • Python BacktestResult 变成薄 wrapper。
  • to_dict / to_msgpack / stats / curves 等后续逐步由 Rust core 提供。

验收:Python BacktestResult 与 Rust BacktestResultCore 对同一数据输出一致。

阶段 4:mock 迁移到 Rust

在 Rust 中实现 mock 数据生成:

  • 稳定 seed。
  • 稳定 symbol offset。
  • 与现有 Python mock.py 字段完全一致。
  • 通过 PyO3 暴露给 Python。

Python mock_symbol_kline / mock_weights 改为调用 Rust 实现。

验收:同一参数下,Python API 与 Rust API 生成的数据字段、行数、日期、价格、权重完全一致;用于 README 示例和 benchmark 的 mock 数据只维护一份实现。

阶段 5:评估 Python utils 是否迁 Rust

逐个判断:

  • weights_simple_ensemble:偏核心数据处理,建议迁 Rust 或至少定义 cross-language contract。
  • cal_trade_price:偏量化数据处理,建议迁 Rust 或定义 cross-language contract。
  • log_strategy_info:日志展示辅助,可保留 Python-only。

验收标准

  1. 有明确 API 分层文档。
  2. Rust/Python canonical API 清单一一对应。
  3. Python-only API 明确标注,不再要求 Rust 同步实现。
  4. Rust internal API 不作为稳定 public API 暴露。
  5. mock 由 Rust 单一实现驱动,Python/Rust 共用。
  6. 新增 API 对齐测试:同一输入下,Rust 与 Python canonical API 的关键输出一致。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions