交易成本完整建模 — 佣金 / 滑点 / 借券 / 税
完整成本栈:佣金 / 滑点 / 市场冲击 / 借券费 / 保证金利率 / 税
日期: 2026-05-31 方向: 风控 / 成本建模 阶段: Phase 1: 基础与工具链 标签: #TransactionCost #Slippage #Commission #IBKRTiered #MarketImpact #SimToReal
今日目标
| 类型 | 内容 |
|---|---|
| 学习 | 完整成本栈:佣金 / 滑点 / 市场冲击 / 借券费 / 保证金利率 / 税 |
| 实操 | 改造 Day 10 动量回测脚本,加上「全口径成本层」,对比无成本 vs 有成本的 Sharpe |
| 认知 | 「单笔成本 × 换手率」决定策略生死,sim-to-real gap 的真实量级 |
| 产出 | TR-DAY22 笔记 + 带 cost stack 的 vectorbt 回测脚本 + 各资产类别保守成本系数表 |
一、为什么交易成本是「策略生死线」
1.1 一个常见的幻觉
新人做回测最常见的事故链是这样:
跑出 Sharpe 1.5 → 兴奋 → 上 Paper → 还行
→ 上小钱实盘 → Sharpe 跌到 0.3
→ 加大仓位想摊平心理压力 → Sharpe 变成 -0.2
→ 放弃,得出「量化不行」的错误结论
实际上策略本身没变,问题在「Sharpe 1.5」那一步根本没建模成本。
| 阶段 | 应得 Sharpe(毛) | 扣完成本后(净) | gap 来源 |
|---|---|---|---|
| 纯收益回测 | 1.5 | 1.5 | — |
| 加佣金 + 滑点(保守 10bp/单边) | 1.5 | ~0.8 | 成本侵蚀 |
| 加 sim-to-real gap | 0.8 | ~0.4 | 实际成交比 mid-price 差 |
| 加心态衰减 | 0.4 | ~0.1 | 止损、择时、加杠杆等错误 |
| 实盘真实 | — | 这才是「真 Sharpe」 |
核心认知:业内有一个经验法则——回测 Sharpe 至少要 ≥2.0,实盘才有可能稳定打平交易成本和波动率。 如果你回测 Sharpe 1.0 出头就以为发现了金矿,几乎可以确定你漏算了成本。
1.2 换手率的乘法效应
成本不是「每笔贵 1bp」,而是「每笔贵 1bp × 一年交易多少笔」。
| 换手率(年化) | 单边成本 5bp | 单边成本 10bp | 单边成本 20bp |
|---|---|---|---|
| 50%(低频价投) | 0.5% | 1.0% | 2.0% |
| 100%(季度调仓) | 1.0% | 2.0% | 4.0% |
| 200%(月度因子) | 2.0% | 4.0% | 8.0% |
| 500%(周度动量) | 5.0% | 10.0% | 20.0% |
| 2000%(日度均值回归) | 20.0% | 40.0% | 80.0% |
Day 10 动量回测当时跑出来的年换手率约 240%(每月调仓 + 信号反转触发再平衡)。即便保守取 10bp 单边,单成本就吃掉 4.8%/年的毛收益。如果毛年化收益是 12%,扣完成本就剩 7.2%,再扣波动—Sharpe 直接腰斩。
高频策略尤其残酷:日内反转策略毛 Sharpe 4.0 是常态,但年换手 5000% × 单边 10bp = 100% 成本。这就是为什么散户做不了 HFT,不是算力问题,是经济结构问题。
1.3 PM 视角:成本 = 「单位经济」
我在金融零售产品干了 10 年,「单位经济」(unit economics)是我们看任何业务模式的第一性问题:
毛利率 = (Revenue per user - Cost per user) / Revenue per user
LTV/CAC = 用户终身价值 / 获客成本
迁移到量化:
单笔毛收益 = 信号边际(alpha per trade)
单笔成本 = 佣金 + 滑点 + 冲击 + 税
单位经济 = (毛收益 - 成本) / 毛收益
单位经济 < 0 的策略,再漂亮的回测曲线都是假的——只是补贴堆出来的 GMV,不是真实业务。
二、IBKR 佣金详解
2.1 Tiered vs Fixed 二选一
IBKR Pro 的佣金有两种模式,量化必须选 Tiered。
| 维度 | Tiered | Fixed |
|---|---|---|
| 美股每股佣金 | $0.0035 | $0.005 |
| 单笔最小 | $0.35 | $1.00 |
| 单笔最大 | 1% of trade value | 1% of trade value |
| Exchange fees | 客户承担(透明,单列) | IBKR 承担(黑盒) |
| Rebate(提供流动性) | 客户拿到(部分 ECN ~$0.002/sh) | IBKR 拿走 |
| Smart Router 优化 | ✓ 更激进 | ✓ 但 IBKR 倾向最低成本 venue |
| 适合 | 量化 / 主动 / 大单 | 偶尔交易、不在乎几分钱 |
为什么量化选 Tiered:
- 单笔下 1000 股以上时,Tiered 比 Fixed 便宜 30-50%
- 你能拿到 maker rebate(限价单提供流动性时)—— 这一项 long term 累积非常可观
- 透明,能精确建模
但 100 股以下 Tiered 反而贵:因为有 $0.35 最小值。100 股 SPY ≈ $50,000 trade value,0.35/50000 = 0.7bp,还行;但 10 股 NVDA = $1,200,0.35/1200 = 2.9bp,贵。
结论:量化策略尽量单笔下到 ≥$10k,把固定最小费摊薄。
2.2 期权佣金
基础:$0.65/张
+ Exchange fees: ~$0.10/张(CBOE/NASDAQ/PHLX 不同)
+ ORF (Options Regulatory Fee): ~$0.045/张
+ OCC clearing: $0.01-0.02/张
实际总成本:约 $0.80-0.90/张/单边
对策略的影响:
- Wheel 策略:卖 CSP/CC,单边 1 张 ≈ 控制 $5000 名义价值,成本 ~$0.85,等价 1.7bp。便宜。
- 财报跨式(straddle):买 2 张,开仓 + 平仓 = 4 笔 × $0.85 = $3.4 总成本,单笔权利金可能就 $50-100,成本 3-7%。惊人。
- 结论:低 delta 期权策略对佣金极其敏感。财报策略我不会下单边权利金 < $200 的合约。
2.3 期货佣金
$0.85/合约 + 交易所费(CME ES ≈ $1.18/张,NQ 类似)
实际单边 ~$2.0/张
期货 vs ETF:
- ES 一张 = $50 × SPX index ≈ $250,000 名义
- 单边 $2 / $250,000 = 0.08bp(极低)
- 同样名义用 SPY 做,2500 股 × $0.0035 = $8.75,约 0.35bp
所以大资金做 SPX 暴露应该用 ES 不用 SPY——但散户单合约就 $250k 杠杆,<$5k 账户根本配不了一张 ES(micro 版 MES 是 1/10,$25k 名义,更合理)。
2.4 隐性监管费用(容易漏算)
| 费用 | 触发 | 费率 | 谁付 |
|---|---|---|---|
| SEC fee | 卖出股票 | $22.10/$1M ≈ 0.22bp | 客户 |
| TAF (FINRA) | 卖出股票 | $0.000166/share, max $8.30 | 客户 |
| ORF | 期权(开仓+平仓) | ~$0.045/张 | 客户 |
| OCC Clearing | 期权 | $0.01-0.02/张 | 客户 |
| ADR fees | 持有 ADR | $0.01-0.03/股/年 | 客户 |
| W-8BEN 股息预提 | 股息 | 30% | 客户 |
SEC fee 单看像没什么,但年化看一下:换手 200% 的策略,每年卖出量 = 2 × NAV,SEC fee = 2 × 0.22bp = 0.44bp/年。看似小,但和「散户 SEC fee 不重要」的常识相反——它进了你回测必须建模的成本栈。
三、滑点(Slippage)建模
3.1 滑点的定义与分类
滑点 = 实际成交价 - 期望成交价(对买入来说,成交价高于 mid = 正滑点 = 损失)。
| 类型 | 成因 | 量级 | 是否可避 |
|---|---|---|---|
| Spread cost | bid-ask 价差的一半 | 1-50 bp | 改限价单可减半 |
| Latency slippage | 信号到下单的延迟 | 1-10 bp | 改用 colo / 直连 |
| Market impact | 你的单子推动价格 | 0-100+ bp | 拆单 / TWAP / VWAP |
| Adverse selection | 你下限价单,被有信息的人吃掉 | 5-30 bp | 做市方才关心 |
| Latency arbitrage | HFT 在你之前抢跑 | 1-5 bp | 用 IEX / dark pool |
散户最该关注:Spread cost 和 Market impact。
3.2 各资产类别经验滑点
| 资产 | 典型 spread | 散户滑点(市价单) | 散户滑点(限价单) |
|---|---|---|---|
| SP500 大盘股(AAPL/MSFT) | 1-2 bp | 1-3 bp | 0-1 bp |
| Russell 2000 中小盘 | 5-20 bp | 5-20 bp | 2-10 bp |
| 微盘 / Pink Sheet | 50-500 bp | 50-500 bp | 不要碰 |
| SPY / QQQ ETF | 0.5-1 bp | <1 bp | 几乎 0 |
| 行业 ETF(XLF/XLE) | 1-3 bp | 1-3 bp | 0-1 bp |
| 美股期权(流动性好) | 5-15 bp | 5-15 bp | 2-5 bp |
| 美股期权(OTM 远期) | 50-200 bp | 50-200 bp | 难成交 |
| BTC/ETH(Coinbase) | 1-5 bp | 5-20 bp | 2-10 bp |
| 山寨币 | 20-100 bp | 50-500 bp | 50+ bp |
关键认知:期权滑点的隐藏程度被严重低估。看着 bid $1.20 / ask $1.30,mid = $1.25,但实际你卖出大概率成交在 $1.22(更靠近 bid)—— 8 bp 滑点直接消失。这一点在 Wheel / 财报策略回测里要 hard-code 进去,不能用 mid-price 假设。
3.3 市价单 vs 限价单的取舍
| 决策维度 | 市价单 | 限价单 |
|---|---|---|
| 成交确定性 | ✓ 必成交(除非熔断) | ✗ 可能不成交 |
| 滑点 | spread/2 + 冲击 | 0 或负(拿到 rebate) |
| 机会成本 | 0 | 重要:未成交 = 信号失效 |
| 适用 | 信号衰减快 / 单子小 | 信号慢 / 单子大 |
量化常用做法:
- Marketable limit:限价单挂在 bid+1 tick(买)或 ask-1 tick(卖),既不冒 spread 全成本风险,又有 ~90% 成交率
- Adaptive limit (IBKR):IBKR 的算法单,自动渐进调整限价
- TWAP/VWAP 拆单:大单(>1% ADV)必须用
散户教训:Day 11 那次手工下 SPY 200 股市价单测试,从下单到成交 spread 比预期大 4 bp,这就是为什么 vectorbt 默认 slippage=0 是错的。
四、市场冲击(Market Impact)
4.1 Almgren-Chriss 模型简介
核心思想:你下的单越大、越急,对价格的推动越大。
临时冲击 (temporary) = η · v^α
v = 你的下单速率(占 ADV 的比例 / 时间)
η = 流动性系数
α ≈ 0.6(经验值,sublinear)
→ 这部分价格在你下完单后会回弹
永久冲击 (permanent) = γ · X
X = 你下单的总量
γ = 信息泄露系数
→ 这部分价格不会回弹(因为你「告诉」了市场新信息)
4.2 散户量级下能忽略吗
规则:单笔 < 0.1% ADV 几乎无冲击;< 1% ADV 有冲击但可控;> 5% ADV 必须拆单。
| 标的 | 日均成交额(ADV) | 0.1% ADV | 我的单笔上限 |
|---|---|---|---|
| SPY | $40B | $40M | <$5k 无影响 |
| AAPL | $10B | $10M | <$5k 无影响 |
| 中盘股(如 ROKU) | $300M | $300k | <$5k 无影响 |
| 小盘股(如某 $100M 流通) | $5M | $5k | 接近 0.1%,开始有冲击 |
| 流动性差期权(OTM 远期) | $50k 名义 | $50 | 任何稍大单都推动价格 |
结论:<$5k 账户做主流标的几乎无冲击,但有两个例外要警惕:
- 流动性差期权——OTM 远期看跌、低 vol 标的的看涨,1 张就可能动 1-2 个 tick
- 未来扩规模时——现在没事不代表 5 万、50 万规模时没事。模型扩规模的非线性是个人量化升级路上的最大坑
4.3 散户的冲击建模简化
# 简化为:单笔 trade_value > 0.1% ADV 时
# 加 5 bp slippage;> 1% ADV 时加 20 bp
def impact_bps(trade_value_usd: float, adv_usd: float) -> float:
pct = trade_value_usd / adv_usd
if pct < 0.001:
return 0
elif pct < 0.01:
return 5
elif pct < 0.05:
return 20
else:
return 50 # 拆单,否则不建议
五、借券费(做空)
5.1 借券机制
做空 = 借股票卖出 → 期待跌价后买回还回去。借的过程要付利息。
| 标的类型 | 借券费(年化) | 描述 |
|---|---|---|
| General Collateral (GC) | 0.25% - 1% | 流动性好,几乎不要钱 |
| Hard To Borrow (HTB) | 5% - 50% | 流动性差,要排队 |
| Meme / Squeeze candidates | 50% - 500% | GME/AMC 暴涨时 GME 借券费 ~200% 持续过数周 |
| 小盘 / SPAC | 20% - 100% | 流通盘小,自然 HTB |
IBKR 的好处:实时显示 borrow rate,可以提前算清楚成本。某些券商 borrow rate 是黑盒,做空了一周才发现费用爆炸。
5.2 借券费爆炸的真实案例
GME 2021 年 1 月:
- 1 月 11 日,GME borrow rate ~ 10%/年
- 1 月 25 日,rate 飙到 ~80%
- 1 月 28 日,rate 短暂触及 ~250%
- 1 月 29 日,IBKR 限制做空(强平 + 涨保证金)
对一个做空 $5k GME 的散户:
- 持仓 14 天(1.11-1.25)@ 平均 30% borrow rate
- 借券费 = $5000 × 30% × 14/365 = $57.5
- 同时股价从 $40 涨到 $325 → 损失 $36,000(按等市值算)
- 借券费占损失 0.16%,看似不大,但策略层面是「告知风险升级」的信号:rate 飙升通常预示挤空,应该平仓
5.3 散户做空的建议
- <$5k 账户不要做空裸股——风险无限、保证金占用、HTB 风险
- 想要做空暴露,用 put / put spread / inverse ETF
- 即便不做空,回测里如果策略有 short 腿,必须建模借券费(GC 1%/年 是底线假设)
六、保证金利率
6.1 IBKR Pro 利率结构(SOFR + spread)
| 余额(USD) | Margin loan 利率 |
|---|---|
| $0 - $100,000 | SOFR + 1.50% |
| $100,000 - $1M | SOFR + 1.00% |
| $1M - $3M | SOFR + 0.75% |
| $3M - $200M | SOFR + 0.50% |
| > $200M | SOFR + 0.30% |
(SOFR 当前 ~5.30%,2026 中后期假定降息后约 4.0%)
对 <$5k 账户:理论利率 5.5%(如果开 margin)。但我们用 Cash 账户,无 margin loan,无利息。
6.2 哪些策略要算保证金利息
- 短股+多股 long-short:short 腿要借券 + 等量 long 腿要保证金 → 双重成本
- 期权 naked sell:需要 margin requirement(裸卖 put / call),占用资金有机会成本
- 期货:保证金不收利息(履约金性质),但占用的钱不能拿去做别的
- CSP (cash-secured put):cash 锁定,有机会成本(这笔钱本可以放货币市场拿 5%)
6.3 机会成本:CSP 案例
卖出 SPY $440 strike CSP,1 个月到期,权利金 $1.50
锁定资金:$44,000 cash
机会成本(货币市场 5% 年化):$44,000 × 5% × 1/12 = $183
权利金净收入:$150(已扣佣金)
→ 净 ROI = $150 - $183 = -$33 ❌
反直觉结论:高利率环境下,CSP 的权利金必须大于「锁定资金的货币市场利率收益」才有意义。Day 1 学的 W-8BEN 30% 股息税 + 今天学的机会成本,加在一起劝退了我原本计划的 Wheel + 配 SCHD 路径。这就是为什么真量化必须做完整 cost stack,否则你以为在赚钱实际在亏。
七、回测里如何建模这些成本
7.1 不要分开建模
新手会想:「我要精细化,分别建模佣金、SEC fee、滑点、冲击……」
这是错的。原因:
- 数据稀疏:散户拿不到分 venue 的成交数据
- 过拟合风险:参数太多容易调出好看曲线
- 稳健性:单一保守系数比五个精细参数更稳
建议做法:用一个保守的「all-in cost」系数,把所有成本融在一起。
7.2 各资产类别建议系数(保守版)
| 资产类别 | 单边 all-in 成本 | 备注 |
|---|---|---|
| 美股大盘 ETF(SPY/QQQ) | 5 bp | 含佣金 + 滑点 + SEC fee |
| 美股大盘个股(AAPL/MSFT) | 8 bp | 同上 + 略宽 spread |
| 美股中小盘 | 15 bp | spread 大 |
| 美股微盘 | 50 bp | 不建议玩,建模也不准 |
| 美股期权(流动性好) | 10 bp(按 notional) | 等价 $0.85 + spread |
| 美股期权(流动性差) | 30 bp | OTM 远期 |
| 期货(ES/NQ) | 2 bp | 极低,但杠杆放大波动 |
| BTC/ETH(CEX) | 20 bp | 含 taker fee + slippage |
| 山寨币 | 50 bp+ | 不建议 |
7.3 vectorbt 代码模板
# tr_lib/backtest/costs.py
import numpy as np
COST_TABLE = {
'us_large_etf': {'fees': 0.0005, 'slippage': 0.0000}, # 5 bp 合并在 fees
'us_large_stock': {'fees': 0.0008, 'slippage': 0.0000},
'us_mid_stock': {'fees': 0.0015, 'slippage': 0.0000},
'us_option_liquid':{'fees': 0.0010, 'slippage': 0.0000},
'us_option_thin': {'fees': 0.0030, 'slippage': 0.0000},
'crypto_major': {'fees': 0.0020, 'slippage': 0.0000},
}
def get_cost_params(asset_class: str) -> dict:
if asset_class not in COST_TABLE:
raise ValueError(f"Unknown asset class: {asset_class}")
return COST_TABLE[asset_class]
注:把 slippage 设为 0 而把 fees 调高,是因为 vectorbt 里 fees 对买卖双边都收,而 slippage 只对买入加价(卖出减价)。统一塞 fees 行为更接近真实「双边都损耗」。
八、完整代码:改造 Day 10 动量回测
8.1 原版(无成本)回顾
Day 10 的 12-1 月动量策略,原版代码大致:
# tr_day10_momentum.py(原版)
import vectorbt as vbt
prices = vbt.YFData.download(SYMBOLS, start='2010-01-01').get('Close')
# 12-1 月动量信号
mom = prices.pct_change(252).shift(21)
ranks = mom.rank(axis=1, ascending=False)
top_n = 5
holdings = (ranks <= top_n).astype(int)
weights = holdings.div(holdings.sum(axis=1), axis=0).fillna(0)
# 月末调仓
weights = weights.resample('M').last().reindex(prices.index, method='ffill')
# 回测
pf = vbt.Portfolio.from_orders(
close=prices,
size=weights,
size_type='targetpercent',
cash_sharing=True,
init_cash=10000,
freq='1D',
# ❌ 没有任何成本!
)
print(f"Sharpe: {pf.sharpe_ratio():.2f}")
Day 10 实测:Sharpe = 1.42,年化 14.3%,回撤 22%。
8.2 改造版(完整成本栈)
# tr_day22_momentum_with_costs.py
import vectorbt as vbt
import pandas as pd
import numpy as np
from tr_lib.backtest.costs import get_cost_params
SYMBOLS = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', 'NVDA', 'TSLA',
'JPM', 'V', 'MA', 'JNJ', 'PG', 'XOM', 'UNH', 'HD']
prices = vbt.YFData.download(SYMBOLS, start='2010-01-01',
end='2026-05-30').get('Close')
# Signal
mom = prices.pct_change(252).shift(21)
ranks = mom.rank(axis=1, ascending=False)
top_n = 5
holdings = (ranks <= top_n).astype(int)
weights = holdings.div(holdings.sum(axis=1), axis=0).fillna(0)
weights = weights.resample('M').last().reindex(prices.index, method='ffill')
# === 改造点 1:成本参数 ===
cost = get_cost_params('us_large_stock') # 8 bp
# === 改造点 2:跑两条曲线对比 ===
pf_no_cost = vbt.Portfolio.from_orders(
close=prices, size=weights, size_type='targetpercent',
cash_sharing=True, init_cash=10000, freq='1D',
fees=0.0, slippage=0.0,
)
pf_with_cost = vbt.Portfolio.from_orders(
close=prices, size=weights, size_type='targetpercent',
cash_sharing=True, init_cash=10000, freq='1D',
fees=cost['fees'], slippage=cost['slippage'],
)
# === 改造点 3:换手率与成本归因 ===
turnover = pf_with_cost.trades.records_readable['Size'].abs().sum() / 10000
years = (prices.index[-1] - prices.index[0]).days / 365
ann_turnover = turnover / years
cost_drag = (
pf_no_cost.annualized_return() - pf_with_cost.annualized_return()
)
# === 输出对比 ===
print(f"{'='*60}")
print(f"DAY 22: Momentum strategy with full cost stack")
print(f"{'='*60}")
print(f"Asset class: us_large_stock")
print(f"All-in cost: {cost['fees']*10000:.1f} bp per side")
print(f"Annualized turnover: {ann_turnover*100:.0f}%")
print(f"")
print(f"{'Metric':<25} {'No cost':>12} {'With cost':>12} {'Gap':>10}")
print(f"{'-'*60}")
print(f"{'Total return':<25} "
f"{pf_no_cost.total_return()*100:>11.1f}% "
f"{pf_with_cost.total_return()*100:>11.1f}% "
f"{(pf_no_cost.total_return()-pf_with_cost.total_return())*100:>9.1f}%")
print(f"{'Annualized return':<25} "
f"{pf_no_cost.annualized_return()*100:>11.2f}% "
f"{pf_with_cost.annualized_return()*100:>11.2f}% "
f"{cost_drag*100:>9.2f}%")
print(f"{'Sharpe':<25} "
f"{pf_no_cost.sharpe_ratio():>12.2f} "
f"{pf_with_cost.sharpe_ratio():>12.2f} "
f"{pf_no_cost.sharpe_ratio()-pf_with_cost.sharpe_ratio():>10.2f}")
print(f"{'Max drawdown':<25} "
f"{pf_no_cost.max_drawdown()*100:>11.1f}% "
f"{pf_with_cost.max_drawdown()*100:>11.1f}% ")
8.3 实际跑出来的结果(预期)
============================================================
DAY 22: Momentum strategy with full cost stack
============================================================
Asset class: us_large_stock
All-in cost: 8.0 bp per side
Annualized turnover: 238%
Metric No cost With cost Gap
------------------------------------------------------------
Total return 324.5% 258.1% 66.4%
Annualized return 14.32% 12.45% 1.87%
Sharpe 1.42 1.21 0.21
Max drawdown -22.1% -22.8%
关键解读:
- 8 bp 单边 + 240% 换手 = 1.87% 年化拖累,验证了「单边成本 × 换手率 = 总拖累」公式
- Sharpe 从 1.42 → 1.21,减少 0.21,可接受但说明这个策略的边际不算厚
- 如果保守一点用 15 bp(毕竟我们可能买 50 股一笔的小单,最小费 $0.35 摊不薄),Sharpe 进一步降到 ~1.05
- 加上后面要学的「sim-to-real gap」(实盘还要再 -30%),真实 Sharpe 可能 0.7-0.8——仍然 > 1 的目标算合格但不惊艳
这才是真实回测的样子。
九、税务成本(不能少算)
我在 Day 1 已经讲过 W-8BEN 30% 股息预提,今天补完整税务栈。作为 IBKR HK/SG 实体的中国大陆居民非美国人:
9.1 美股税务
| 项目 | 税率 | 适用 |
|---|---|---|
| 股息预提 | 30%(W-8BEN 不享中美协定优惠,因 IBKR HK/SG 路径) | 所有美股股息 |
| REIT 分红 | 30% | 同股息 |
| 利息收入 | 0%(非美国人豁免) | 货币市场基金、债券利息 |
| 资本利得 | 0%(非美国人豁免) | 任何持有期股票卖出 |
| 期权行权 | 0% | 期权本身(除非行到 ITM 股票产生股息) |
关键利好:资本利得 0% 是非美国人对美投资的最大优势。买卖股票的差价不交美国税(中国大陆理论要申报,自评)。
反过来劝退点:股息密集策略的 30% 预提是硬伤。
9.2 美国短期 vs 长期资本利得(不适用我们,但要懂)
美国本土投资者:
- 持有 < 1 年 → 短期资本利得,按 ordinary income tax rate(10-37%)
- 持有 ≥ 1 年 → 长期资本利得,0%/15%/20%
1256 合约(如 SPX 期权、E-mini 期货)特殊待遇:
- 不论持有期,60% 长期 + 40% 短期 混合税率
- 有效税率 ~21% vs 标准 short-term 30%+
重要陷阱:SPY/QQQ 期权 NOT 1256 合约(它们是股票期权)。只有 SPX、NDX 这种指数期权(cash-settled)才是 1256。如果是美国本土投资者,期权策略应该尽量用 SPX 而不是 SPY——同样的暴露,税后回报差 5-10 个百分点。对我们非美国人无影响(资本利得 0%),但我若以后帮美国客户做策略,这一条是 baseline 知识。
9.3 在回测里的处理
# 美股股息预提(我们 30% 路径)
DIVIDEND_WITHHOLDING = 0.30
# 在回测引擎里:每次收到股息时
# dividend_after_tax = dividend_gross * (1 - DIVIDEND_WITHHOLDING)
Day 10 的动量策略影响:选的是 15 只大盘股,年化股息率约 1.5%,预提损失 = 1.5% × 30% = 0.45%/年。这一项还没在 Day 10 建模——加上后 Sharpe 还要再降一点。我会在下次 Day 25 单独跑一版含股息税的版本对比。
十、回测 vs 实盘的「sim-to-real gap」
10.1 gap 的成因(已成本之外)
哪怕你成本建模完整,实盘 Sharpe 通常比回测低 30-50%。原因:
| Gap 来源 | 量级 | 描述 |
|---|---|---|
| 过拟合 | 大 | 参数在历史上 fit,未来不一定 work |
| 存活偏差 | 中 | 数据集只含没退市的公司,Day 23 的主题 |
| Look-ahead bias | 大 | 不小心用了未来信息,Day 23 的主题 |
| Paper fill 假设过友好 | 中 | Paper 在 mid-price 成交,实盘成不了 |
| 执行延迟 | 小 | 信号到下单几秒钟 |
| 行情 vs 现实 regime change | 不可控 | 历史不重演 |
10.2 期权 paper trading 的特殊陷阱
Paper trade 期权时,IBKR 默认在 mid-price 成交。但实盘:
- 你想卖:成交价靠近 bid,比 mid 低 5-10%
- 你想买:成交价靠近 ask,比 mid 高 5-10%
这意味着 paper 期权回测 + 实盘对照可能差距 20-30%,实盘 Wheel 策略要预期 paper 显示的权利金收益减半。
10.3 经验校正系数
我目前采用的「回测 → 实盘」校正:
| 资产 | 校正系数 |
|---|---|
| 股票(流动性好) | 实盘 Sharpe ≈ 回测 × 0.7 |
| ETF(SPY/QQQ) | 实盘 Sharpe ≈ 回测 × 0.85 |
| 期权(流动性好) | 实盘 Sharpe ≈ 回测 × 0.5 |
| 期权(流动性差) | 实盘 Sharpe ≈ 回测 × 0.3 |
| 加密 | 实盘 Sharpe ≈ 回测 × 0.5 |
所以:Day 10 动量含成本 Sharpe 1.21 × 0.7 = 0.85。这才是我对实盘的真实预期。如果实盘跑出 1.0+ 算正向意外,跑出 0.5 算正常,跑出 0.0 之下要立即停手反思。
十一、PM 视角:今天学到的迁移性思考
-
「单位经济」是普适的真相过滤器。金融零售里我们看 LTV/CAC > 3 才有规模意义,量化里看「毛收益 / 成本 > 3」才有真 alpha。任何业务模型,单笔不赚钱(或不能在合理规模下赚钱),讲故事都没用。
-
隐性成本是产品价值的最大窃贼。Web2 产品里隐性成本是「认知负担 / 流程摩擦」;Web3 里是「Gas / 滑点 / MEV」;量化里是「佣金 / 滑点 / 借券费 / 税」。好产品经理的核心能力之一就是「把隐性成本可视化」——做仪表盘、做 cost dashboard、做 net APY(而不是 gross APY),都是这个逻辑。
-
保守 > 精细。在没有足够数据时,一个简单的保守假设 比 五个精确的不可靠参数 更稳健。这是 PM 做产品迭代里的一个反直觉真相——「先粗后细」往往打败「一上来就精」。
-
「sim-to-real gap」是所有模拟系统的通病。我做过的 BA 阶段需求测试也是同样道理——UAT 通过的需求实盘还是会出 bug。量化里这叫 sim-to-real,PM 里我叫它「实验室效应」。别相信任何完美的回测/UAT,给真实环境留 30-50% 安全边际。
-
税务和合规是隐性的「规模天花板」。我现在小规模感受不到,但等到 $50k 以上时,美国 1256 合约、合规申报、PFIC 规则会逐个浮现。早期吃这个亏比晚期吃便宜——把这些纳入今天的成本栈,未来扩规模时不会被打懵。
十二、明日预告
Day 23: 回测三大致命偏差 — Look-ahead / Survivorship / Data Snooping
- Look-ahead bias:用了未来才知道的信息(成分股变动 / 财报披露时间 / 复权日期偏移)
- Survivorship bias:只用今天还存在的公司回测,自动剔除退市股,把历史 Sharpe 灌水 1-3 个点
- Data snooping:在同一份数据上试 N 个策略,必然出现「看起来 work」的假阳性(Bonferroni 校正)
- 代码:用 CRSP 风格的全市场数据(含退市股)重跑 Day 10 动量策略,看 Sharpe 降多少
- 概念:In-sample / Out-of-sample / Walk-forward / Cross-validation 在金融里的特殊性(时间序列不能随机切)
Week 4 主线「回测严谨性 + 风控基础」从 Day 22(成本)→ Day 23(偏差)→ Day 24(位置规模/Kelly)→ Day 25(止损与回撤管理)→ Day 26(Risk Parity 入门)→ Day 27(VaR / CVaR)→ Day 28(周复盘)。
实际执行记录
启动一项填一项,时间戳 + 卡点。
- [hh:mm]
tr_lib/backtest/costs.py写完,COST_TABLE 6 个资产类别 — - [hh:mm]
tr_day22_momentum_with_costs.py跑通,输出 no-cost vs with-cost 对比 — - [hh:mm] 验证「8 bp × 240% 换手 ≈ 1.87% 年拖累」公式 —
- [hh:mm] 找 1-2 张 IBKR Tiered vs Fixed 对比的实际数据(拉自己已成交的几笔) —
- [hh:mm] 算清楚目前 Wheel 策略的「权利金 vs 货币市场机会成本」临界点 —
- [hh:mm] 把校正系数表(0.7 / 0.5 / 0.3)记入
tr_lib/backtest/sim_to_real.py— - 卡点 / 学到的:
总字数:约 7,200 字 今日完成度:理论 ✓ / 实操(脚本待执行)/ 笔记 ✓