5 · 20 分钟

订单类型与执行

市价、限价、止损 — 以及 PortfolioEngine 如何模拟成交。

订单滑点调仓换手率

订单是给券商的指令。新手容易被术语淹没——市价、限价、止损、收盘市价——但在系统化交易中,你通常用 `set_target_weights` 表达*意图*,再由基础设施把它翻译成具体订单。

Definition: Execute now at the best available price.

Pros

Certainty of fill (if liquidity exists).

Cons

Price uncertainty — you pay the spread + slippage.

Quant Buffet: PortfolioEngine rebalances at the daily close with slippage applied — similar to a market-on-close intent.

Daily bar (lab assumption)Close price → engine fill + slippage

真正重要的四种订单

订单类型保证什么放弃什么量化何时使用
市价单一定成交价格流动 ETF 上的小额订单
限价单价格上限 / 下限是否成交清淡标的,或相对成交量偏大的订单
止损(市价)会尝试离场完全放弃价格很少用 — 参见闪崩那一课
收盘市价单(MOC)官方收盘价盘中选择权信号本身*就是*收盘价的日频策略

收盘市价单值得特别关注,因为它最接近实验室的模拟方式。收盘集合竞价通常是美股全天流动性最好的时刻——往往占到全天成交量的约十分之一——所以基于日收盘信号并提交 MOC 订单的策略,恰好是在深度最佳时成交。这是少见的「现实做法同时也是方便做法」的情形。

Quant Buffet 在代码中如何执行

python
def on_day(engine, dt):
    # 目标 60% SPY、40% TLT —— 引擎自动买卖以达到该权重
    engine.set_target_weights(dt, {"SPY": 0.6, "TLT": 0.4})
  • 日收盘价作为调仓参考价。
  • 滑点 2 bps:买入略贵、卖出略便宜。
  • 佣金 5 bps,按每笔成交额收取。
  • 先卖后买,确保买入时现金充足。
  • 权重被下限截断为 0 —— 负权重变成 0(仅做多)。
  • 权重之和超过 1.0 时会按比例缩放,因此你无法意外使用杠杆。
  • 目标权重未变时整笔调仓被跳过,所以每日调用的策略并不会每日付费。

一次完整的调仓计算

初始 10 万美元现金。SPY 收于 500 美元,TLT 收于 90 美元,目标 60/40。

步骤SPYTLT
目标金额60,000 美元40,000 美元
成交价(+2 bps 滑点)500.10 美元90.018 美元
买入股数约 119.98约 444.35
佣金(5 bps)约 30 美元约 20 美元

这次调仓的总摩擦约为 10 万美元上的 62 美元,即约 6.2 bps,一次性成本约 0.06%——可以忽略。但如果你的信号每天都完全翻转呢?

真实示例:换手率如何吃掉一个好信号

策略风格每年往返次数大致年化成本拖累
SPY 上的 200 日均线趋势2–6约 0.03–0.09%
月度动量轮动约 12约 0.2%
周度轮动约 50约 0.7%
日度均值回归、满仓翻转约 250约 3.5% 或更高

算术非常直白:在实验室模型下,每次完整往返约耗 14 bps(卖出与买入各承担 5 bps 佣金 + 2 bps 滑点)。250 次约等于每年 3.5%,且尚未计税。许多已发表的均值回归 edge 毛收益仅值每年 2%–4%——也就是说,仅执行成本就足以吞掉整个信号。每当日频策略表现疲弱,先检查换手率,再怀疑想法本身。

python
# 降低换手率的廉价做法:只在变化足够大时才调仓
state = {"weights": {}}

def on_day(engine, dt):
    target = compute_weights(dt)   # 你的信号
    current = state["weights"]     # 上一次设定的目标权重

    keys = set(target) | set(current)
    drift = sum(abs(target.get(s, 0.0) - current.get(s, 0.0)) for s in keys)
    if drift < 0.05:               # 总偏移小于 5%
        return                     # 直接跳过本次调仓

    state["weights"] = dict(target)
    engine.set_target_weights(dt, target)

仅做多的权重算术

权重含义
{"SPY": 1.0}100% SPY,0% 现金
{"SPY": 0.5, "TLT": 0.5}满仓,等权两分
{"SPY": 0.6, "TLT": 0.3}90% 投资,10% 现金拖累
{"SPY": 0.8, "TLT": 0.8}缩放为 50/50 —— 不允许杠杆
{"SPY": -0.5}截断为 0 —— 不支持做空
{} 或全为 0清仓为现金

进入第 6 课前 — 您应能够

  • 说清四种订单各自放弃了什么。
  • 根据权重、价格、滑点与佣金计算一次调仓的成本。
  • 每年往返次数估算年化成本拖累。
  • 用偏移阈值替代无脑调仓,从而降低换手率。