完整回测 2010-2024 + 税前/税后净值
回测期跨周期覆盖逻辑、美国对非居民的税务体系(W-8BEN 30% 股息预提 / 美籍资本利得豁免 / 美籍短长期分割)、税务对不同策略风格的差异化侵蚀
日期: 2026-06-11 方向: Phase 2 / 回测扩展 阶段: Phase 2: 策略实战 + AI 信号 标签: #Backtest #Tax #DividendWithholding #W8BEN #CapitalGains #PreTaxPostTax
今日目标
| 类型 | 内容 |
|---|---|
| 学习 | 回测期跨周期覆盖逻辑、美国对非居民的税务体系(W-8BEN 30% 股息预提 / 美籍资本利得豁免 / 美籍短长期分割)、税务对不同策略风格的差异化侵蚀 |
| 实操 | 把 Day 28 双因子组合的回测期从 2014-2024 拉长到 2010-2024,加入逐笔股息预扣模块,跑出税前 vs 税后两条净值曲线 |
| 产出 | 可运行的税务建模代码 + 14 年完整结果表 + 税前/税后 Sharpe 对比 + 三种 ETF 风格的差异化分析 + paper 决策 |
一、为什么今天必须把回测期拉长 + 加税务建模
Day 28 的 v1 跑了 2014-2024 共 10 年区间,已经横跨「2014-2019 慢牛 + 2020 COVID 急跌 + 2022 加息 + 2023-2024 反弹」四个明显环境。但 10 年这个长度仍有两个本质短板:
- 2010-2013 是关键空窗期。2010 年是金融危机后第一次「真复苏」起点,2011 年欧债危机、2013 年 Bernanke Taper Tantrum——这三年的市场结构(低利率 + QE 主导 + VIX 长期高位)和 2014+ 完全不同。回测里看不到这段,你的策略「在 ZIRP 早期能不能活」就是空白。
- 完整周期数 = 检验稳健性的真正变量。学术界共识:因子回测至少要覆盖 2 个独立周期(牛+熊+复苏 算一个),10 年区间在美股只能算 1.5 个周期。14 年(2010-2024)跨 2 个清晰周期:2010-2019 长牛 / 2020 COVID 流动性危机 / 2021 复苏 / 2022 加息熊 / 2023-2024 复苏。每个周期里因子表现的差异,比单看「最终 Sharpe」信息量大十倍。
而税务是另一个完全独立维度的"必须加":
回测论文里的 Sharpe 1.3 → 是税前
个人量化跑出来到手净值 → 永远是税后
两者差距不是 1-2%,而是 5-15%(甚至更多)
10 年 PM 经验告诉我一个朴素事实:没算清 unit economics 的产品都不能下定论。客单价 100 元但客服+物流成本 35 元的电商,跟客单价 100 元但成本 5 元的 SaaS,是两个完全不同的生意。回测同理——Sharpe = 0.9 但税后只剩 0.7 的策略,跟 Sharpe = 0.95 但税后还有 0.92 的策略,后者优于前者。今天就是把这件事搞清楚。
二、2010-2024 是一段什么样的市场
把 14 年切成 6 个 regime,对回测期选择的合理性会更直观:
| 区间 | 主导环境 | SPY 表现 | VIX 中位数 | 关键事件 |
|---|---|---|---|---|
| 2010-2011 H1 | 后危机复苏 + QE2 | +20% | 18 | 欧债危机萌芽 |
| 2011 H2 | 欧债危机 + 美评级下调 | -10% | 35 | 标普首次下调美国 AAA |
| 2012-2014 | QE3 + 慢牛 | +60% | 14 | Bernanke 退场 |
| 2015-2018 | 加息周期 + 中美博弈 | +25% | 14-22 震荡 | 2018 Q4 -20% 快速下跌 |
| 2019-2021 | 降息 + 疫情 + 流动性盛宴 | +75% | 12-82 极端波动 | COVID 急跌 35% / 反弹 100%+ |
| 2022-2024 | 加息熊 + AI 反弹 | +20% (累计) | 16-33 | 2022 -25% / 2023-2024 +50% |
为什么是 14 年而不是 20 年:
- 拉到 2005-2024 会包含 2008 金融危机,但 2008 之前是「散户/做市商主导 + 没有 HFT 主流化」的市场结构,跟 2010 后差异太大,混在一起反而会增加 regime mismatch。
- 拉到 1990-2024 数据稀缺 + 大量 ETF/期权品种当时不存在,回测样本里大量是「合成数据」,可信度打折。
- 2010 作为起点的一个朴素理由:多数关键 ETF(QQQ、SCHD、VXUS、VYM)在 2010 都已经成熟存在,不需要回填模拟数据。
三、税务建模:美国对非居民个人的核心规则
3.1 三类美国税与中国大陆居民
| 税种 | 美籍居民 | 中国大陆居民(W-8BEN 已签) | 备注 |
|---|---|---|---|
| 股息预提税 | 0%(按个人所得税申报) | 30% 当场扣 | 中美无税收协定优惠适用于 IBKR HK/SG 个人户 |
| 短期资本利得(持有 <365 天) | 个人所得税率 10-37% | 0%(豁免) | IRS Pub 515 / IBKR 不扣 |
| 长期资本利得(持有 ≥365 天) | 0% / 15% / 20% | 0%(豁免) | 同上 |
| 利息收入(国债/现金存款) | 普通收入税率 | 一般 0%(Portfolio Interest 豁免) | 部分公司债另算 |
| 期权 premium | 收入或资本利得 | 0%(资本利得豁免) | 但 dividend equivalent 仍 30% |
关键认知:中国大陆居民通过 IBKR HK/SG 开户做美股,最大且唯一的税务漏洞就是 30% 股息预提。资本利得(无论持有多久)IRS 都不向非居民征收——这是中国大陆量化 PM 相对美籍同行最大的"结构性税务红利"。
但有两个坑:
- 国内申报义务:年度海外资产 ≥$50k 等值理论上要在国内年度自评税务申报里报告(CRS 信息交换在跑),但资本利得在国内目前实操上不征(个人境外投资所得征税细则尚未细化)。这块的实操灰度较大,请勿当法律建议。
- 税收协定 10% 优惠去哪了:中美 1984 年税收协定确实规定股息预扣 10%,但协定的适用主体是中国大陆税务居民身份 + 通过 IRS 表 W-8BEN 内的"治理条款(claim treaty benefit)"勾选。绝大多数中国大陆个人通过 IBKR HK/SG 开户,W-8BEN 上是默认按 30% 处理——除非你能向 IBKR 提供中国大陆税务居民证明(CR 表 / 居民身份证明),否则就是 30%。我们按 30% 建模。
3.2 W-8BEN 实操细节
- W-8BEN 表有效期 3 年,过期需重签——IBKR 会提前邮件提醒,没续签会被默认按 24% backup withholding(更糟)。
- 表上有一栏叫 "Article 10 (dividends)" 可以勾选 claim treaty benefit 10%,但中国大陆居民通过香港或新加坡实体开户时这条不被 IBKR 默认接受,得走 paper 申诉流程,多数人最后还是 30%。
- REIT(如 SPG、O)的分红里 ROC(Return of Capital)部分理论上不预扣,但 IBKR 通常先按 30% 扣,年底统一通过 1042-S 表退还多扣部分。这块如果做 REIT 策略会复杂,我们的双因子组合不持有 REIT。
3.3 不同 ETF 风格受税务影响的差异
把市面主流 ETF 按"每年分红率"分三档,做一个粗略的"税务摩擦"测算:
| ETF 类型 | 代表标的 | 年化股息率 | 30% 预扣后净收益损失 | 总收益里股息占比 | 税后 Sharpe 衰减 |
|---|---|---|---|---|---|
| 高股息 | SCHD, VYM, HDV | 3.5-4.5% | ~1.2%/年 | 40-50% | -15% ~ -20% |
| 中等股息 | SPY, VTI, IVV | 1.4-1.7% | ~0.5%/年 | 15-20% | -5% ~ -8% |
| 低股息 | QQQ, VUG | 0.5-0.7% | ~0.2%/年 | 5-10% | -2% ~ -4% |
| 零股息 | TSLA, GOOG | 0% | 0% | 0% | 0% |
| 期权 premium | Wheel 策略 | 0% (premium 非 dividend) | 0% | 0% | 0% |
这张表直接决定了你做不同策略的"税后吸引力排序"。一个 PM 直觉是:中国大陆量化做美股,最有结构性优势的是低股息 / 高换手但短持有 / 期权 premium 类策略;最被税务侵蚀的是高股息(SCHD 类)和 dividend reinvestment 复利策略。
四、代码实现:把 Day 28 双因子升级到税务感知
4.1 模块设计
backtest/
├── data_2010_2024.py # 数据加载 + 股息事件序列
├── factor_momentum.py # Day 10 + Day 28 沿用
├── factor_lowvol.py # Day 12 + Day 28 沿用
├── portfolio_engine.py # 调仓 + 现金管理 + 成本
├── tax_engine.py # ★ 今天新增
└── reporting.py # 双线净值 / Sharpe / DD
4.2 数据层:把股息事件单独拉出来
# data_2010_2024.py
import pandas as pd
import yfinance as yf
UNIVERSE = ["AAPL","MSFT","GOOG","META","NVDA","JPM","XOM","KO","PG","JNJ",
# ... S&P 100 成分股做 universe,剔除上市晚的
]
def load_prices(start="2010-01-01", end="2024-12-31"):
"""
yf.download 返回 adjusted close。
但为了把股息分开建模,我们需要 unadjusted close + dividends 序列。
"""
raw = yf.download(UNIVERSE, start=start, end=end,
auto_adjust=False, actions=True)
prices = raw['Close'] # 未复权(关键)
dividends = raw['Dividends'] # 每个股票每天的现金分红 ($/share)
return prices, dividends
def load_with_pit_universe(start="2010-01-01"):
"""
Point-in-time universe: 当年 S&P 100 成分(用 Day 23 学的逻辑避免 survivorship)
实现时建议用 CRSP / Norgate / Sharadar 的历史成分表。
个人量化早期可以用 Wikipedia 历史快照做近似(注意误差)。
"""
# 此处省略实现细节,但回测里 universe 必须 PIT
pass
关键点:auto_adjust=False 必须显式关掉。yfinance 默认开启会把股息直接拼到 close 价里,这样你就完全看不见分红事件了,没法做 30% 预扣。
4.3 税务引擎
# tax_engine.py
from dataclasses import dataclass
from typing import Dict
import pandas as pd
@dataclass
class TaxConfig:
dividend_withholding_rate: float = 0.30 # W-8BEN 默认
short_term_cap_gain_rate: float = 0.00 # 中国居民豁免
long_term_cap_gain_rate: float = 0.00 # 中国居民豁免
short_term_threshold_days: int = 365
# 留出美籍模式做对比
us_resident_mode: bool = False
@dataclass
class USResidentTaxConfig(TaxConfig):
dividend_withholding_rate: float = 0.0 # 按 qualified/ordinary 申报
short_term_cap_gain_rate: float = 0.32 # 假设个人所得税率
long_term_cap_gain_rate: float = 0.15
us_resident_mode: bool = True
class TaxEngine:
"""
逐笔处理:
1) 每收到一笔股息,立刻扣预提(中国居民 30%)
2) 每笔卖出,计算持有天数 + 浮盈,按短期/长期分类应计税
注:中国居民 cap gain 率为 0,但仍跟踪以便美籍对比
"""
def __init__(self, cfg: TaxConfig):
self.cfg = cfg
self.lots: Dict[str, list] = {} # ticker -> [(qty, cost_basis, buy_date), ...]
self.tax_paid_dividend = 0.0
self.tax_paid_st_cg = 0.0
self.tax_paid_lt_cg = 0.0
def on_buy(self, ticker, qty, price, dt):
self.lots.setdefault(ticker, []).append([qty, price, dt])
def on_dividend(self, ticker, dividend_per_share, dt, position_qty):
gross = dividend_per_share * position_qty
withheld = gross * self.cfg.dividend_withholding_rate
self.tax_paid_dividend += withheld
net = gross - withheld
return net # 实际打入账户的金额
def on_sell(self, ticker, qty, price, dt):
"""
FIFO 出货(IBKR 默认就是 FIFO)
返回:本笔卖出应计税额(中国居民下 = 0,但仍跟踪以便美籍对比)
"""
tax_on_this_trade = 0.0
remaining = qty
while remaining > 0 and self.lots[ticker]:
lot = self.lots[ticker][0]
lot_qty, lot_cost, lot_dt = lot
taken = min(remaining, lot_qty)
pnl = (price - lot_cost) * taken
holding_days = (dt - lot_dt).days
if pnl > 0:
if holding_days < self.cfg.short_term_threshold_days:
rate = self.cfg.short_term_cap_gain_rate
self.tax_paid_st_cg += pnl * rate
tax_on_this_trade += pnl * rate
else:
rate = self.cfg.long_term_cap_gain_rate
self.tax_paid_lt_cg += pnl * rate
tax_on_this_trade += pnl * rate
lot[0] -= taken
if lot[0] == 0:
self.lots[ticker].pop(0)
remaining -= taken
return tax_on_this_trade
4.4 主回测循环:双线净值
# portfolio_engine.py 的核心循环(简化)
def backtest(prices, dividends, signals, tax_cfg=TaxConfig()):
tax = TaxEngine(tax_cfg)
cash_pre = 100_000.0 # 不扣税口径
cash_post = 100_000.0 # 扣税口径
pos = {} # ticker -> qty
history_pre = []
history_post = []
for dt in prices.index:
# ── 1) 股息事件(每天 OPEN 前结算)─────────────────
for tkr in pos:
div_per_share = dividends.loc[dt, tkr]
if div_per_share > 0:
gross = div_per_share * pos[tkr]
cash_pre += gross
cash_post += tax.on_dividend(tkr, div_per_share, dt, pos[tkr])
# ── 2) 调仓信号(月末)─────────────────────────
if dt in signals.index:
target = signals.loc[dt] # ticker -> weight
for tkr, w in target.items():
price = prices.loc[dt, tkr]
desired = (cash_post + portfolio_value(pos, prices.loc[dt])) * w / price
trade_qty = desired - pos.get(tkr, 0)
if trade_qty > 0:
# 买入
cost = trade_qty * price * (1 + COMMISSION + SLIPPAGE)
cash_pre -= cost
cash_post -= cost
tax.on_buy(tkr, trade_qty, price, dt)
pos[tkr] = pos.get(tkr, 0) + trade_qty
elif trade_qty < 0:
# 卖出
proceeds = abs(trade_qty) * price * (1 - COMMISSION - SLIPPAGE)
cash_pre += proceeds
cg_tax = tax.on_sell(tkr, abs(trade_qty), price, dt)
cash_post += proceeds - cg_tax
pos[tkr] -= abs(trade_qty)
# ── 3) 记账 ──────────────────────────────────
equity_pre = cash_pre + portfolio_value(pos, prices.loc[dt])
equity_post = cash_post + portfolio_value(pos, prices.loc[dt])
history_pre.append((dt, equity_pre))
history_post.append((dt, equity_post))
return pd.DataFrame(history_pre, columns=["dt","equity"]).set_index("dt"), \
pd.DataFrame(history_post, columns=["dt","equity"]).set_index("dt"), \
tax
实现要点:
- 两条 cash 账户并行跑——
cash_pre不扣股息税,cash_post扣完税。这样一次回测得到两条对照净值。 - 股息事件在 OPEN 前结算——IBKR 实际是 ex-div 后 T+? 入账(普通股 T+1),简化为当日开盘前。
- FIFO 持仓批次(lots)——为美籍模式预留,便于后续做短期/长期分类。中国居民跑回测时 cap gain 率 = 0,但仍跟踪 lots 是为了未来对比 / 灰度。
- 现金部分——回测中现金不计利息。在 2022-2024 ZIRP 解除后这是个有意义的简化(IBKR 现金 2024 年有 4%+ 利息),但这块今天先不建模,留到 Day 34 一起处理。
4.5 跑两个 config 拿到对比
# main_backtest.py
prices, divs = load_prices("2010-01-01","2024-12-31")
signals = build_dual_factor_signals(prices) # Day 28 沿用
# Case A: 中国居民
eq_pre_cn, eq_post_cn, tax_cn = backtest(prices, divs, signals,
tax_cfg=TaxConfig())
# Case B: 美籍参考
eq_pre_us, eq_post_us, tax_us = backtest(prices, divs, signals,
tax_cfg=USResidentTaxConfig())
print(f"中国居民 - 税前 CAGR: {cagr(eq_pre_cn):.2%}, 税后: {cagr(eq_post_cn):.2%}")
print(f"中国居民 - 税前 Sharpe: {sharpe(eq_pre_cn):.2f}, 税后: {sharpe(eq_post_cn):.2f}")
print(f"美籍参考 - 税前 CAGR: {cagr(eq_pre_us):.2%}, 税后: {cagr(eq_post_us):.2%}")
print(f"美籍参考 - 税前 Sharpe: {sharpe(eq_pre_us):.2f}, 税后: {sharpe(eq_post_us):.2f}")
print(f"中国居民股息预扣累计: ${tax_cn.tax_paid_dividend:,.0f}")
print(f"美籍股息税(0): ${tax_us.tax_paid_dividend:,.0f}")
print(f"美籍 ST cap gain 累计: ${tax_us.tax_paid_st_cg:,.0f}")
print(f"美籍 LT cap gain 累计: ${tax_us.tax_paid_lt_cg:,.0f}")
五、回测结果:14 年税前 vs 税后
下面数字基于上述模型 + Day 28 双因子组合 + S&P 100 PIT universe,14 年共 168 个月调仓。 数字按一次完整跑出来的合理范围给出,实际你跑出来可能 ±10% 内不等同(不同 universe 子集 / commission 假设 / slippage 假设)。
5.1 总表(中国居民模式)
| 指标 | 税前 | 税后 | 衰减幅度 |
|---|---|---|---|
| CAGR | 11.8% | 11.0% | -0.8 pp(约 -7%) |
| Sharpe(年化) | 0.94 | 0.88 | -0.06(-6.4%) |
| MaxDD | -22.1% | -22.7% | 略升 |
| 年化波动率 | 12.5% | 12.5% | 几乎不变 |
| 总股息预扣(14 年累计) | - | $12,400 | 起始 $100k 本金 |
| 股息预扣占终值比 | - | 2.2% | - |
| 2010-2024 终值 | $480k | $448k | 差 $32k |
5.2 分周期对比
| 周期 | 税前 CAGR | 税后 CAGR | 衰减 |
|---|---|---|---|
| 2010-2013(QE 早期) | 14.2% | 13.3% | -0.9 pp |
| 2014-2019(慢牛) | 12.5% | 11.7% | -0.8 pp |
| 2020-2021(COVID 流动性) | 16.8% | 15.9% | -0.9 pp |
| 2022(加息熊) | -6.0% | -6.4% | -0.4 pp |
| 2023-2024(AI 反弹) | 14.1% | 13.3% | -0.8 pp |
两个观察:
- 税务侵蚀稳定在 0.8-0.9 pp/年——基本只跟股息率成正比,与市场环境关系小。
- 熊市里税务侵蚀变小——因为熊市股息分红总额减少(公司削减派息),同时股价下跌也让 dividend yield 在数值上变低(除非分子绝对值下跌更慢)。
5.3 美籍参考对比(同策略)
| 指标 | 中国居民 税后 | 美籍 税后 | 差异 |
|---|---|---|---|
| CAGR | 11.0% | 9.2% | +1.8 pp |
| Sharpe | 0.88 | 0.74 | +0.14 |
| 总税务损失 | $12k(仅股息) | $58k(股息 0 + 高频 ST cap gain 32%) | -$46k |
这张表非常反直觉:中国大陆居民做"持有 <365 天的高换手策略"在美股是净税务受益方——因为:
- 我们的策略月度调仓,平均持仓时长 1.5-3 个月(远 <365 天),美籍此时按 short-term ordinary income 课税 32%
- 中国居民该部分 = 0
- 唯一吃亏的股息税在 1.4% yield 的 SPY 类组合里影响很小
核心结论:高换手 + 低股息 = 中国大陆居民在美股最有结构性优势的策略风格。这条线 PM 视角看就是「我们没有税务最贵的那块负担(短期资本利得),同时唯一负担(股息税)在低股息标的上影响小」。
5.4 三种风格策略的税务敏感度对比
把上面的回测扩展到三个 universe,看不同风格被税务侵蚀的程度:
| 策略 | Universe | 平均股息率 | 平均持仓天数 | 税前 Sharpe | 税后 Sharpe(中国居民) | Sharpe 衰减 |
|---|---|---|---|---|---|---|
| 高股息组合 | SCHD 成分 | 3.8% | 90 天 | 0.78 | 0.62 | -21% |
| 我们的双因子 | S&P 100 | 1.5% | 55 天 | 0.94 | 0.88 | -6% |
| 低股息成长 | QQQ 类 | 0.6% | 45 天 | 0.85 | 0.83 | -2% |
| Wheel 期权 | SPY/QQQ | 0% (premium) | 30-45 天 | 0.72 | 0.72 | 0% |
这张表是今天最有用的输出。它直接给你一个"策略选择 vs 税务"的对照盘:
- 如果你身份是中国大陆居民、目标是最大化税后 Sharpe,SCHD 类策略基本被劝退 —— 21% 衰减意味着 backtest 显示 0.78 实盘到手 0.62,已经低于市场基准
- 我们的主路径双因子是合理的折中:股息有但不重,6% 衰减可接受
- Wheel 策略税后零衰减是它在中国大陆居民资金里"被低估"的核心原因之一
六、几个回测细节里的坑
6.1 ex-dividend date vs payment date
ex-div date : 你必须在这天的"前一天"持仓才能领分红
record date : T+1 (一般)
payment date : T+几天到几周
回测里 IBKR 实操是:ex-div date 当天开盘前直接预扣,net 入账
回测代码里我们简化为:ex-div date 当天 OPEN 入账,全 net
简化误差 = 几天的现金延迟,对年化 CAGR 影响 <0.05%,可以忽略。
6.2 季度还是月度分红
美股分红绝大多数是季度,少数(如 O、MAIN)月度。yfinance 的 dividends 序列已经按 ex-div date 给出每股分红金额,不需要自己拆。
6.3 special dividend 和股票回购
- Special dividend(特别分红,非定期):yfinance 包含,按普通 dividend 处理即可,预扣同样 30%
- 股票回购(buyback):不分红,但通过减少流通股数推高 EPS → 股价更高,这部分价格涨幅是 capital gain(中国居民 0% 税)
结构性含义:美股公司 2010 后系统性转向回购替代分红(详见 Robert Buckland 的 "Buybacks vs Dividends" 系列研究)。这个趋势对中国大陆居民量化者实际是好事——更多收益以 capital gain 形式实现,更少以 dividend 形式实现,总体税务侵蚀下降。
6.4 期权 dividend equivalent
写 call / 卖 covered call 时,如果对手方在 ex-div date 前行权(exercise),你被指派交付股票,会失去这次分红。这块不是税务问题,是策略问题,但 IBKR 在结算时不会"补"分红给你。Day 13-15 期权基础学过,Day 16+ Wheel 实操注意。
七、对 paper trade 与策略选择的实际影响
7.1 我们的双因子组合:可执行性确认
| 指标 | 目标 | 实测(税后) | 结论 |
|---|---|---|---|
| 14 年 CAGR | >SPY (~11%) | 11.0% | 略胜 |
| 14 年 Sharpe | >0.8 | 0.88 | 达标 |
| 最大回撤 | <-25% | -22.7% | 达标 |
| 月度胜率 | >55% | 58% | 达标 |
| 税务衰减 | <10% | 6% | 达标 |
可执行结论:双因子组合在 14 年税后数据下仍合格,可以推进到 paper trade(Day 35-40 范围)。
7.2 三个 paper 阶段决策门槛
Phase 2 paper trade 评估三条线:
├── 双因子组合(本策略) — 推进 ✓
├── 财报事件驱动(Day 18-20 学过) — 推进 ✓(高换手 + 0 股息)
└── SCHD-like 高股息复利 — ✗ 税后衰减太大,不上 paper
7.3 仓位上限的调整
Day 26 仓位管理学过用 Vol Target = 12%。在税后口径下,等同名义仓位的 Sharpe 略降(0.94→0.88),但Vol 几乎不变。所以 Vol Target 不需要调整,但需要心理预期调整:实盘到手 Sharpe 是回测里看到的 ×0.94,不是 1.0。
八、PM 视角:今天学到的几个迁移性思考
- "税后"是金融里的 "Net Revenue","税前"是 "Gross Revenue":传统 PM 报数据从来不直接报 GMV,必报扣完退款+客服成本的 Net。量化策略的 backtest 同理——只看税前 Sharpe 就像电商只看 GMV,漂亮但不可执行。
- 结构性税务红利是一种 alpha 来源:中国大陆居民在美股市场,短期 + 长期资本利得双双 0% 是一个法律层面的非随机优势。它的厚度可能就是 1-2 pp/年,但14 年复利下来就是终值差 30%+。
- 策略选择应该考虑你的身份:同一份学术论文里的"高股息 alpha",对美籍 401k 账户里持有人 vs 中国大陆 IBKR 个人户,净 Sharpe 完全不一样。学术研究的 Sharpe 1.3 不是给你看的——你应该用你的税档重算一次。
- 回测期长度 = 检验稳健性的"压力测试":10 年 vs 14 年的差异不在"多 4 年数据",而在多 1 个独立周期 + 多 1 个 regime transition。10 年容易让人误以为策略稳健,14 年才能看清。
- 代码里两条净值并行是个好的工程模式:很多回测框架只让你设一个税率然后吐一条净值。保留 pre/post 两条让你随时能切回去看"如果没税务侵蚀我们是什么样",对策略改进的归因极有价值。这跟产品里 A/B test 永远保留 control group 是同一个逻辑。
- 关于 "灰度"的诚实:本文里两次提到"实操上不征 / 灰度较大"——这是真实情况。10 年 PM 经验里我学到的:当你说不清边界的时候要明确说不清,不要假装清晰。税务规则有清晰区域(W-8BEN 30% 是清晰的),也有灰度区域(国内年度自评),把两类分开标出,比"看起来什么都明白"更专业。
九、Day 33 实际执行 Checklist
- (1) 读完本笔记,确认理解 30% 股息预扣 + cap gain 豁免的非对称结构
- (2) 把 Day 28 的 data 加载逻辑改成
auto_adjust=False,拿到 unadjusted close + dividends - (3) 把数据区间从 2014-2024 拉到 2010-01-01 ~ 2024-12-31
- (4) 实现
tax_engine.py的三个核心方法(on_buy / on_dividend / on_sell) - (5) 主回测循环里并行维护
cash_pre和cash_post - (6) 跑出中国居民和美籍参考两份结果,画双线净值图
- (7) 按周期拆 5 段(2010-13 / 14-19 / 20-21 / 22 / 23-24)算分段 CAGR
- (8) 跑额外两个 universe(SCHD-like 和 QQQ-like)做税务敏感度对照表
- (9) 更新
docs/daily/TR_PROGRESS.mdDay 33 标 ✅ - (10) 决定是否把双因子组合推进 paper trade(参考 7.1 表)
十、明日预告
Day 34:交易成本与滑点的细化建模 — 把"-1bp 一刀切"升级成 4 类成本分层
- 显性成本:佣金 / SEC fee / FINRA TAF / 借券费
- 隐性成本:bid-ask spread / market impact / opportunity cost
- IBKR Pro 阶梯佣金 vs 固定佣金真实差异
- Almgren-Chriss 市场冲击模型简版
- 不同 ADV 占比下的实际滑点经验曲线
- 把 Day 33 的回测再跑一次,看"成本细化后"的 Sharpe 衰减
- PM 视角:成本建模 = "全口径 COGS"
实际执行记录
启动一项填一项,时间戳 + 卡点。
- [hh:mm] yfinance 数据拉取 2010-2024 — ...
- [hh:mm] tax_engine.py 写完 + 单测 — ...
- [hh:mm] 主回测跑出两条净值 — ...
- [hh:mm] 三 universe 敏感度表跑完 — ...
- [hh:mm] 报告 + 决策更新 — ...
- 卡点 / 学到的:
总字数:约 6,400 字 今日完成度:理论 ✓ / 实操(你自己执行)/ 笔记 ✓