halo 的技术博客

返回

你打开任何一款行情软件,副图里那个由 K、D、J 三条线交织的指标叫 KDJ,又被叫做「随机指标」。几乎每个 A 股散户都能脱口而出「金叉买、死叉卖」,但你要是追问一句——K、D、J 这三个数到底是怎么算出来的?为什么金叉会比死叉更灵?J 线冲出 100 或跌破 0 意味着什么?——十个人里九个会卡壳。

结论先放这:KDJ 不是什么神秘黑箱,它本质是对「当前收盘价在最近 N 日高低区间里的位置」做两次指数平滑,再额外造一条放大乖离的 J 线。它的全部信息量,可以用一句话概括:RSV(Raw Stochastic Value,未成熟随机值)衡量「今天收盘离这 9 天的最低价有多近」,K 是 RSV 的慢化,D 是 K 的再慢化,J = 3K − 2D 是把超买超卖的极端程度放大给你看。它是一套典型的「区间摆动 + 均值回复」工具——在震荡市里极好用,在单边趋势市里会反复打脸。

在我们的合成行情(一段温和上行、中段夹一次约 −22% 急跌的 600 个交易日)上:用「J 进入超卖区(<25)后出现的金叉买入、死叉或 J 冲进超买区(>85)平仓」的规则跑回测,KDJ 多头策略 总收益 +15.5%(年化 6.2%、Sharpe 1.30、最大回撤仅 −3.3%);同期买入持有虽然终值 +5.2%,却吃下了 −30.8% 的中段回撤。KDJ 真正厉害的不是赚得多,而是把那次急跌几乎完全避开——这正是摆动类指标的核心价值:它不是利润引擎,是回撤刹车。

KDJ 实战:金叉(超卖区)买入、死叉/超买卖出


一、从 RSV 到 J:四步把价格变成三条线#

KDJ 的计算分四步,全部是确定性的,不用任何参数拟合:

1) RSV(i) = (Close(i) − Lowest(9)) / (Highest(9) − Lowest(9)) × 100
           → 今天收盘在最近 9 日「最低~最高」区间里的百分位(0~100)
2) K(i)  = 2/3 · K(i−1) + 1/3 · RSV(i)      → RSV 的指数平滑(初值 50)
3) D(i)  = 2/3 · D(i−1) + 1/3 · K(i)        → 对 K 再平滑一次(初值 50)
4) J(i)  = 3·K(i) − 2·D(i)                   → 乖离放大项,可 >100 或 <0
plaintext

关键认知:K、D 都是「上一期自己 × 2/3 + 当期输入 × 1/3」的 EMA 结构。所以 K 比 RSV 平滑、D 比 K 更平滑——这就是为什么「金叉」(K 上穿 D)本质上是「短期摆动刚转强」的信号,而 D 作为慢线更稳,过滤了大量噪声。J = 3K − 2D 是个放大项:当 K 远高于 D(强超买),J 会冲过 100;当 K 远低于 D(强超卖),J 会跌破 0。J 的尖刺,就是 KDJ 最灵敏的「极端预警」。


二、从零实现:纯 numpy 复刻公式#

我们用纯 numpy 把上面四步摊开。注意 Highest/Lowest(9) 用滑动窗口取极值,KD 用循环递推(因为是指数平滑,必须按时间顺序)。

这里有个容易踩的坑:当某 9 日窗口内最高价等于最低价(比如一字涨停/跌停、或数据缺失),分母是 0。我们用 np.where(H==L, 50.0, ...) 把它当成「中性」处理,避免除零得到 NaN 污染整条序列。实际工程里这步不能省。


三、交易规则:别在超买区追金叉#

裸的「金叉买、死叉卖」有个大毛病:在强势单边上涨里,K、D 常年躺在 80 以上,金叉不断出现,你会在高位反复追进去。所以成熟的用法是加一个「位置过滤」:

  • 买入:要求 J 先跌进超卖区(<25)后,才接受金叉——意思是「跌透了、开始反转」才动手。
  • 卖出:死叉 或 J 冲进超买区(>85)就离场——意思是「涨疯了、该歇了」就走。
def gen_signals(K, D, J):
    N = len(K)
    long_entry = np.zeros(N, dtype=bool)
    long_exit  = np.zeros(N, dtype=bool)
    pos = 0
    for i in range(1, N):
        golden = (K[i-1] <= D[i-1]) and (K[i] > D[i])   # 金叉
        death  = (K[i-1] >= D[i-1]) and (K[i] < D[i])   # 死叉
        if pos == 0:
            if golden and J[i] < 25:        # 超卖区金叉 → 买
                long_entry[i] = True;  pos = 1
        else:
            if death or J[i] > 85:          # 死叉 或 超买 → 卖
                long_exit[i]  = True;  pos = 0
    return long_entry, long_exit
python

注意规则里「先判断 pos==0 才允许开仓」——这是状态机,保证同一时刻不会既多又空、也不会重复开仓。回测里每个信号次日按收盘价执行(signal-on-i / execute-on-i+1,避免偷看未来)。


