社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

新高新低指标(NH-NL):原理、应用与Python实现

量化OK投研交流 • 7 月前 • 470 次点击  


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

新高新低指标(New Highs-New Lows,NH-NL)是衡量市场广度和趋势强度的核心技术指标,通过统计一定周期内创阶段新高/新低的标的数量,判断市场整体强弱、趋势持续性及反转信号,适用于股票、指数、行业板块等宽基市场分析,是量化策略中“择时+仓位管理”的关键工具。

一、核心原理:用“市场广度”反映趋势本质

1. 定义与核心逻辑

市场趋势的本质是“多数标的的一致性运动”:

  • • 当大量标的同步创阶段新高,说明多头力量占优,上涨趋势具备广度和持续性;
  • • 当大量标的同步创阶段新低,说明空头力量占优,下跌趋势未结束;
  • • 若新高/新低数量背离(如指数创新高但新高标的数减少),预示趋势可能反转。

2. 核心指标公式

新高新低指标有3个核心维度,需结合使用:

指标名称
计算公式
含义
新高数(NH)
统计周期内,收盘价创N日新高的标的数量(N常见20/50/60/120日,代表不同周期)
反映多头力量的广度(数量越多,多头越强)
新低数(NL)
统计周期内,收盘价创N日新低的标的数量
反映空头力量的广度(数量越多,空头越强)
新高新低差(NH-NL)
新高数 - 新低数
整体市场情绪(正数=多头占优,负数=空头占优,绝对值越大趋势越强)
新高新低比率(NH/NL)
新高数 / 新低数(NL=0时取极大值)
相对强弱(比值>3=极端多头,比值<0.3=极端空头)

3. 关键参数说明

  • • 统计周期N
    • • 短期:20/30日(反映短期市场情绪,适合短线择时);
    • • 中期:60/90日(反映中期趋势,适合波段操作);
    • • 长期:120/250日(反映长期趋势,适合仓位管理);
  • • 统计范围:可选择全市场(如A股全个股)、行业板块(如半导体板块)、指数成分股(如沪深300成分股);
  • • 新高/新低判定:当日收盘价>过去N个交易日收盘价→创N日新高;当日收盘价<过去N个交易日收盘价→创N日新低(等于不算)。

二、核心应用:趋势判断与反转信号

1. 基础应用:趋势强度判断

通过NH-NL差值/比率判断市场整体状态,指导仓位管理:

指标特征
市场状态
操作建议
NH-NL>0且持续扩大
多头趋势确认
重仓(如80%-100%),持有趋势型标的
NH-NL>0但逐步收窄
多头趋势衰减
减仓(如50%-60%),警惕反转
NH-NL<0且绝对值扩大
空头趋势确认
轻仓/空仓(0%-20%),避免抄底
NH-NL<0但绝对值收窄
空头趋势衰减
小仓位试错(20%-30%),等待反转信号
NH=NL(差值≈0)
震荡市
中性仓位(40%-50%),波段交易为主

2. 进阶应用:背离信号(核心用法)

新高新低指标的最大价值是识别“指数与广度的背离”,预判趋势反转:

(1)顶背离(下跌预警)

  • • 特征:指数创阶段新高,但同期新高数(NH)未同步新高,甚至减少;
  • • 逻辑:指数上涨仅由少数权重股推动,多数标的未跟随,“赚指数不赚钱”,上涨趋势无广度;
  • • 案例:沪深300创年内新高,但20日新高标的数从500只降至200只→后续指数回调概率80%+。

(2)底背离(上涨预警)

  • • 特征:指数创阶段新低,但同期新低数(NL)未同步新低,甚至减少;
  • • 逻辑:指数下跌仅由少数权重股拖累,多数标的已止跌,下跌趋势无广度;
  • • 案例:创业板指创年内新低,但20日新低标的数从400只降至100只→后续指数反弹概率80%+。

3. 实战技巧:多周期共振

单一周期易失真,需结合短/中/长期新高新低指标:

  • • 短(20日)+ 中(60日)+ 长(120日)NH-NL均为正→强多头趋势,持仓不动;
  • • 短NH-NL为正,但中/长为负→反弹行情,快进快出;
  • • 短NH-NL为负,但中/长为正→回调行情,可低吸。

4. 适用场景与注意事项

适用场景

  • • 宽基指数择时(如沪深300、创业板指);
  • • 行业板块轮动(如筛选NH-NL持续为正的板块);
  • • 量化策略仓位管理(根据NH-NL绝对值调整仓位);
  • • 反转信号确认(结合背离判断指数顶底)。

注意事项

  • • 避免单一个股分析:新高新低是“广度指标”,对单一个股无意义,仅适用于多标的市场;
  • • 剔除异常标的:统计时需排除停牌、ST、新股(上市<N日),避免数据失真;
  • • 结合成交量:NH-NL扩大+成交量放大,趋势更具持续性;NH-NL扩大但成交量萎缩,趋势易反转。

