作 者:老余捞鱼
原创不易,转载请标明出处及原作者。

技术讨论不构成任何操作建议。
模型评测不等于投资建议。
不荐股、不卖课、不承诺收益。
市场有风险,请合法合规投资。
本文约 3200 字 | 预计阅读 8 分钟,后有3段代码和数据来源,建议先收藏
三个数字先摆在这里:+300.1%、87.86%、-98.4%。它们来自同一份量化策略,第一眼都很有诱惑力,很容易以为这是一套能直接拿去跑的策略。而实际上说的却是三种不同层级的证据,有的缺成本,有的缺损益,有的连样本量都不够。
这也是我想写这篇文章的原因。最近“拿来就能跑”的量化材料很多,图都做得漂亮,但信号什么时候发布、按什么价格成交、成本扣没扣,往往被放在最不显眼的地方。图上的高收益和账户里的收益,中间隔着一整套执行细节。
今天这篇就把材料里的三个策略拆开:一个按月排名的动量组合、一个标普500当天到期期权的区间带,以及一个S-1稀释事件。先看它们各自在赌什么,再看图上的数字能说明到哪一步,最后落到代码和执行细节。
三组数字都来自附件图表,我只做算术核对,不把它们写成自己的收益。
| 策略 | 图上给出的证据 | 我会怎样称呼它 |
|---|---|---|
| 横截面动量 | 12个月,10正2负 | 最近12个月月度收益 |
| SPX 0-DTE区间 | 593天,521次命中 | 区间命中率87.86% |
| S-1稀释 | 3个案例,3种窗口 | 事件案例,不是完整回测 |
这三组数字各自能说明的问题差得很远。动量图只有12个月,区间带只统计命中与落空,稀释图只有3个案例。它们共同回答的是“信号长什么样”,还没有回答“按信号执行能不能赚到钱”。
后面顺着三个问题往下看。信号什么时候能看到,规则怎么落地,图上没给的成本和风险又在哪里。
一、先把发布时间对上
时点数据(point-in-time)可以理解成监控录像。某天上午10点30分屏幕上显示什么,就把那一帧锁住。以后即使知道收盘结果,也不能回头修改当时的画面。当时知道什么,就只准用什么。
很多回测看起来很好,问题就出在这。用今天修订过的成分股回测五年前,等于提前把结局递给策略。用收盘后才公布的字段决定当天开盘,也一样。这个坑很隐蔽,代码通常不会报错。
这些数据的发布时间并不一样,我把四个按日更新、和交易时点有关的数据整理成一张表。时间都是纽约时间,不能简单压成“今天”。
| 数据 | 发布时间 | 最容易用错的地方 |
|---|---|---|
| 风险状态 | 每日10点10分 | 当天开盘提前使用 |
| SPX区间带 | 每日10点30分 | 当成开盘前已知 |
| 动量篮子 | 调仓日16点05分 | 用新名单决定当天收盘 |
| Next-Day Movers | 每日15点30分 | 当成下一日方向信号 |
日期相同,不等于同时可见,这就是时点数据要管的事。官网专门提醒过,10点10分才发布的风险状态,不能拿去决定当天开盘。规则若在开盘执行,只能使用此前已经拿到的数据。S-1是事件触发,没有每日固定时刻。它的filing_timestamp放到第四节再说。
我一开始也没管datetime.now(),觉得取当天总不会错。把发布时间排在一起才发现,本机日期和纽约日期可能差一天,周末还会取不到数据。示例里换成ZoneInfo,取不到就停,不拿后一天的数据硬补。
二、动量先比相对排名
横截面动量做的是相对排名,不是挑出最近涨幅最大的那只。它先把流动性足够、期权交易也方便的美股放进同一个池子。接着按过去一段时间的表现排队,只取前10只。某只股票自己涨了多少并不重要,重要的是它有没有比同池的其他股票更强。
组合每月重新排一次,调仓时10只等权,可以先理解成每只占10%。一个月后价格变化,权重会偏离10%。回测如果每月恢复等权,就要把调仓产生的换手和成本算进去。
还有一个容易忽略的执行时点。名单在调仓日16点05分更新,而纽约时间的常规收盘是16点。如果名单要到16点05分才更新,回测就不能用当天16点的收盘价成交。顺序反了。这样算,等于假装自己提前拿到了名单。我在研究规则里会把执行放到下一个可交易时点。
图上从2025年5月到2026年4月,10个月为正、2个月为负。最好+51%,最差-18%。我把12个月收益连乘,累计约+300.1%。我盯着这张图看了半天,我仍没找到成本口径,所以这个结果只能按毛收益理解。下一年还能不能维持,说不好,我也不打算用12个月外推。
它能说明这12个月走得强,不能回答扣完成本还剩多少。图里也没有基准和最大回撤。官网说历史可以追到2017年,这与只展示最近12个月是两回事。
三段代码按顺序放进同一个.py文件就能运行。API key从环境变量读,只取研究数据,不连接券商。第一段只做一件事,把最新一期10只篮子取出来。
import os
from datetime import datetime
from zoneinfo import ZoneInfo
import requests
BASE = "https://api.alphanume.com/v1"
def get_rows(path, **params):
response = requests.get(
f"{BASE}/{path}",
params={"api_key": os.environ["ALPHANUME_API_KEY"], **params},
timeout=30,
)
response.raise_for_status()
return response.json()["data"]
rows = get_rows("quant-galore-momentum-index")
latest = max(row["date"] for row in rows)
basket = sorted(
(row for row in rows if row["date"] == latest),
key=lambda row: row["rank"],
)
assert len(basket) == 10, "最新篮子不足10只,先检查数据"
for row in basket:
print(latest, row["rank"], row["ticker"])assert len(basket) == 10是我加的。少一只就该停下来查,不该让程序带着半张篮子继续跑。后面两段也沿用这个get_rows,并按rank排序,保证拿到的就是当期名单。
三、87.86%,能当胜率吗?
0-DTE是当天到期的期权。区间带给出一个上界和一个下界,可以把它理解成模型对当天收盘范围的估计。铁鹰组合就是围绕这两条线搭出来的结构:上方一组价差在指数冲高时赔付,下方一组价差在指数跌破时赔付。指数留在中间,两组都收权利金。权利金可以理解成期权的价格,也是这类结构先收到的一笔保费。
这类结构的毛收入上限是权利金,最大亏损由行权价的距离和收到的权利金共同决定。翼宽就是同一侧两个行权价之间的间隔,间隔越大,极端行情下赔得越快。到期损益要拿收到的权利金减去赔付和相关费用,行权价和保证金要记账,滑点也别漏。
现在再看87.86%。先看分母。521加72等于593,521除以593等于87.858%。四舍五入正好87.86%。这个数其实只统计收盘有没有落在区间内,不能直接当成组合扣费后盈利的概率。
落在区间外,不一定整笔亏损;落在区间内,也不代表扣掉成本后一定赚钱。我更倾向把它叫区间命中率,少写“交易”两个字,是在给结论上刹车。
风险状态过滤器提供的也不是涨跌方向。它看的是期权市场对未来波动的定价,不看指数过去涨了还是跌了。1代表高风险状态,0代表相对平静。官网样本覆盖3833个交易日。两种状态年化收益分别为13.0%和12.7%,几乎贴着。
已实现波动率却是24.7%和12.8%,高风险状态约为低风险状态的1.93倍。这组数字说明的是路更颠,不是车一定往下开。拿它调整仓位,常见做法是高风险日把仓位调小,背后的逻辑是波动大时少承担一点风险,并不等于躲开下跌。这条规则本身还得单独回测,我暂时不替它补收益。真实成本下还能剩多少优势,我说不好,所以只把它当辅助信息。
today = datetime.now(ZoneInfo("America/New_York")).date().isoformat()
band = get_rows("spx-0dte-strike-band", date=today)
regime = get_rows("sp500-risk-regime", date=today)
if not band or not regime:
print(today, "数据尚未发布,保留空记录")
else:
b, r = band[0], regime[0]
if b["date"] != r["date"]:
raise ValueError("两个接口返回了不同日期")
if r["risk_regime"] == 1:
print(r["date"], "风险状态1,只记录,不生成卖方信号")
else:
print(b["date"], b["lower_strike"], b["upper_strike"])这段代码只做日期对齐。数据没发布就停,两个接口日期不一致就报错,高风险日只记录、不输出信号。0也不值得庆祝,它只是少了一个劝阻理由。
四、三个稀释案例,不能当成绩单
S-1是公司递交给SEC的注册文件,可能登记新发股份,也可能只是老股东转售。代码先要求dilutive等于1、resale等于0。接着筛市值小于5000万美元的公司,目的就是把新增股份和老股转让分开。
可附图只有ELOX、AKTX、BAFN三行。三行分别是-98.4%、-47.8%、-22.1%,后面标着6天、5天、13天。数字很有冲击力,但持有窗口并不一样,借券费没给,可借数量和成交约束也没给。我不敢把这3个案例当成一张成绩单。
这段筛选还有两个字段没用上。官方提供filing_timestamp,专门区分盘中与盘后,这段筛选却只看日期。它还提供shares_offered。市值门槛只能说明公司小,不能说明这次新发的规模有多大。
dilutive也只是文件标签,不等于稀释已经完成。注册可能过很久才定价,实际发行规模可能缩小,也可能撤回。要认真统计这类事件的影响,就要把生效与撤回分开,仍待处理的单算,再统一持有窗口。还要用同期非稀释的S-1做对照组,免得把小盘股本身的波动都算到稀释头上。
第三段代码先把研究清单需要的字段补齐,包括披露时间、发行股数以及市值。
filings = get_rows("dilution", date=today)
candidates = [
row for row in filings
if row["dilutive"] == 1
and row["resale"] == 0
and row["market_cap_at_filing"] is not None
and row["market_cap_at_filing"] < 50_000_000
]
for row in candidates:
print(
row["date"], row["filing_timestamp"], row["ticker"],
row["shares_offered"], row["market_cap_at_filing"],
)再往下做,还要确认披露时刻早于可交易时刻,把离场窗口写进同一条规则。借券能不能拿到、费用多少,也要进损益表。代码筛出候选,只代表研究可以开始。
五、附加信号只告诉你可能波动
Next-Day Movers是一个附加接口。它挑的是下一交易日可能波动更大的股票,只给波动幅度,不给方向。最新记录的return和absolute_move为空。空值不是缺失,只是结果还没发生。如果下载历史时先把空值删掉,等于只留下已经知道结局的样本。历史会被悄悄改写。
它和SPX区间带可以配合研究:一个判断指数会不会留在窄区间,一个寻找个股可能的大波动。但两个信号拼在一起后是否更好,要重新算。期权价格和价差要另取,滑点、停牌也不在接口字段里,官网也没有替这种组合背书。
三段示例代码实际请求4个接口,加上只在正文说明的Movers,全文一共涉及5个。辅助数据同样有发布时间,不能因为它是辅助就跳过时点核对。
六、哪些能核对,哪些不能
还有一项现实变化需要说明。2026年10月26日我查官网时,新REST API和MCP已经要求Pro或Enterprise。公开的数据看板还能看。真想照着跑,先确认账户权限,不要把旧教程里的免费额度提示当成长期承诺。
这篇没有给自己编一套收益。我核对的是四件事。12个月收益重新连乘,521和72重新算命中率。三段Python做语法和模拟返回测试,发布时间同官方文档逐项对照。没有真实API返回,我不敢写接口实测通过。
要把这些方法放进自己的研究,我会先留四类记录,每一类都对应一个容易漏掉的环节。字段可以不复杂,关键是事前记,不要等结果出来再补。
- 每次请求保存原始JSON和抓取时间,旧文件不覆盖。
- 每个信号保存发布日期和具体时刻,执行时只取当时可见版本。
- 每笔研究记录权利金、费用、换手以及资金占用,口径先写死。
- 每次无法成交都记下原因,借不到与价差过大要分开,数据未发布也单列。
这三套方法最值得研究的地方,恰恰是这些不太好看的执行细节。先把记录补齐,再谈优势。
你手上那张87.86%的成绩单,分母是区间命中,还是扣费后的交易笔数?
参考资料
- Quant Galore Momentum Index,https://www.alphanume.com/docs/quant-galore-momentum-index
- S&P 500 0-DTE Strike Band,https://www.alphanume.com/docs/sp-500-0-dte-strike-band
- S&P 500 Risk Regime,https://www.alphanume.com/sp500-risk-regime
- Stock Dilution,https://www.alphanume.com/dilution
- Next-Day Movers与Risk Regime组合说明,https://www.alphanume.com/blog/combine-market-regime-stock-movement-signals
- API访问与定价,https://www.alphanume.com/pricing
#量化策略 #时点数据 #横截面动量 #0DTE #铁鹰组合 #风险状态 #S1稀释 #NextDayMovers #Python #量化回测
觉得有用的话,把这篇转给同样在做策略研究的朋友。
Be First to Comment