用 Python 结合 K-Means 聚类优雅地抓取“压力位”和“支撑位”

·

支撑位阻力位 是最常挂在交易者嘴边的关键词之一:
在价格不断下探时,总有一些“地板价”把跌势托住,这被称为支撑;当多头试图冲出重围时,又会被“天花板”压回来,那便是阻力。
把这两个概念交给算法,就可能复盘、回测、甚至在高频里把“直觉”变成量化信号。本文用 K-Means 聚类 来演示怎样在 Python 中自动计算长期水平的支撑与阻力,并一步步剖析怎样做得更好。


1 支撑位与阻力位:交易心理学101

1.1 基本定义

1.2 为什么人们记得整数价位

-human bias- 让 $100$500¥70,000$1,000 成为天然的“心理关卡”。
图 1:价格为上升途中突破阻力,之后原阻力位转为支撑。

1.3 真实案例:Amazon 2018–2022

2018 年亚马逊冲高后回调,$2,020 附近多次上攻失败,形成阻力;2022 年同一价位既然又托住了瀑布式的下跌,角色立刻“反串”成支撑。


2 发现价格“滞区”的两条赛道

场景形态代表例子
长期水平多空反复争夺的价格记忆带5 年周线
短期斜线趋势线通道日内/30 分钟图

本文聚焦长期水平用法,先用 K-Means 把 5 年周线 BTC/USD 的收盘数据切成若干“价格坑”;斜线则留给你用线性回归和高低点算法继续探索。


3 K-Means 如何定位支撑阻力?

核心思路:
Adj Close 扔进 K-Means,让算法自动切分“密集区”,再把相邻区的边界当作支撑 / 阻力。流程如下:

👉 想跳过基础理论,直接捞源码?戳这看完整 notebook 示例!

3.1 环境与数据准备

pip install pandas scikit-learn plotly numpy
import pandas as pd, numpy as np, plotly.graph_objects as go
from sklearn.cluster import KMeans

# 读取 5 年周线 Bitcoin
btc = pd.read_csv('BTC-USD.2017-2022.week.csv')
btc['Date'] = pd.to_datetime(btc['Date'])
btc.set_index('Date', inplace=True)

3.2 聚类到画线 5 步走

  1. 准备价格向量

    prices = btc['Adj Close'].values.reshape(-1, 1)
  2. 跑 K-Means(K=6 起手)

    k = 6
    model = KMeans(n_clusters=k, random_state=42).fit(prices)
    labels = model.labels_
  3. 计算各区边界

    bounds = []
    for c in range(k):
        mask = labels == c
        lower, upper = prices[mask].min(), prices[mask].max()
        bounds.append((lower, upper))
    bounds = sorted(bounds, key=lambda x: x[0])
  4. 合并相邻边界(取平均值):

    lines = []
    for i, (_min, _max) in enumerate(bounds):
        if i == 0: lines.append(_min)         # 最下线
        elif i == k-1: lines.append(_max)     # 最上线
        else: lines.append((_max + bounds[i+1][0]) / 2)
    # 现在 lines 包含了 k-1 条干净的支撑阻力价位
  5. 可视化(Plotly 极简版):

    fig = go.Figure(go.Scatter(x=btc.index, y=btc['Adj Close'],
                               mode='lines', line=dict(color='black', width=1)))
    for lvl in lines[1:-1]:  # 去掉极值边界
        fig.add_hline(y=lvl, line_color='blue', opacity=.8)
    fig.update_layout(height=500, xaxis_rangeslider_visible=False)
    fig.show()

4 问:K 定几才合适?

大多数教程会教你“肘部法”,但实践证明 坐标压缩延伸 会让肘部曲线失真。
亲手遍历 k=2~9 并做市图对比更直观:

👉 想了解肘部、Silhouette、Gap 三大指标一站对比?点击查看 Demo!


5 聚合可视化:真实样貌

图 7:合并相邻边界后的水平线,把 5 年 BTC 历史切成五块定价带。
图 8:手工改线对比,发现人工经验更侧重“高低点历史回撤”——机器边界略滞后。
=> 启示:K-Means 适合“整体密度”而非“题材新闻驱动的局部大级别高低”


6 代码边界的局限与改进

  1. 极值边界失真
    把 5 年中峰顶、峰谷直接当支撑阻力会过度反应;剔除首尾一两个价位即可
  2. 滴答密度不均
    K-Means 把高容量横盘区撕开成好几段,解决办法用 加权 K-Means 或以成交量当权重。
  3. MTF 优化(Multi-TimeFrame):
    把日线、4h、周线三维数据压成一个张量用 K-Means++MiniBatchKMeans,再投影回周线,样本稀疏度显著下降。
  4. 加入斜线混合模型
    PCA + 线性回归能找到“斜率”显著的通道,再配合 K-Means 提供水平带,实现点—线—面三位一体。

7 总结

支撑与阻力归根结底是“记忆价”,而记忆价往往表现为价格的“密度中心”。
K-Means 给了我们把密度中心转成水平供给/需求带的一把快刀,但它:

因此:

把 K-Means 当“绘图板”而非“圣杯”,再用回测验证真假,才能真正吃透它。

常见问题(FAQ)

Q1:K 选错难道会让系统崩溃吗?
A:不会崩溃,只是真实成交概率直线下降。建议用回测胜率 + 集中交易分布双指标评估。

Q2:聚类法能否用于 A 股日线?
A:当然可以。前提是把节假日缺口对齐,否则聚类中心可能落在停券缺口。

Q3:是否需要分段再跑?例如牛市、熊市?
A:是的。K-Means 假设“一个分布”,把冰火两重天混一起,边界会失真;建议按 60WMA 斜率切分区,效果更稳。

Q4:为何文中剔除了最上/最下线?
A:它们往往是黑天鹅极值,并非“高概率回补区”,拿来做回测易过拟合。

Q5:能否直接拿行业平均、地产概念指数当主成分?
A:可以。宏观经济共振可能使 A 股和港、美共振,需要加权欧式距离或在张量空间聚类。


已在今日一词一句、一图一算法中,陪你走完了 “用 K-Means 计算支撑阻力” 的全程。
下一篇,我们聊 Python 里把 Bollinger、K-Means 打包成Pipeline并用网格 CV 找超参数,敬请期待。