三、Python实战实现(基于A股全市场数据)

以下代码以“A股全个股20日新高新低”为例,实现指标计算、可视化及背离信号检测,适配量化回测场景。

1. 核心代码

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

# 初始化tushare(需注册获取token)
ts.set_token("你的tushare_token")
pro = ts.pro_api()

def get_stock_list():
    """获取A股全市场股票列表(剔除ST、停牌、新股)"""
    # 获取基础股票列表
    stock_basic = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name,list_date')
    # 剔除上市不足20日的新股
    stock_basic['list_date'] = pd.to_datetime(stock_basic['list_date'])
    stock_basic = stock_basic[stock_basic['list_date'] < pd.Timestamp.now() - pd.Timedelta(days=20)]
    # 剔除ST股(可根据需要补充停牌筛选)
    stock_basic = stock_basic[~stock_basic['name'].str.contains('ST', na=False)]
    return stock_basic['ts_code'].tolist()

def calculate_nh_nl(stock_codes, start_date, end_date, period=20):
    """
    计算指定周期内的新高新低指标
    :param stock_codes: 股票代码列表
    :param start_date: 开始日期(格式:YYYYMMDD)
    :param end_date: 结束日期(格式:YYYYMMDD)
    :param period: 新高/新低统计周期(默认20日)
    :return: 每日NH、NL、NH-NL、NH/NL的DataFrame
    """

    # 初始化结果字典
    nh_nl_dict = {
        'trade_date': [],
        'nh': [],  # 新高数
        'nl': [],  # 新低数
        'nh_nl_diff': [],  # 新高-新低
        'nh_nl_ratio': []  # 新高/新低
    }
    
    # 获取全市场交易日列表
    trade_cal = pro.trade_cal(exchange='SSE', start_date=start_date, end_date=end_date)
    trade_dates = trade_cal[trade_cal['is_open'] == 1]['cal_date'].tolist()
    
    # 遍历每个交易日,计算当日NH/NL
    for trade_date in trade_dates:
        print(f"计算{trade_date}新高新低...")
        nh_count = 0
        nl_count = 0
        
        # 批量获取当日全市场股票收盘价(tushare单次最多取500只,需分批)
        batch_size = 500
        for i in range(0len(stock_codes), batch_size):
            batch_codes = stock_codes[i:i+batch_size]
            # 获取该批次股票的period+1日收盘价(需历史数据判断新高/新低)
            try:
                df = pro.daily(
                    ts_code=','.join(batch_codes),
                    start_date=str(int(trade_date) - period*100),  # 往前推period天(简化处理)
                    end_date=trade_date
                )
                if df.empty:
                    continue
                
                # 按股票代码分组,计算每只股票的新高/新低
                for ts_code, group in df.groupby('ts_code'):
                    # 按日期排序,确保数据连续
                    group = group.sort_values('trade_date')
                    if len(group) < period:
                        continue  # 数据不足period天,跳过
                    
                    # 取最新收盘价和过去period日收盘价
                    latest_close = group['close'].iloc[-1]
                    past_close = group['close'].iloc[:-1][-period:]  # 过去period日收盘价
                    
                    # 判断是否创period日新高
                    if latest_close > past_close. max():
                        nh_count += 1
                    # 判断是否创period日新低
                    if latest_close < past_close.min():
                        nl_count += 1
            except Exception as e:
                print(f"批量获取数据失败:{e}")
                continue
        
        # 计算衍生指标
        nh_nl_diff = nh_count - nl_count
        nh_nl_ratio = nh_count / nl_count if nl_count != 0 else np.inf
        
        # 存入结果
        nh_nl_dict['trade_date'].append(trade_date)
        nh_nl_dict['nh'].append(nh_count)
        nh_nl_dict['nl'].append(nl_count)
        nh_nl_dict['nh_nl_diff'].append(nh_nl_diff)
        nh_nl_dict['nh_nl_ratio'].append(nh_nl_ratio)
    
    # 转换为DataFrame并整理
    nh_nl_df = pd.DataFrame(nh_nl_dict)
    nh_nl_df['trade_date'] = pd.to_datetime(nh_nl_df['trade_date'])
    nh_nl_df = nh_nl_df.sort_values('trade_date').reset_index(drop=True)
    
    return nh_nl_df

