第 4 章 · 02 Zipline 均值回归多空策略(对应 QS045)


文档摘要

第 4 章 · 02 Zipline 均值回归多空策略(对应 QS045) 速查摘要:Zipline 是 Quantopian 的回测引擎,以 Pipeline(批量算因子) + CustomFactor(自定义因子) + schedulefunction(调仓) 三件套闻名。本节是一个教科书级的均值回归多空策略:用 21 日窗口的标准化 Z-score 给股票排序,做多最便宜的 5 只(bottom)、做空最贵的 5 只(top),月末市场开盘调仓,市场中性。是"用 Zipline 把因子变成策略"的标准模板。 涉及脚本:原项目 (约 132 行) ⚠️ 注意:Zipline 已停止官方维护,装在 Python 3.8 上最稳; 需要先 数据(社区版可用 或自建 bundle)。

第 4 章 · 02 Zipline 均值回归多空策略(对应 QS045)

速查摘要:Zipline 是 Quantopian 的回测引擎,以 Pipeline(批量算因子) + CustomFactor(自定义因子) + schedule_function(调仓) 三件套闻名。本节是一个教科书级的均值回归多空策略:用 21 日窗口的标准化 Z-score 给股票排序,做多最便宜的 5 只(bottom)、做空最贵的 5 只(top),月末市场开盘调仓,市场中性。是"用 Zipline 把因子变成策略"的标准模板。

涉及脚本:原项目 QS045-mean-reversion/01_mean_reversion.py(约 132 行)

⚠️ 注意:Zipline 已停止官方维护,装在 Python 3.8 上最稳;bundle="quotemedia" 需要先 ingest 数据(社区版可用 quandl-eod 或自建 bundle)。运行需在 Zipline 沙箱内,纯 pandas 环境跑不起来。

工具与原理

均值回归(mean reversion):价格短期偏离会回归均值的假设。涨太多的(超买)容易跌,跌太多的(超卖)容易反弹。本节用每日收益衡量"偏离"——最近一日收益显著高于 21 日均值的,认为是"涨过头",做空;反之做多。

Z-score 标准化:把每个值减去均值再除以标准差,得到"以标准差为单位的偏离度":

z = (x - mean) / std

z > 0 表示高于均值,z < 0 表示低于均值。脚本里 df.iloc[-1].sub(df.mean()).div(df.std()) 就是把"最新日收益"做 Z-score 化,数值越大越超买。

市场中性多空组合:同时持有多头(bottom 5,等权各 20%)和空头(top 5,等权各 20%),组合总仓位约 2(多头 100% + 空头 100%)。多空对冲掉系统性 beta,只赚"价格回归"那一部分。极端市场(全市场单边暴跌)多空都亏也罕见,所以称"市场中性"。

月末调仓:每月最后一个交易日市场开盘时,rebalance 一次。频次适中(不会因高频交易被手续费侵蚀),又能及时轮换持仓。

VWAP 价格过滤:用 21 日成交量加权均价(VWAP)> 15 美元过滤掉仙股(penny stocks),仙股流动性差、容易被操纵、做空难,不适合均值回归。

脚本精读

CustomFactor 三件套——inputs(输入)+ window_length(窗口)+ compute(计算):

class MeanReversion(CustomFactor): inputs = [Returns(window_length=21)] window_length = 21 def compute(self, today, assets, out, monthly_returns): df = pd.DataFrame(monthly_returns) out[:] = df.iloc[-0].sub(df.mean()).div(df.std())

Returns(window_length=21) 内置因子,提供过去 21 日的每日收益率。window_length=21 表示这个 CustomFactor 看最近 21 个交易日的数据。compute 把传进来的 monthly_returns(shape = [21, num_assets])转 DataFrame,把"最新一日"(iloc[-0]iloc[-1],Python 里 -0 == 0,这里作者写法略怪但语义是"取最新行")减去均值再除标准差,结果写入 out(Zipline 要求用 out[:] = 而非 return)。

Pipeline 选股——多空两侧 + 过滤:

