程序员量化交易实战 11:从单只股票扩展到多标的组合回测
程序员量化交易实战 11:从单只股票扩展到多标的组合回测
古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。这个专栏会把一个 A 股量化平台从 0 到 1 拆开写:数据、策略、回测、模拟盘、提醒和生产化,尽量用真实代码和真实运行结果说话。更完整的更新也会同步到微信公众号「字与码」。
第 10 篇跑通了单只股票的最小回测闭环。单标的回测能解释规则,但不能代表策略在股票池上的表现。
这一篇把回测从一只股票扩展到多标的组合。先不做复杂组合优化,只做等权资金分配、逐标的运行、权益曲线聚合和交易统计。简单,但足够把“策略在股票池上跑一遍”这件事落到代码。

组合回测先从等权开始
组合回测有很多复杂问题:调仓周期、权重约束、行业暴露、相关性、成交量容量、现金复用。
这些都重要,但第一版先不要全塞进去。我们先做一个明确边界:
- 输入一组股票代码。
- 每只股票分到相同初始资金。
- 每只股票调用第 10 篇的
run_signal_backtest()。 - 最后把各股票权益曲线按日期相加。

新增组合结果对象
第 11 章新增 app/portfolio_backtest.py。
组合结果对象是:
@dataclass(frozen=True)
class PortfolioBacktestResult:
initial_cash: float
final_equity: float
total_return: float
max_drawdown: float
symbol_results: tuple[MiniBacktestResult, ...]
equity_curve: tuple[dict[str, object], ...]
这里保留 symbol_results,不是只保留聚合指标。因为后面排查策略表现时,必须能知道是哪只股票贡献了收益,哪只股票拖累了回撤。
等权资金分配
核心函数是 run_equal_weight_portfolio_backtest():
cash_per_symbol = initial_cash / len(selected)
results = tuple(
run_signal_backtest(
symbol,
all_bars,
initial_cash=cash_per_symbol,
position_ratio=position_ratio,
)
for symbol in selected
)
这里有两个细节。
第一,symbols 会先去重:
selected = list(dict.fromkeys(symbols))
第二,可以用 max_symbols 限制回测规模,避免本地实验一次跑太大。
聚合权益曲线
单标的回测已经有每日权益。组合层做的是按日期求和:
def _sum_equity_by_date(results: Iterable[MiniBacktestResult]) -> list[dict[str, object]]:
by_date: dict[str, float] = {}
for result in results:
for row in result.equity_curve:
trade_date = str(row["trade_date"])
by_date[trade_date] = by_date.get(trade_date, 0.0) + float(row["equity"])
return [{"trade_date": trade_date, "equity": round(equity, 2)} for trade_date, equity in sorted(by_date.items())]
这仍然是简化版。真实组合回测要处理不同股票停牌、日期不齐、现金共享和调仓。但第一版先让组合权益能跑出来。
交易统计
组合层还加了 portfolio_trade_summary():
{
"symbols": len(result.symbol_results),
"traded_symbols": len(traded_symbols),
"buy_count": buy_count,
"sell_count": sell_count,
"trade_count": buy_count + sell_count,
}
这个摘要很实用。策略如果在 100 只股票上只交易了 1 只,和在 80 只股票上都有信号,是完全不同的解释。
本章更新与代码仓库
本章更新内容:
- 新增
app/portfolio_backtest.py。 - 实现等权多标的组合回测、权益曲线聚合、交易统计和日期裁剪。
- 新增
tests/test_portfolio_backtest.py,覆盖资金分配、去重限额、交易摘要和日期过滤。
代码仓库:
https://github.com/ax2/zi-quant-platform
本章代码:
git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-11
uv sync --extra dev
uv run pytest tests/test_portfolio_backtest.py
第 11 章全量测试通过:172 passed,仍只有既有 FastAPI deprecation warning。
本篇小结
组合回测的第一步不是优化权重,而是把多标的运行链路接上。
等权分配、逐标的回测、权益聚合和交易摘要,让策略可以从单只股票走向股票池。下一篇继续补回测指标,让组合结果不只是一条收益曲线。