def detect_divergence(nh_nl_df, index_df, period=20):
    """
    检测指数与新高新低的背离信号
    :param nh_nl_df: 新高新低指标DataFrame
    :param index_df: 指数收盘价DataFrame(含trade_date、close)
    :param period: 背离检测周期(默认20日)
    :return: 含背离信号的DataFrame
    """

    # 合并新高新低和指数数据
    merge_df = pd.merge(nh_nl_df, index_df, on='trade_date', how='inner')
    merge_df.rename(columns={'close''index_close'}, inplace=True)
    
    # 计算指数和NH的20日最大值(用于判断背离)
    merge_df['index_high_20'] = merge_df['index_close'].rolling(window=period).max()
    merge_df['nh_high_20'] = merge_df['nh'].rolling(window=period).max()
    
    # 顶背离:指数创新高,但NH未创新高
    merge_df['top_divergence'] = (merge_df['index_close'] == merge_df['index_high_20']) & \
                                 (merge_df['nh'] < merge_df['nh_high_20'])
    
    # 底背离:指数创新低,但NL未创新低
    merge_df['index_low_20'] = merge_df['index_close'].rolling(window=period).min()
    merge_df['nl_low_20'] = merge_df['nl'].rolling(window=period).min()
    merge_df['bottom_divergence'] = (merge_df['index_close'] == merge_df['index_low_20']) & \
                                    (merge_df['nl'] < merge_df['nl_low_20'])
    
    return merge_df

def plot_nh_nl(nh_nl_df, index_df=None):
    """可视化新高新低指标及指数背离"""
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    
    fig, (ax1, ax2) = plt.subplots(21, figsize=(1410), sharex=True)
    
    # 子图1:NH、NL、NH-NL差值
    ax1.plot(nh_nl_df['trade_date'], nh_nl_df['nh'], color='red', label='20日新高数(NH)')
    ax1.plot(nh_nl_df['trade_date'], nh_nl_df['nl'], color='green', label='20日新低数(NL)')
    ax1.plot(nh_nl_df['trade_date'], nh_nl_df['nh_nl_diff'], color='blue', label='NH-NL差值', linestyle='--')
    ax1.axhline(y=0, color='black', alpha=0.3, linestyle='-')
    ax1.set_title('A股全市场20日新高新低指标')
    ax1.set_ylabel('数量')
    ax1.legend()
    ax1.grid(alpha=0.3)
    
    # 子图2:指数+背离信号(若传入指数数据)
    if index_df is not None:
        merge_df = pd.merge(nh_nl_df, index_df, on='trade_date', how='inner')
        ax2.plot(merge_df['trade_date'], merge_df['close'], color='black', label='沪深300指数')
        # 标记顶背离(红色三角)和底背离(绿色三角)
        top_div = merge_df[merge_df['top_divergence'] == True]
        bottom_div = merge_df[merge_df['bottom_divergence'] == True]
        ax2.scatter(top_div['trade_date'], top_div['close'], color='red', marker='^', s=100, label='顶背离')
        ax2.scatter(bottom_div['trade_date'], bottom_div['close'], color='green', marker='v', s=100, label='底背离')
        ax2.set_ylabel('指数收盘价')
        ax2.legend()
        ax2.grid(alpha=0.3)
    
    plt.xlabel('日期')
    plt.tight_layout()
    plt.show()

# --------------- 主函数调用 ---------------
if __name__ == "__main__":
    # 1. 获取A股股票列表
    stock_codes = get_stock_list()
    print(f"有效股票数量: {len(stock_codes)}")
    
    # 2. 计算2024年1-6月的20日新高新低指标
    nh_nl_df = calculate_nh_nl(
        stock_codes=stock_codes,
        start_date="20240101",
        end_date="20240630",
        period=20
    )
    
    # 3. 获取沪深300指数数据(用于背离检测)
    index_df = pro.index_daily(ts_code='000300.SH', start_date='20240101', end_date='20240630')
    index_df['trade_date'] = pd.to_datetime(index_df['trade_date'])
    index_df = index_df.sort_values('trade_date').reset_index(drop=True)
    
    # 4. 检测背离信号
    merge_df = detect_divergence(nh_nl_df, index_df, period=20)
    
    # 5. 可视化
    plot_nh_nl(nh_nl_df, index_df)
    
    # 6. 输出结果
    print("新高新低指标(最后10日):")
    print(nh_nl_df.tail(10)[['trade_date''nh''nl''nh_nl_diff''nh_nl_ratio']])

2. 代码说明

(1)数据获取层

  • •  get_stock_list():筛选有效标的(剔除ST、新股、停牌股),保证统计广度;
  • • pro.daily():批量获取股票/指数收盘价,适配tushare分批限制(单次500只)。

(2)指标计算层

  • • 遍历每个交易日,统计全市场创20日新高/新低的标的数量;
  • • 计算NH-NL差值(整体情绪)、NH/NL比率(相对强弱),处理NL=0时的除零异常。

(3)信号检测层

  • • detect_divergence():通过滚动窗口判断“指数新高但NH未新高(顶背离)”“指数新低但NL未新低(底背离)”;
  • • 顶/底背离是趋势反转的核心信号,量化策略中可作为“减仓/加仓”的触发条件。