def compute_factors(): mean_reversion = MeanReversion() vwap = VWAP(window_length=21) pipe = Pipeline( columns={ "longs": mean_reversion.bottom(5), # Z-score 最低的 5 只(超卖) "shorts": mean_reversion.top(5), # Z-score 最高的 5 只(超买) "ranking": mean_reversion.rank(), }, screen=vwap > 15.0 ) return pipe

bottom(5) 取因子最小的 5 个,top(5) 取最大的 5 个。screen 把 VWAP<=15 的股票全部排除出 Pipeline 输出。

调仓逻辑——清掉不在新名单里的 + 等权多空:

def rebalance(context, data): factor_data = context.factor_data assets = factor_data.index longs = assets[factor_data.longs] shorts = assets[factor_data.shorts] divest = context.portfolio.positions.keys() - longs.union(shorts) exec_trades(data, assets=divest, target_percent=0) exec_trades(data, assets=longs, target_percent=1 / len(longs) if len(longs) > 0 else 0) def exec_trades(data, assets, target_percent): for asset in assets: if data.can_trade(asset): order_target_percent(asset, target_percent)

divest 是"既不在新多单也不在新空单里"的旧持仓,先清零。order_target_percent(asset, target) 是 Zipline 的招牌——目标权重撮合,直接说"我要这只想占 20%",引擎自己算差额下单。

initialize 注册 Pipeline + 调度:

def initialize(context): attach_pipeline(compute_factors(), "factor_pipeline") schedule_function( rebalance, date_rules.month_end(), time_rules.market_open(), calendar=calendars.US_EQUITIES, )

month_end() + market_open() = 每月最后一天开盘调仓。attach_pipeline 把 Pipeline 注册成"name",before_trading_start 里用 pipeline_output("factor_pipeline") 取当日选股结果。

跑回测:

start = pd.Timestamp("2020-01-01") end = pd.Timestamp("2024-07-01") capital_base = 25_000 perf = run_algorithm( start=start, end=end, initialize=initialize, capital_base=capital_base, before_trading_start=before_trading_start, bundle="quotemedia", ) perf.portfolio_value.plot()

初始 2.5 万美元,2020-01 到 2024-07 共 4 年半,最后画组合净值曲线。

关键技巧

  1. CustomFactor 三件套(inputs / window_length / compute)是 Zipline 自定义因子的标准范式,computeout[:] = 不能写成 return
  2. Pipeline 的 bottom(N) / top(N) / rank() 直接给"分位数选股"——配合 screen 过滤,选股逻辑一句话搞定。
  3. order_target_percent 是目标权重撮合,关注"我要这只想占多少比例"而非"下多少股",Zipline 自动算差额。
  4. schedule_function + date_rules.month_end() + time_rules.market_open() 是 Zipline 的事件调度三件套,日历(calendars.US_EQUITIES)指定交易日历。
  5. 多空市场中性:多头等权(各 1/N)、空头等权(各 1/N),divest 清掉不在新名单的旧仓——这套 rebalance 模板可复用到任何截面选股策略。

💡 速查要点:Zipline 因子策略范式 = CustomFactor 定义因子 → Pipeline 选股(bottom/top + screen) → schedule_function 调度 → rebalance 用 order_target_percent 等权多空。本月信号次月初 / 月末调仓是常见频率,市场中性 = 多头等权 + 空头等权 + 系统对冲。

本节要点

  1. Zipline 三件套:CustomFactor(自定义因子,inputs/window_length/compute)→ Pipeline(选股,bottom/top/screen)→ schedule_function(调度调仓)。
  2. 均值回归 = Z-score 标准化,数值越大越超买(做空),越小越超卖(做多)。
  3. order_target_percent 是目标权重撮合,直接给"想要的比例",引擎算差额下单。
  4. 市场中性多空:多头等权 + 空头等权 + VWAP 过滤仙股 + 月末调仓,是截面选股策略的标准模板。
  5. 跑回测需要先 ingest bundle(quotemedia/quandl-eod),Zipline 已停维护,Python 3.8 最稳。

作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U