前言

WR(Williams %R,威廉指标)是短线交易常用的超买超卖指标,擅长捕捉股价短期高低拐点。WR和RSI原理相近,但WR灵敏度更高,经常提前发出反转信号,适合震荡行情抄底、逃顶。

很多同学自己写WR时容易踩坑:分子分母写反、忘记乘以负号,最终计算结果和通达信、东方财富不一致。本文严格遵循通达信原版公式,使用Pandas原生实现,不依赖TA-Lib,附带绘图展示、自动交易信号识别,全部代码可直接复制运行,能够接入量化回测系统。

⚠️ 重要声明:本文仅作为Python量化编程学习,不构成任何投资建议。

一、WR指标原理与通达信计算公式

指标简介

WR威廉指标,利用一段时间内最高价、最低价与当前收盘价的相对位置,判断股价是否处于短期极端高位/低位。
A股软件默认双周期参数:WR1=10,WR2=20

通达信原版公式

HH:=HHV(HIGH,N);
LL:=LLV(LOW,N);
WR:=(HH-CLOSE)/(HH-LL)*100;
WR指标 = -WR

数学公式:
WR=−HHN−CloseHHN−LLN×100WR = -\frac{HH_N - Close}{HH_N - LL_N} \times 100WR=HHNLLNHHNClose×100

  • HHNHH_NHHN:N周期内最高价
  • LLNLL_NLLN:N周期内最低价
  • CloseCloseClose:当日收盘价

重点提醒:最终结果需要取负数!区间范围 [-100, 0]

WR指标基础交易规则

  1. 超买区(0 ~ -20)
    股价短期上涨过多,多头动能衰竭,有回调风险,止盈、减仓信号。
  2. 超卖区(-80 ~ -100)
    短期持续下跌,空头释放充分,反弹概率加大,关注低吸机会。
  3. 中性区间(-20 ~ -80)
    多空相对均衡,没有明确超买超卖信号,观望为主。
  4. 双周期共振
    WR1、WR2同时进入超卖区,底部信号可靠性更高;同时进入超买区,回落风险加大。

二、环境依赖

pip install pandas numpy matplotlib

三、Python实现WR指标计算

3.1 封装通用WR计算函数

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def calc_wr(df, high_col="high", low_col="low", close_col="close", n1=10, n2=20):
    """
    复刻通达信 WR威廉指标
    :param df: K线DataFrame,必须包含 high low close
    :param high_col: 最高价列名
    :param low_col: 最低价列名
    :param close_col: 收盘价列名
    :param n1: WR1短期周期 默认10
    :param n2: WR2长期周期 默认20
    :return: 添加 WR1 WR2 后的DataFrame
    """
    data = df.copy()

    # N周期最高价、最低价
    hh_n1 = data[high_col].rolling(window=n1).max()
    ll_n1 = data[low_col].rolling(window=n1).min()
    hh_n2 = data[high_col].rolling(window=n2).max()
    ll_n2 = data[low_col].rolling(window=n2).min()

    # 防止除零(横盘,最高价=最低价)
    # WR1
    denom1 = hh_n1 - ll_n1
    wr1_raw = np.where(denom1 == 0, 0, (hh_n1 - data[close_col]) / denom1 * 100)
    data["WR1"] = -wr1_raw

    # WR2
    denom2 = hh_n2 - ll_n2
    wr2_raw = np.where(denom2 == 0, 0, (hh_n2 - data[close_col]) / denom2 * 100)
    data["WR2"] = -wr2_raw

    return data

3.2 模拟行情数据测试

if __name__ == "__main__":
    np.random.seed(666)
    base_price = 12
    data_list = []
    for i in range(180):
        change = np.random.normal(0, 0.22)
        close = round(base_price + change, 2)
        high = round(close + abs(np.random.normal(0, 0.1)), 2)
        low = round(close - abs(np.random.normal(0, 0.1)), 2)
        data_list.append({"high": high, "low": low, "close": close})
        base_price = close

    df = pd.DataFrame(data_list)
    df["date"] = pd.date_range(start="2026-01-01", periods=180, freq="D")

    # 计算WR
    df = calc_wr(df)
    print(df[["date", "close", "WR1", "WR2"]].tail(15))