(4)可视化层

  • • 分两行展示“新高新低数量+指数走势”,直观标记背离信号,便于策略分析。

3. 轻量化实现(单标的/小样本)

若无需全市场数据,仅分析单指数/板块成分股,可简化代码:

def calculate_nh_nl_light(df, close_col='close', period=20):
    """
    轻量化版:计算单DataFrame内的新高新低(如板块成分股)
    :param df: 含code、trade_date、close的DataFrame
    :return: 每日NH/NL
    """

    # 按日期分组,计算每日新高/新低数
    df['high_roll'] = df.groupby('code')[close_col].rolling(period).max().reset_index(0, drop=True)
    df['low_roll'] = df.groupby('code')[close_col].rolling(period).min().reset_index(0, drop=True)
    df['is_nh'] = df[close_col] > df['high_roll'].shift(1)  # 创period日新高
    df['is_nl'] = df[close_col] < df['low_roll'].shift(1)  # 创period日新低
    
    # 按日期统计数量
    nh_nl = df.groupby('trade_date').agg(
        nh=('is_nh''sum'),
        nl=('is_nl''sum')
    ).reset_index()
    nh_nl['nh_nl_diff'] = nh_nl['nh'] - nh_nl['nl']
    nh_nl['nh_nl_ratio'] = nh_nl['nh'] / nh_nl['nl'].replace(0, np.inf)
    
    return nh_nl

四、实战策略集成示例

新高新低指标可直接融入量化策略的择时逻辑,以下是“沪深300指数增强策略”的核心逻辑:

def strategy_nh_nl(merge_df):
    """
    基于新高新低的择时策略
    规则:
    1. NH-NL>100 → 满仓(100%)
    2. 0<NH-NL≤100 → 半仓(50%)
    3. NH-NL≤0 → 空仓(0%)
    4. 顶背离 → 强制减仓至20%
    5. 底背离 → 强制加仓至80%
    """

    merge_df['position'] = 0.0
    # 基础仓位
    merge_df.loc[merge_df['nh_nl_diff'] > 100'position'] = 1.0
    merge_df.loc[(merge_df['nh_nl_diff'] > 0) & (merge_df['nh_nl_diff'] <= 100), 'position'] = 0.5
    # 背离修正
    merge_df.loc[merge_df['top_divergence'] == True'position'] = 0.2
    merge_df.loc[merge_df['bottom_divergence'] == True'position'] = 0.8
    
    # 计算策略收益
    merge_df['index_return'] = merge_df['index_close'].pct_change()
    merge_df['strategy_return'] = merge_df['index_return'] * merge_df['position'].shift(1)
    merge_df['strategy_nav'] = (1 + merge_df['strategy_return']).cumprod()
    
    # 输出策略绩效
    print(f"策略累计收益:{(merge_df[ 'strategy_nav'].iloc[-1]-1)*100:.2f}%")
    print(f"指数累计收益:{(merge_df['index_close'].iloc[-1]/merge_df['index_close'].iloc[0]-1)*100:.2f}%")
    
    return merge_df

# 调用策略
merge_df = strategy_nh_nl(merge_df)

五、关键优化与注意事项

1. 数据优化

  • • 补充复权收盘价:使用前复权价格计算新高/新低,避免除权除息导致的虚假新高/新低;
  • • 处理停牌数据:停牌标的按“最后收盘价”填充,避免统计遗漏。

2. 参数优化

  • • 周期适配:短线策略用20日,中长线用60/120日;
  • • 阈值校准:全市场NH-NL差值的阈值需根据市场规模调整(如A股全市场NH-NL>500为强多头)。

3. 策略优化

  • • 结合成交量:NH-NL扩大+成交量放大,趋势确认;NH-NL扩大但成交量萎缩,趋势存疑;
  • • 多指标共振:新高新低+均线(如指数站上60日线),提高信号胜率。

总结

新高新低指标的核心价值在于“脱离指数权重陷阱,反映真实市场广度”:

  • • 原理上,通过“多数标的的一致性运动”判断趋势,比单一指数更贴近市场本质;
  • • 应用上,是趋势强度判断、反转信号检测、仓位管理的核心工具;
  • • 实现上,需注意数据广度(全市场/板块)、周期适配(短/中/长期)、背离检测(核心信号)。

对量化策略而言,新高新低指标是“择时体系”的基础组件,结合均线、成交量、情绪指标(如PSY)可大幅提升策略胜率,尤其适合宽基指数的趋势性交易和仓位管理。


 


 

 

 

 


风险提示:本文仅作为知识分享,模拟测试不构成任何投资建议,不作投资依据。
图片



END
图片
如需 策略源文件→扫一扫成为星球会员
图片
如需系统学习Python→购买成为量化高手

 

 

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/189924