3. 相对强弱指标计算
在ETF轮动策略中,“相对强弱”不是一句模糊的定性判断,而是一组可以从价格序列中直接算出来的数值。本节要解决的核心问题是:给定一组候选ETF的日线收盘价,如何把它们转换成可比较的强弱分数,并在每个交易日按固定窗口滚动排名,最终输出“当前该持有哪只ETF”的信号。这个信号的质量,直接决定了后续回测结果是否可信。
先明确一个关键约定:本课程所有动量、夏普比率、排名分数,数值越大代表相对越强。排名第1名即分数最高者。这一方向约定在全文和图示中保持一致,后续章节不再重复说明。
一、输入数据的组织方式
计算的第一步不是写公式,而是把数据整理成“宽表”。假设候选池为4只ETF:沪深300(510300)、中证500(510500)、创业板(159915)、黄金ETF(518880)。取最近250个交易日的日线收盘价,整理成如下结构:每一行是一个交易日,每一列是一只ETF的收盘价。宽表的好处是,任意一天的横截面比较只需取同一行,任意一只ETF的时间序列计算只需取同一列,滚动窗口的切片操作非常自然。
实际工程中需要注意两点。第一,不同ETF的上市时间不同,早期数据可能存在空值,滚动窗口内若有效数据不足,应将该日该标的的分数置为空值而不是用0填充,否则会人为制造“最弱”的假信号。第二,遇到停牌或数据缺失,建议用前值填充(forward fill),但连续缺失超过5个交易日的标的应在该窗口内剔除,避免用陈旧价格参与排名。
二、动量指标:窗口收益率的计算
最直观的强弱度量是区间动量,即过去N个交易日的累计收益率。设第t日收盘价为Pt,则20日动量定义为:
momentum_20(t) = P(t) / P(t-20) - 1
这里用“20个交易日前”而不是“20个自然日”,是为了对齐交易日历。若某标的在t-20日无有效价格,则向前寻找最近的有效价格,并记录实际间隔天数,间隔偏离超过3个交易日则该值作废。动量指标简单、可解释性强,但它对窗口端点价格非常敏感——如果端点恰好是暴涨日或暴跌日,排名会被单日噪声扭曲。因此实践中通常不单独使用动量,而是与风险调整后的指标配合。
三、夏普比率:把波动纳入强弱判断
夏普比率衡量的是“每承担一单位波动获得的收益”。在滚动窗口内,用日收益率计算:
ret(t) = P(t) / P(t-1) - 1
sharpe_60(t) = mean(ret, 60) / std(ret, 60) * sqrt(252)
其中mean和std分别取最近60个交易日的日收益率均值与标准差,sqrt(252)是年化因子。这里假设无风险利率近似为0,在ETF轮动的短周期比较中这一简化是可接受的。夏普比率的优势在于:同样上涨10%,波动小的ETF得分更高,这符合“稳健强势”的偏好。但它也有陷阱——如果窗口内波动率极低而收益为正,夏普会被放大,因此需要对分母设置下限,例如std低于0.2%时按0.2%计,防止除零和异常放大。
把动量与夏普结合,常见的做法是分别排名后加权,或先标准化再相加。本课程采用“分别排名、加权求和”的方式,因为它对量纲不敏感,且天然抗异常值:
score = 0.5 * rank(momentum_20) + 0.5 * rank(sharpe_60)
注意这里的rank是横截面排名,分数越高排名越靠前,最终score越高代表综合越强。
四、滚动窗口排名逻辑
“滚动”意味着每个交易日都重新计算一次,而不是只在月末调仓日算一次。实现上,用一个循环遍历每个交易日t,对每只ETF取t时刻往前20日(动量)和60日(夏普)的切片,计算指标,再在当日横截面上排名,得到每只ETF的score,取score最高者为当日目标持仓。若最高分标的与当前持仓不同,则产生换仓信号。
下面这张图展示了从原始价格序列到最终排名信号的完整数据流,以及两个不同长度窗口如何并行计算、在横截面上汇合:
五、实现细节与常见坑
把上述逻辑写成代码时,有几个细节决定了回测是否“干净”。第一,排名必须在当日横截面上做,不能拿不同日期的分数直接比较,因为动量分数的绝对水平会随市场整体涨跌漂移。第二,避免未来函数:t日的信号只能用t日收盘及之前的数据,若在t日收盘价上计算却假设t日开盘成交,就引入了不可实现的收益。稳妥做法是t日收盘算信号、t+1日开盘或收盘执行。第三,窗口长度要固定,动量20日、夏普60日一旦确定,全回测期不应随行情调整,否则排名逻辑失去一致性。
另一个容易被忽视的问题是并列排名。当两只ETF分数完全相同时,应设定明确的打破规则,例如优先保留当前持仓者(减少不必要的换手),或按代码顺序取前者。规则本身不重要,重要的是在回测前写死,避免事后解释。
六、结果如何观察与判断
指标算完后,不要急着看净值曲线,先检查中间产物。建议输出一张逐日排名表,包含日期、各ETF的动量值、夏普值、综合score和排名。观察三点:一是排名是否频繁在相邻名次间跳动,若第1名和第2名分数差距长期小于0.1,说明信号不稳定,换手会很高;二是空值比例,若某标的长期因数据不足被剔除,需确认是数据问题还是上市时间问题;三是极端值,若某日夏普出现异常大数,检查是否触发了std下限保护。
以图中示例(假设数据)来看,159915动量最高但夏普中等,518880夏普最高但动量偏低,综合排名后159915居首。这说明加权方式会实质影响选股结果——若把夏普权重提高到70%,518880可能反超。因此权重不是拍脑袋定的,而应在样本外做敏感性检验,确认排名信号对权重不敏感后再固化参数。
至此,价格序列已经被转换成每日可执行的排名信号。这个信号是后续换仓规则、交易成本扣除和绩效评估的共同输入,它的计算口径必须在整个回测中保持唯一和透明。