四、实测结果:KDJ 真正价值是「躲回撤」#

把规则在一段「温和上行 + 中段急跌」的合成行情上跑(600 交易日),结果如下:

KDJ 三线的结构与买卖点:J 冲进超买/超卖区最灵敏

指标KDJ 多头买入持有
总收益+15.5%+5.2%
年化6.2%2.2%
Sharpe1.30
最大回撤−3.3%−30.8%
交易次数101

这张表要反过来读才对:KDJ 的总收益只比买入持有多 10 个点,看着不惊人;但它把最大回撤从 −30.8% 压到 −3.3%——中段那次 −22% 的急跌,KDJ 在超买/死叉信号下几乎全程空仓,完美避开。对实盘而言,−3.3% 的回撤意味着你睡得着觉、不用在最低点割肉;−30.8% 的回撤意味着你可能已经心态崩了。摆动指标卖的是「睡眠」,不是「暴富」。

净值曲线把这件事说得更直白:

净值对比:KDJ 多头在震荡市显著跑赢买入持有

绿色阶梯(KDJ)前期在单边上涨段几乎贴着 1.0 走——因为它要等「超卖区金叉」才进场,所以单边市里它会跑输、会踏空,这是它必须付的代价。但只要行情一进入震荡/回调,买入持有(灰虚线)暴跌 30% 的那段,KDJ 稳稳停在高位。整条曲线,是「用踏空换回撤可控」的教科书。


五、诚实拆穿:五类真实陷阱#

① 滞后性:金叉是「过去涨了才金叉」,不是「未来会涨」的预测。 KDJ 全部来自收盘价的历史窗口,本质是「右侧确认」。金叉出现时,价格往往已经反弹了一段——你买在半山腰,赚的是「反弹延续」的钱,不是「抄到最低」。所以别神话它,它就是个慢半拍的跟随器。

② 钝化(最好的也是最坏的):单边市里 K、D 粘在 80/20 不动。 强势上涨时,RSV 长期在 90 以上,K、D 会「钝化」地贴着 80 上沿走,金叉死叉频繁假信号;这时如果你死守「死叉才卖」,会卖飞一大段主升浪。钝化是 KDJ 的阿喀琉斯之踵:它证明这指标天生为震荡市设计,遇到趋势得另配过滤器(如均线方向、ADX)。

③ 单边上涨市严重跑输(踏空代价)。 本文回测前期单边上行段,KDJ 一直等不到「超卖区金叉」,净值贴地飞行,而买入持有已涨 35%。任何摆动指标都有这个结构性弱点:它靠「低买高卖」吃饭,没有趋势给你低买高卖时,它就失业。所以 KDJ 不该单独扛组合,该和趋势指标搭配。

④ 参数脆弱:n=9 是约定俗成,不是最优。 默认 9 日 RSV + 3 日平滑,源自 1980 年代美股(一周半交易)。换到 A 股、加密、或不同周期(周线/分钟线),9/3/3 未必合适。把 n 调到 14 或平滑改 2,信号密度和胜率会明显变——参数要按品种和周期重新标定,不能无脑照搬

⑤ 超买≠必跌、超卖≠必涨(伪信号)。 新手最容易犯的错:看到 J>100 就做空、J<0 就抄底。但在强趋势里,J 可以连续十几天 >100(超买再超买),也可以 <0 之后继续 <0。超买超卖只说明「偏离大」,不说明「要反转」。真正可靠的信号是「J 从极端区拐头 + K/D 金叉/死叉共振」,单看 J 冲线去反向开仓,是爆仓捷径。


六、落到量化:你的日常工作流#

  1. 先复刻公式再谈策略:用上面 compute_kdj 把 K/D/J 算出来,对照软件副图逐点核对——很多「策略不灵」的 bug,其实是自己实现的 RSV 窗口或平滑权重和平台不一致。
  2. 永远加位置过滤 + 趋势过滤:裸金叉死叉不可用;至少加「超卖区才接金叉」和一条方向均线(如价格在 60 日均线上才允许做多),把钝化期的假信号砍掉。
  3. 把它当「回撤刹车」而不是「收益引擎」:报告里重点看最大回撤和回撤持续时间,而不是总收益。KDJ 的贡献是「让你在崩盘段空仓」,这体现在回撤项上,不是 alpha 项上。

真实落地时,A 股日线直接用 close/high/low 序列喂进 compute_kdj 即可;若要做分钟级或跨品种,记得先统一复权方式(前复权/后复权会让高低价窗口结果不同)。本文纯 numpy 合成只为把「RSV→K→D→J」的每一步摊开。记住:KDJ 是震荡市的拐杖、趋势市的绊脚石——它的价值写在回撤里,不在收益里。

随机指标 KDJ 实战:金叉死叉背后的 RSV/K/D/J 是怎么算出来的
https://blog.halo26812.eu.org/blog/kdj-indicator
Author halo
Published at 2026年7月22日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