前N-1行数据会是NaN,属于正常现象,滚动窗口需要足够K线数量。

四、WR指标可视化绘图

上下双图:上图股价,下图WR曲线,同时画出-20、-80两条分界线,贴近行情软件样式:

def plot_wr_chart(df):
    plt.rcParams["font.sans-serif"] = ["SimHei"]
    plt.rcParams["axes.unicode_minus"] = False

    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14,8), sharex=True, gridspec_kw={"height_ratios":[2,1]})

    # 上图:收盘价走势
    ax1.plot(df["date"], df["close"], c="#f5222d", linewidth=1.6, label="收盘价")
    ax1.set_title("股价走势 + WR威廉指标", fontsize=14)
    ax1.set_ylabel("价格")
    ax1.legend()
    ax1.grid(alpha=0.3)

    # 下图 WR曲线
    ax2.plot(df["date"], df["WR1"], c="#1890ff", linewidth=1.3, label="WR1(10)")
    ax2.plot(df["date"], df["WR2"], c="#fa8c16", linewidth=1.3, label="WR2(20)")
    # 超买超卖分界线
    ax2.axhline(y=-20, c="red", linestyle="--", alpha=0.6)
    ax2.axhline(y=-80, c="green", linestyle="--", alpha=0.6)
    ax2.set_ylabel("WR")
    ax2.legend()
    ax2.grid(alpha=0.3)

    plt.tight_layout()
    plt.show()

plot_wr_chart(df)

五、自动识别WR交易信号

根据超买超卖区间生成信号,方便策略回测:

def generate_wr_signal(df):
    data = df.copy()
    signal_list = []
    for _, row in data.iterrows():
        wr1 = row["WR1"]
        wr2 = row["WR2"]
        if pd.isna(wr1) or pd.isna(wr2):
            signal_list.append(None)
            continue

        # 双周期同时进入超卖区:低吸信号
        if wr1 <= -80 and wr2 <= -80:
            signal_list.append("buy")
        # 双周期同时进入超买区:卖出信号
        elif wr1 >= -20 and wr2 >= -20:
            signal_list.append("sell")
        else:
            signal_list.append(None)
    data["wr_signal"] = signal_list
    return data

df = generate_wr_signal(df)

buy_signal = df[df["wr_signal"] == "buy"]
sell_signal = df[df["wr_signal"] == "sell"]

print("====WR超卖低吸信号====")
print(buy_signal[["date","close","WR1","WR2"]])
print("\n====WR超买卖出信号====")
print(sell_signal[["date","close","WR1","WR2"]])

六、开发高频踩坑总结

1. 分子分母写反(最常见错误)

错误写法:(Close - LL)/(HH-LL)
正确写法:(HH - Close)/(HH-LL)
顺序颠倒会直接导致指标走势完全反向。

2. 忘记乘以负号

部分国外资料WR范围是0~100,而国内通达信统一 [-100,0],计算完成后必须取负,否则区间和信号全部相反。

3. 缺少除零保护

长期横盘个股,周期内最高价等于最低价 HH-LL=0,直接除法会触发inf无穷值,代码中需要增加判断规避。

4. WR不适合单边大趋势

持续牛市,WR会长时间处于超买区间;持续熊市,长期处于超卖区间。单纯依靠WR极易出现持续假信号,建议搭配趋势指标MACD、均线组合使用。

5. 忽略周期参数

短线交易用10周期,中长线可调整20、30周期,参数越大指标越平滑、灵敏度越低。

七、拓展方向

  1. 接入Akshare / Tushare获取A股真实日线、分钟K数据;
  2. 增加WR背离检测(顶背离、底背离);
  3. WR+MACD共振策略开发与历史回测;
  4. 封装为API接口,供前端量化页面实时计算指标;
  5. 结合仓位管理规则构建完整交易策略。

八、总结

  1. WR威廉指标核心是利用周期高低点相对位置判断超买超卖;复刻通达信重点注意分子顺序 + 末尾取负数
  2. 默认双周期WR1(10)、WR2(20)共振使用,信号稳定性高于单周期;
  3. WR优势是反应灵敏、提前捕捉拐点,短板是单边行情容易持续失真;
  4. 量化开发优先手写指标,摆脱第三方库黑盒,便于自定义修改、问题排查与策略调试。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