HH-HL-LH-LL市场结构指标:摆动点识别与BOS/CHoCH的量化实现
免责声明:本文所述技术内容仅供学习交流,不构成任何投资建议。金融市场存在风险,过往表现不代表未来结果,请根据自身情况谨慎决策。
价格行为交易里,市场结构是最底层的逻辑。HH、HL、LH、LL 这四个字母组合,把趋势的骨架画了出来:高点越来越高、低点也越来越高,就是上升趋势;反之就是下降趋势。结构突破(BOS)和性质改变(CHoCH)则是趋势延续和反转的关键信号。今天拆解的这个指标,用纯算法把这一套结构识别自动化了。
一、摆动点的数学定义
摆动高点(Swing High)和摆动低点(Swing Low)是结构分析的基础。一个点要成为摆动高点,必须在其左右两侧各 N 根 K 线内都是局部最高点;摆动低点同理,左右两侧都是局部最低点。这个 N 就是「回溯周期」,默认 5 表示左右各 5 根,共 11 根 K 线参与判定。
// 摆动高点判定:中心点必须比左右各 lookback 根都高for ( int j = 1; j<=inp_market_structure_swing_lookback; j++ ){if ( high[i - j] >= h_center || high[i + j] >= h_center ) is_sh = false;}// 摆动低点判定:中心点必须比左右各 lookback 根都低for ( int j = 1; j<=inp_market_structure_swing_lookback; j++ ){if ( low[i - j] <= l_center || low[i + j] <= l_center ) is_sl = false;}
h_center 和 l_center 是当前 K 线的高低价。只要左右任意一侧有更高或更低的点,就否定摆动点身份。这种对称判定保证了每个摆动点都是「局部极值」,不会被单边噪音干扰。

二、HH/HL/LH/LL 的分类逻辑
识别出摆动点后,下一步是打标签。高点序列里:比前一个摆动高点更高的是 HH(Higher High),更低的是 LH(Lower High);低点序列里:比前一个摆动低点更高的是 HL(Higher Low),更低的是 LL(Lower Low)。第一个点没有参照,标为 LBL_NONE。
for ( int i = 0; i<g_count; i++ ){if ( g_is_high[i] ) {if ( !has_prev_high ) { g_label[i] = LBL_NONE; has_prev_high = true; }else { g_label[i] = (g_price[i] > prev_high) ? LBL_HH : LBL_LH; } prev_high = g_price[i]; }else {if ( !has_prev_low ) { g_label[i] = LBL_NONE; has_prev_low = true; }else { g_label[i] = (g_price[i] > prev_low) ? LBL_HL : LBL_LL; } prev_low = g_price[i]; }}
用 prev_high 和 prev_low 记录上一个同类型摆动点的价格,当前点与之比较即可完成分类。HH+HL 的连续出现对应上升趋势,LH+LL 对应下降趋势。
三、BOS 与 CHoCH 的触发条件
BOS(Break of Structure)是趋势延续信号:上升趋势中,价格突破前一个摆动高点形成新的 HH,就是 BOS;下降趋势中,突破前一个摆动低点形成新的 LL,也是 BOS。CHoCH(Change of Character)是趋势反转信号:原本在走 LH+LL,突然出现 HH 或 HL,说明空头结构被打破,可能转为多头;反之亦然。
指标用 trend 变量追踪当前结构方向,遍历每个已分类的摆动点时更新:
if ( lbl == LBL_HH || lbl == LBL_HL ){if ( trend == "BEAR" && inp_market_structure_show_choch ) DrawBOSLine(i, "CHoCH", inp_market_structure_choch_color);elseif ( trend == "BULL" && lbl == LBL_HH && inp_market_structure_show_bos ) DrawBOSLine(i, "BOS", inp_market_structure_bos_color); trend = "BULL";}elseif ( lbl == LBL_LH || lbl == LBL_LL ){if ( trend == "BULL" && inp_market_structure_show_choch ) DrawBOSLine(i, "CHoCH", inp_market_structure_choch_color);elseif ( trend == "BEAR" && lbl == LBL_LL && inp_market_structure_show_bos ) DrawBOSLine(i, "BOS", inp_market_structure_bos_color); trend = "BEAR";}
当 trend 是 BEAR 时遇到 HH/HL,说明空头结构被打破,画 CHoCH;当 trend 是 BULL 时遇到新的 HH,画 BOS。下降趋势同理。这样 BOS 和 CHoCH 的语义就清晰了。
四、增量计算与性能优化
K 线一根根来,如果每次都全量重算,在长周期图表上会拖慢。指标做了增量逻辑:只有在新 K 线确认时(time[rates_total-1] != g_last_bar_time)才触发计算;且当 prev_calculated > 0 时,只检查「刚确认」的那根 K 线是否形成新摆动点,而不是从头扫到尾。
if ( time[rates_total - 1] == g_last_bar_time && prev_calculated > 0 )return (rates_total);g_last_bar_time = time[rates_total - 1];// 增量模式:只检查 rates_total-1-swing_lookback 这根int check = rates_total - 1 - inp_market_structure_swing_lookback;if ( check < inp_market_structure_swing_lookback ) return (rates_total);bool new_swing = false;// 只对这一根做摆动判定...if ( new_swing ){ ClassifySwings(); DrawAll();}
摆动点的确认有滞后:一根 K 线要成为摆动高点,必须等右侧 N 根走完才能判定。所以 check 取的是「当前已确认」的最右一根,避免对未确认的 K 线做无效计算。
五、结构线的绘制与同类型连接
除了标签,指标还会把同类型的摆动点用虚线连起来。高点连高点,低点连低点,每个点只连到「前一个同类型且已分类」的点:
for ( int j = i - 1; j>=0; j-- ){if ( g_is_high[j] == g_is_high[i] && g_label[j] != LBL_NONE ) {string ln = g_prefix + "SL" + IntegerToString(i);if ( ObjectCreate(0, ln, OBJ_TREND, 0, g_time[j], g_price[j], g_time[i], g_price[i]) ) { ObjectSetInteger(0, ln, OBJPROP_STYLE, STYLE_DOT); ObjectSetInteger(0, ln, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, ln, OBJPROP_BACK, true); }break; }}
STYLE_DOT 表示虚线,RAY_RIGHT 关掉避免向右无限延伸,BACK 打开让线画在 K 线后面。BOS/CHoCH 的水平线用 STYLE_DASH,在前后两个摆动点之间取中点打标签,方便一眼看出突破位置。
这个指标把摆动点识别、HH/HL/LH/LL 分类、BOS/CHoCH 检测串成一条流水线,适合作为结构分析的辅助工具。关注公众号「超哥量化」,获取更多量化策略源码与学习资料,支持量化学习与产品定制开发。



评论