简介广发证券发布的《低延迟趋势线与交易择时》金融工程专题报告面向技术分析者、量化策略研究员与短线交易者针对传统移动平均线MA平滑性与延迟性难以兼顾的痛点系统介绍低延迟趋势线LLT的构造思路与交易性择时方法。压缩包仅含1个PDF文件大小约1.44MB内容完整、便于直接阅读。报告从EMA与信号处理中的滤波器原理出发说明为何选择二阶滤波器构造LLT随后展示LLT在沪深300、上证指数、深证成指等市场指数上的择时效果并给出ETF趋势交易策略的实证结果同时坦诚分析趋势拐点附近可能出现的震荡与正确率下降问题。对于希望优化入场离场时机、降低趋势跟踪滞后性的投资者这份报告提供了从理论推导到案例验证的完整参考。目前已有615人学习下载适合作为量化择时研究的中级进阶资料。1. 低延迟趋势线为什么传统均线「跟不紧」以及交易性择时的真正收益来源2010 年之后很多用均线做趋势跟随的人会明显感觉到信号慢半拍30 日均线刚转头向下指数已经跌了一段等均线重新走平反弹又错过了。这不是参数没调好而是 MA 的数学结构决定的——它的延迟约等于计算周期的一半20 日均线延迟 10 个交易日60 日均线延迟 30 个交易日。平滑性越好滞后越严重这是一个绕不开的矛盾。这次拆解的是一份券商金工专题报告核心是低延迟趋势线 LLT用二阶低通滤波器把延迟从约 19 个交易日压到接近零同时保留平滑性。基于 LLT 的切线斜率择时被称作「交易性择时」——判断正确率往往低于 50%但正确的时间占比很高盈利来自趋势确立后的长持仓段。适合做指数择时、ETF 轮动和期货趋势策略的人也适合想从信号处理角度重新设计趋势线的量化交易者。2. 从 EMA 到 LLT一阶滤波到二阶滤波的构造路径2.1 EMA 就是一阶低通滤波器时域递推与 Z 变换报告首先讨论的是 EMA。EMA 的递推公式是EMA(T) α·price(T) (1-α)·EMA(T-1)其中 α 是 0 到 1 之间的参数α 越小历史权重越高曲线越平滑延迟也越大。EMA 和 MA 的最大区别在于MA 对窗口内所有价格等权EMA 给靠近计算日的价格更高权重。这一加权方式在信号处理理论中有明确对应——它就是一阶低通滤波器。要用频域角度看这个问题需要用 Z 变换。Z 变换把离散时间序列映射到复频域定义是 F(z) Σ f(k)·z^(-k)。两个常用性质线性性质和时移性质 f(k-m) ↔ z^(-m)F(z)。把 EMA 递推式两边做 Z 变换输出是 EMA(z)输入是 price(z)得到传输函数H1(z) EMA(z) / price(z) α / [1 - (1-α)·z^(-1)]传输函数描述的是任意频率下输出与输入的幅度比。令 z e^(iω)ω0 时 z1H11常序列信号无衰减ωπ奈奎斯特频率时 z-1H1α/(2-α)。α0.05 时该值约 0.0256高频分量被大幅削减。这就是低通滤波的本质。一阶滤波的问题在于两点第一通带到阻带的过渡带太长有用的中频信号也被削弱第二延迟明显。按群延迟定义α0.05 的 EMA 在极低频附近有约 19 个交易日的延迟。EMA 用 α2/(d1) 换算成等效 MA 周期约 39 天延迟和 39 日均线相当。所以 EMA 相对 MA 只是权重的改进延迟问题没有根本解决。2.2 修正 EMA 到二阶滤波先构造高通再补回低频要构造低延迟趋势线报告走的是另一条路先构造高通滤波器再从全频信号里减去高通剩下就是低通。理论上低通 H 和高通 1-H 是全频互补的。直接对 EMA 的 H1 做 1-H1 会得到一个不干净的高通因为 H1 在奈奎斯特频率处的增益不等于 0α0.05 时还有 0.0256意味着高通输出没有包含全部高频。修正方法是把当日和前一日价格都取进来递推式改为EMA(T) α·[price(T) price(T-1)] / 2 (1-α)·EMA(T-1)对应的传输函数 H2 (α/2)(1z^(-1)) / [1 - (1-α)z^(-1)]分子在 z-1 时为零所以奈奎斯特频率处增益为 0高频完全保留。一阶高通 H31-H2 的过渡带仍然偏宽。报告指出阶数越高截止频率附近衰减越快但同时通带会变「不平」靠近截止频率的信号会有放大。折中方案是二阶串联两个一阶高通H4H3·H3。二阶高通在阻带衰减更快能更好地区分高低频。由于全频互补二阶低通就是 H51-H4这就是 LLT 的构造来源。这段涉及多个传输函数放在一起看比较清晰符号对应指标角色关键性质H1EMA一阶低通奈奎斯特处增益 α/(2-α) 不归零H2修正 EMA一阶高通的基础奈奎斯特处增益为 0H31-H2——一阶高通过渡带偏宽H4H3²——二阶高通阻带衰减更快H51-H4LLT二阶低通零频增益 1延迟接近 02.3 LLT 传输函数、差分方程与 α-d 参数换算把 H5 展开后LLT 的传输函数写成一个二阶 IIR 滤波器的形式H5(z) [α(4-α)/4 (α²/2)·z^(-1) (-α3α²/4)·z^(-2)] / [1 - 2(1-α)·z^(-1) (1-α)²·z^(-2)]这个式子看着复杂但它对应的时域差分方程很简洁。设 LLT(T) 是今天的趋势线值price(T) 是今天的收盘价则LLT(T) c0·price(T) c1·price(T-1) c2·price(T-2) - d1·LLT(T-1) - d2·LLT(T-2)其中 c0 α(4-α)/4c1 α²/2c2 -α3α²/4d1 -2(1-α)d2 (1-α)²。代入 α0.05分子系数是 0.049375、0.00125、-0.048125分母反馈系数是 -1.9 和 0.9025。注意 c2 是负的这不是 bug而是二阶高通互补后的固有结构它让趋势线能紧跟拐点。LLT 唯一的参数就是 α。报告给出了与 MA 的等效换算关系 α2/(d1)d 就是「相当于多少日 MA 周期」。α 越小曲线越平滑延迟相对变大但即便 α 很小零频附近的延迟也接近 0远低于 MA 和 EMA。常用参数对照dα应用场景200.0952短周期、交易活跃300.0645上证指数择时偏优600.0328沪深 300、深证成指偏优900.0222长周期、低频过滤注意 d 只是等效概念LLT 递推并不真的使用 90 个交易日的窗口而是每个交易日都用全部历史状态递推这正是其延迟低的另一个原因。3. 用 Python 复现 LLT递推公式、切线斜率与参数扫描3.1 从传输函数到递推冷启动处理LLT 是 IIR 滤波器不能像 MA 一样用滚动窗口直接算必须按时间步递推。核心实现如下import numpy as np import pandas as pd def llt(price: pd.Series, alpha: float) - pd.Series: 低延迟趋势线 LLT按二阶低通滤波器的差分方程递推 c0 alpha * (4 - alpha) / 4.0 c1 alpha * alpha / 2.0 c2 -alpha 0.75 * alpha * alpha d1 -2.0 * (1 - alpha) d2 (1 - alpha) ** 2 out np.full(len(price), np.nan) p np.asarray(price, dtypefloat) # 前两个点直接用价格初始化避免递归冷启动产生尖刺 out[0] p[0] out[1] p[1] for i in range(2, len(price)): out[i] ( c0 * p[i] c1 * p[i - 1] c2 * p[i - 2] - d1 * out[i - 1] - d2 * out[i - 2] ) return pd.Series(out, indexprice.index)逻辑说明c0、c1、c2 是输入价格的三个前馈系数d1、d2 是历史趋势线的反馈系数。差分方程里 price 和 LLT 都要回溯两期所以前两个点没有足够历史直接拿价格本身初始化。有人习惯用 0 填充这在递推初期会造成明显的下冲尖刺滤波器要花很长时间才能稳定用价格初始化可以让 LLT 从第一个交易日就贴在价格附近。参数说明alpha 可以直接传入也可以用 alpha 2 / (d 1) 换算比如 d30 对应 alpha0.064516。d 越大c0 和 c2 的绝对值都会变小曲线更平滑递推惯性更强d 从 20 变到 90 时信号相位变化很小这是 LLT 低延迟特性的直接体现。3.2 切线斜率择时与回测骨架LLT 在正常参数下是一条平滑曲线可以近似看作处处可微。报告用向前差分计算切线斜率 k(T)LLT(T)-LLT(T-1)。k0 看多k0 看空k0 维持前向判断。回测骨架如下def llt_timing(price: pd.Series, alpha: float): tl llt(price, alpha) slope tl.diff().fillna(0.0) pos np.where(slope 0, 1, -1) pos pd.Series(pos, indexprice.index) # 第 T 日收盘后产生信号作用于 T1 日避免未来函数 daily_ret price.pct_change().fillna(0.0) strat_ret daily_ret * pos.shift(1).fillna(0.0) nav (1 strat_ret).cumprod() return nav, tl, slope, pos逻辑说明slope 是每天的切线斜率np.where 把斜率映射为 1 或 -1。pos.shift(1) 是关键一步——当天收盘价数据要等收盘后才能算出 LLT 和斜率最快也只能次日执行所以策略收益是「今日仓位乘明日收益」。如果不 shift等于用了当天的未来信息回测结果会虚高得很明显。参数说明这个框架做的是多空双向收益k0 时持空仓k0 按 -1 处理。原文回测没有计交易成本目的是观察择时信号本身的价值。实盘必须把成本加进来后面避坑部分会专门说。如果只做多头版本把 pos 在斜率小于 0 时改为 0 即可ETF 策略部分会用到。3.3 参数扫描d20/30/60/90 的收益与回撤结构LLT 只有一个参数 α等价于 d。参数怎么选直接决定信号频率和回撤结构。对同一段数据循环计算即可def scan_llt(price: pd.Series, d_list(20, 30, 60, 90)): stats {} for d in d_list: alpha 2.0 / (d 1) nav, tl, slope, pos llt_timing(price, alpha) ret nav.pct_change().fillna(0) mdd (nav / nav.cummax() - 1).min() stats[d] { 累积收益: nav.iloc[-1] - 1, 年化波动: ret.std() * np.sqrt(252), 最大回撤: mdd, 交易次数: int((pos.diff() ! 0).sum()), } return pd.DataFrame(stats).T报告用上证指数 2005 年 9 月 6 日至 2013 年 6 月 28 日的数据回测暂不计成本。统计结果如下d择时次数累积收益率收益率标准差盈利比率最大回撤平均盈亏比20182528.27%8.29%36.81%-26.96%3.32301301076.47%9.67%41.54%-21.35%3.916096683.55%10.51%37.50%-29.80%4.109081407.27%17.80%27.16%-26.94%7.73几个值得注意的点。d30 在四项里综合最优收益最高、回撤适中、盈亏比 3.91。d20 交易最频繁182 次信号灵敏度高但回撤也最大因为震荡市里来回止损多。d90 交易次数最少单笔盈利最大盈亏比 7.73但正确率只有 27.16%累积收益反而最低。这说明 LLT 参数选择不是越灵敏越好而是要匹配标的的波动周期。4. 交易性择时的收益结构低正确率、高盈亏比与长期持仓4.1 MA 择时的延迟代价看着平滑实则滞后报告先跑了一组传统 MA 的切线择时作为基准。同样是上证指数、同样的回测区间、同样按收盘价成交、暂不计成本MA20、MA30、MA60、MA90 的择时效果如下均线择时次数累积收益率收益率标准差盈利比率最大回撤平均盈亏比MA20136348.84%8.97%36.76%-30.88%3.36MA30118324.21%10.55%33.90%-33.45%4.04MA6050669.69%28.29%36.00%-15.90%9.48MA90581143.20%47.21%46.55%-13.92%11.71有意思的是MA90 累积收益 1143% 是所有 MA 里最高的回撤也只有 -13.92%但收益率标准差高达 47.21%几乎贴着单边持有的波动水平。原因不难理解90 日均线信号极少大部分时间仓位不动择时次数只有 58 次本质上是一个低换手的长周期过滤器。反过来MA20、MA30 交易频繁但每次都受延迟拖累——等斜率翻转向下时价格已经跌了一段等斜率转上时反弹也没赶上所以收益一般、回撤却不小。报告还指出一个现象2010 年之后市场波动收窄MA 择时的有效性显著下降。长均线延迟太大导致信号太钝短均线又容易被噪声欺骗传统均线的平滑性—延迟矛盾在这个阶段暴露得特别明显。对比表 1 和表 2 可以看出LLT 在同样区间内不仅收益分布更稳定而且在 2010 年之后的震荡环境里仍然能维持盈利这是 MA 做不到的。4.2 「交易性择时」的本质正确率低于 50% 依然赚钱对比两组统计可以发现一个反直觉的结论LLT 择时的盈利比率全部低于 50%d30 只有 41.54%但累积收益反而最高。这不是统计误差而是这类「交易性择时」的固有结构。原因在切线法本身。趋势拐点附近LLT 的斜率会在零轴附近来回穿越每次穿越都产生一次方向判断。这些判断大部分是错的但因为斜率刚从正变负时价格往往刚开始下跌空仓或做空的损失很小等于内嵌了一个止损机制。一旦趋势真正确立比如一轮持续上涨行情LLT 斜率会稳定为正持仓可以持续很长时间盈利主要来自这些长持仓段。所以交易性择时看重的不是「判断正确的次数比例」而是「判断正确的时间占比」。用报告的话说判断正确率相对较低时判断正确的时间占比却往往较高盈利主要来自这一部分贡献。这是和我平时习惯的「先看胜率再看盈亏比」完全不同的评估方式——对这类策略平均盈亏比和正确时间占比比胜率重要得多。4.3 不同指数有不同最优参数上证 d30沪深 300 与深证成指 d60~70模型是否稳健要在不同标的上验证。报告把 LLT 择时分别跑在上证指数、沪深 300 和深证成指上结论是模型整体都有效收益分布比 MA 更稳定但最优参数因指数而异。沪深 300 和深证成指在 d60~70 时累积收益最高上证指数则在 d30 附近较优每个指数的最优 d 并不一样。一个合理的解释是不同指数的波动结构不同。上证指数历史上有更多快牛慢熊和长期横盘短周期信号更能捕捉阶段性行情沪深 300 和深证成指里权重股占比高趋势持续时间更长需要较大 d 来过滤噪声。这也意味着LLT 做策略落地时不能「一个参数打天下」。我的习惯是先把候选标的按波动特征分组每组在样本内做 d 从 20 到 90 的滚动寻优观察收益—回撤曲面是否平滑如果最优参数附近邻居的表现相差很大说明这个参数不稳健宁可换标的也不要硬用。5. 从指数到 ETFLLT 择时落地与避坑清单5.1 ETF 趋势交易结构多空双向与只做多报告最后把 LLT 用于 ETF 趋势交易。ETF 的交易成本结构比个股更友好且跟踪指数、没有个股暴雷风险非常适合做日线级别的趋势切换。策略流程不复杂取 ETF 日线收盘价计算 LLT(d)d 先用标的所跟踪指数的历史波动特征来初选比如宽基 ETF 从 d30 开始试每日收盘后计算切线斜率 kLLT(T)-LLT(T-1)只做多版本k0 持有 ETFk0 空仓多空双向版本k0 持有或做多k0 做空或持有反向仓位次日执行调仓记录每次调仓的滑点和费用。报告对 ETF 的多空双向和只做多都做了回测结论是两种形态都能获得良好风险收益表现。只做多版本的优势是换手低、在单边下跌市里只承受空仓的机会成本而不是做空摩擦双向版本在震荡和下跌段收益更好但对执行要求更高。对普通投资者我会更推荐只做多版本先把「空仓也是一种仓位」这个纪律练好再考虑双向。5.2 避坑排查五个典型坑与解决按遇到频率排列现象LLT 递推前几十天曲线明显偏离价格甚至出现巨大尖刺。 原因初始化用了 0 或缺失值二阶递归需要两个历史状态。 解决前两个点直接用价格初始化如 3.1 节代码所示。如果仍然不稳可以把前 50 个交易日的 LLT 只用于热身不产生信号。现象斜率和零轴纠缠信号频繁翻转一周内开平仓多次。 原因切线法在拐点附近天然存在斜率零震荡LLT 延迟低反而让噪声更容易触发信号。 解决加斜率过滤带——当 |k| 小于某个阈值比如最近 20 个交易日 LLT 振幅的 5%时保持原仓位或者对 k 再做一次 3~5 日简单平均把微观毛刺滤掉再判断方向。现象回测收益高得离谱年化翻倍往上。 原因大概率用了未来函数比如当天收盘后用同一根收盘价算出信号又用当天收盘价成交等于提前知道结果。 解决严格按「T 日收盘出信号T1 日执行」的时序回测中把仓位序列 shift(1) 后再和日收益相乘。检查这一步最直接的方法是随机打乱信号序列看收益是否应声下降。现象同一套参数在上证、沪深 300 和 ETF 上效果天差地别。 原因每个标的的波动周期不同最优 d 不同属于正常现象不代表模型失效。 解决把参数寻优限制在样本内d 的候选池固定为 20~90选完后在样本外只跑一次。不要在同一个数据集上反复试参数那是在拟合噪声。现象模拟盘稳定盈利实盘 ETF 收益明显缩水。 原因回测没算交易成本、滑点和冲击成本。LLT d20 时一年可能交易上百次每次按双边费用加一两个 tick 滑点累积损耗非常可观。 解决在回测里按真实能拿到的佣金率建模滑点按 ETF 盘口最小变动价位的一半到一倍计提如果扣完成本策略从正收益变成负收益说明信号频率太高加大 d 或改用只做多版本。注意第 2 条和第 4 条是 LLT 用得最多的地方。斜率过滤带解决的是信号抖动参数分组解决的是标的适配两者叠加之后LLT 在 ETF 上的实盘体验会接近回测而不是「回测横盘、实盘打脸」。6. 进阶把 LLT 作为信号预处理层双周期确认与样本外验证LLT 最大的价值不是直接给买卖点而是把价格序列清洗成一条低延迟的趋势基准线。一旦有了这条基准线很多策略组件都可以换上去。这里给一个除了切线法之外最常用的进阶用法双周期确认。双周期确认的思路是同时计算两条不同参数的 LLT比如 d30 和 d60。只有当两条趋势线的斜率方向一致时才开仓方向不一致时空仓或维持前向判断。这样可以过滤掉大量只有短周期信号支持、长周期还在纠结的中间状态。代价是信号次数变少收益通常略低于单条 d30但回撤和交易频率都会有明显改善实盘友好度更高。def dual_llt_signal(price, d_fast30, d_slow60): fast llt(price, 2.0 / (d_fast 1)).diff().fillna(0) slow llt(price, 2.0 / (d_slow 1)).diff().fillna(0) agree np.sign(fast) np.sign(slow) pos np.where(agree (fast 0), 1, np.where(agree (fast 0), -1, 0)) return pd.Series(pos, indexprice.index)逻辑上这个信号只在高频和低频趋势线同向时输出仓位方向不一致输出 0天然规避了切线法的零轴震荡问题。参数说明d_fast 和 d_slow 的间隔不要超过一倍比如 30 和 60 合适30 和 120 就容易出现长周期一直压着短周期、信号总出不来。用最近 3~5 年的指数数据测试双周期版本的交易次数通常只有单周期的三分之一到二分之一最大回撤能收窄 5 个百分点以上代价是累积收益略低几个点。对于不愿意盯盘的交易者这个交换很划算。另一个要养成的习惯是样本外验证。记得有段时间我习惯把参数扫描放在全历史样本上找出最优 d 后直接拿同一样本的回测收益做复盘自我感觉良好后来把同样的参数挪到后一段数据上收益直接腰斩。从那以后我每次做 LLT 或者任何带参数的择时都会强制把时间轴切成两段前一段只用来选参数后一段只跑一次、记录一次、不复调参。筛选出来的 d 值会落在 20~90 之间一个平台上而不是孤峰我才敢拿它上模拟盘。这个习惯帮我避开了很多「回测漂亮、实盘翻车」的坑希望帮到你。本文还有配套的精品资源点击获取