作 者:老余捞鱼
原创不易,转载请标明出处及原作者。

写在前面的话:今天教大家一个量化分析股票资金流向的硬核方法,把成交量按价格和方向画成图,一眼看穿多空力量对比!这个工具能帮你找到主力真实意图,轻松识别关键支撑阻力位。文中有完整代码,手把手教你实现。
一、什么是市场压力可视化?
你是不是经常盯着K线图里的成交量柱子发懵。
- 传统成交量只能告诉你这里交易活跃,但买方和卖方到底谁在主导?
- 资金集中在什么价格区间?
这些关键问题它答不上来。举个栗子🌰:
- 如果某天股价上涨,成交量放大,可能是主力吸筹;
- 也可能是散户疯狂接盘,第二天直接砸盘…
光看成交量就像雾里看花,而传统的成交量指标只能告诉我们”交易了多少”,但不能告诉我们”在哪里交易的”和”谁在主导”。今天我要教大家的方法,就能完美解决这个问题。
简单说,我们就是把成交量按照两个维度进行分类:
- 按价格分:把相近的交易价格归为一类。
- 按方向分:区分是买入主导还是卖出主导。
这样我们就能看到:在哪个价格区间买入力量强,在哪个价格区间卖出力量强。
想象一下,这就像是一场拔河比赛。左边是买方队伍,右边是卖方队伍。我们的图表就是看两边在哪个位置使了多大的力气。
二、双侧模型核心原理
传统成交量只看总量,不管方向。我们改成双侧:一边买家,一边卖家。
我们只需要三个步骤:
- 区分买卖方向:收盘价高于开盘价算买入,低于开盘价算卖出。
- 价格分桶:把相近的价格分成一组。
- 成交量汇总:计算每个价格区间内的总成交量。
具体公式是这样的:
买入成交量 = 所有收盘价 > 开盘价的交易日的成交量总和
卖出成交量 = 所有收盘价 < 开盘价的交易日的成交量总和
然后用一个简单的数学公式进行价格分桶:

Pt 表示第 t 日的收盘价,δ 表示最小变动价位(例如 0.01 美元)。每个桶包含收盘价接近该价格的日期的总交易量。
一旦分桶,我们接着计算:

Ct:收盘价;Ot:开盘价;Vt:音量;B:所有可见条形的集合;p:价格区间;
接下来需要对每一方进行标准化(成交量汇总):

峰值价(最多成交量的价位)、中位价(累积超50%的价位)、成交量加权平均价(VWAP,成交量重的价位影响大)。
通过这个累计百分比,我们能一眼看出在哪个价位区间,买方或卖方的力量特别集中。曲线越陡,说明成交量越集中在少数几个价格附近,显示出强烈的多空决心。
三、手把手教学
下面我就带大家一步步实现这个可视化分析工具。
第一步:环境准备
首先安装必要的库:
pip install yfinance pandas matplotlib numpy
设置参数和下载数据:先导入库,设参数。股票代码、起始结束日期、间隔、可见柱子数、价格间隔。
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
from matplotlib.dates import AutoDateLocator, AutoDateFormatter
# 用户参数
TICKER = "PLTR" # 股票代码
START = "2024-01-01" # 开始日期
END = "2025-07-13" # 结束日期
INTERVAL = "1d" # 日线
VISIBLE_BARS = 180 # 显示最后180天
TICK_SIZE = 0.01 # 价格间隔,小点分辨率高
# 颜色定义
BULL_EDGE_COLOR = "#089981" # 买家边色
BULL_FILL_COLOR = (8/255, 153/255, 129/255, 0.90) # 买家填充
BEAR_EDGE_COLOR = "#F23645" # 卖家边色
BEAR_FILL_COLOR = (242/255, 54/255, 69/255, 0.90) # 卖家填充
# 下载数据
df = yf.download(
TICKER,
start=START,
end=END,
interval=INTERVAL,
auto_adjust=True,
progress=False
)
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
vis = df.tail(VISIBLE_BARS).copy() # 取最后180天
跑这段,数据就到手。yfinance从Yahoo Finance拉历史价。
第二步:计算价格区间和买卖方向
分上涨天(买家)和下跌天(卖家)。
vis['bucket'] = (vis['Close'] / TICK_SIZE).round().astype(int) * TICK_SIZE
# 分割
bull = vis[vis['Close'] > vis['Open']] # 买家天
bear = vis[vis['Close'] < vis['Open']] # 卖家天
# 聚合成交量
bull_map = bull.groupby('bucket')['Volume'].sum()
bear_map = bear.groupby('bucket')['Volume'].sum()
简单吧?groupby就是按桶合计成交量。
第三步:计算关键指标
计算累积分布和指标:归一化,算总和、峰值、累积、VWAP、中位。
# 缩放因子
bull_max = bull_map.max() if not bull_map.empty else 0
bear_max = bear_map.max() if not bear_map.empty else 0
# 总和和峰值
bull_total = bull_map.sum()
bear_total = bear_map.sum()
bull_peak_price = bull_map.idxmax() if not bull_map.empty else np.nan
bear_peak_price = bear_map.idxmax() if not bear_map.empty else np.nan
# 从高到低排序
bull_levels = bull_map.sort_index(ascending=False)
bear_levels = bear_map.sort_index(ascending=False)
# 累积占比
bull_frac = bull_levels.cumsum() / bull_total if bull_total > 0 else pd.Series([], dtype=float)
bear_frac = bear_levels.cumsum() / bear_total if bear_total > 0 else pd.Series([], dtype=float)
# VWAP和中位
bull_vwap = (bull_map.index.to_numpy() * bull_map.values).sum() / bull_total if bull_total > 0 else np.nan
bear_vwap = (bear_map.index.to_numpy() * bear_map.values).sum() / bear_total if bear_total > 0 else np.nan
bull_median = bull_frac[bull_frac >= 0.5].index[0] if not bull_frac.empty else np.nan
bear_median = bear_frac[bear_frac >= 0.5].index[0] if not bear_frac.empty else np.nan
# 价格范围
price_min = min(
bull_levels.index.min() if not bull_levels.empty else np.inf,
bear_levels.index.min() if not bear_levels.empty else np.inf,
vis['Low'].min()
)
price_max = max(
bull_levels.index.max() if not bull_levels.empty else -np.inf,
bear_levels.index.max() if not bear_levels.empty else -np.inf,
vis['High'].max()
)
上面这些算出曲线和线的位置。
第四步:画图展示
建图,三面板:左买、中价、右卖。底部盒子秀占比。
plt.style.use('dark_background')
fig = plt.figure(figsize=(16, 8)) # 图大小
# 位置
left_margin = 0.05
bull_width = 0.20
price_width = 0.50
price_left = left_margin + bull_width
bear_left = price_left + price_width
bottom = 0.15
height = 0.75
box_height = 0.05
box_bottom = bottom - box_height
# 中间价面板
price_ax = fig.add_axes([price_left, bottom, price_width, height])
price_ax.plot(vis.index, vis['Close'], color='white', lw=1)
price_ax.set_ylim(price_min, price_max)
date_loc = AutoDateLocator(minticks=5, maxticks=10)
price_ax.xaxis.set_major_locator(date_loc)
price_ax.xaxis.set_major_formatter(AutoDateFormatter(date_loc))
price_ax.tick_params(axis='x', rotation=45, colors='white', labelsize=8)
price_ax.tick_params(axis='y', colors='white', labelsize=8)
price_ax.set_title(f"{TICKER} – last {VISIBLE_BARS} bars", color='white')
# 左买面板
bull_ax = fig.add_axes([left_margin, bottom, bull_width, height], sharey=price_ax)
if not bull_frac.empty:
if bull_max > 0:
bull_norm = bull_levels.values / bull_max
bull_ax.barh(
bull_levels.index,
bull_norm,
height=TICK_SIZE * 3,
left=1 - bull_norm,
color='gray',
alpha=0.5
)
bull_ax.fill_betweenx(
bull_frac.index,
1 - bull_frac,
1,
facecolor=BULL_FILL_COLOR,
edgecolor=BULL_EDGE_COLOR,
linewidth=1, alpha=0.5
)
bull_ax.axhline(bull_peak_price, xmin=0, xmax=1, color=BULL_EDGE_COLOR, linestyle='dotted')
bull_ax.axhline(bull_median, xmin=0, xmax=1, color='gray', linestyle='dashdot')
bull_ax.axhline(bull_vwap, xmin=0, xmax=1, color='gray', linestyle='dashed')
bull_ax.set_xlim(0, 1)
bull_ax.axis('off')
# 右卖面板
bear_ax = fig.add_axes([bear_left, bottom, bull_width, height], sharey=price_ax)
if not bear_frac.empty:
if bear_max > 0:
bear_norm = bear_levels.values / bear_max
bear_ax.barh(
bear_levels.index,
bear_norm,
height=TICK_SIZE * 3,
left=0,
color='gray',
alpha=0.5
)
bear_ax.fill_betweenx(
bear_frac.index,
0,
bear_frac,
facecolor=BEAR_FILL_COLOR,
edgecolor=BEAR_EDGE_COLOR,
linewidth=1, alpha=0.5
)
bear_ax.axhline(bear_peak_price, xmin=0, xmax=1, color=BEAR_EDGE_COLOR, linestyle='dotted')
bear_ax.axhline(bear_median, xmin=0, xmax=1, color='gray', linestyle='dashdot')
bear_ax.axhline(bear_vwap, xmin=0, xmax=1, color='gray', linestyle='dashed')
bear_ax.set_xlim(0, 1)
bear_ax.axis('off')
# 底部占比
bull_share = bull_total / (bull_total + bear_total)
bear_share = bear_total / (bull_total + bear_total)
bull_box = fig.add_axes([left_margin, box_bottom, bull_width, box_height])
bull_box.barh(0, bull_share, height=1, color=BULL_FILL_COLOR, edgecolor=BULL_EDGE_COLOR)
bull_box.set_xlim(0, 1)
bull_box.axis('off')
bull_box.text(0.5, 0, f"{bull_share:.1%}", ha='center', va='center', color='white', fontsize=14)
bear_box = fig.add_axes([bear_left, box_bottom, bull_width, box_height])
bear_box.barh(0, bear_share, height=1, color=BEAR_FILL_COLOR, edgecolor=BEAR_EDGE_COLOR)
bear_box.set_xlim(0, 1)
bear_box.axis('off')
bear_box.text(0.5, 0, f"{bear_share:.1%}", ha='center', va='center', color='white', fontsize=14)
plt.tight_layout()
plt.show()
复制这些代码到Jupyter或Python文件,跑起来就能出图。改TICKER参数还可以试其他股。
四、图表解读
当你运行完代码后,会看到一个包含三部分的图表,怎么看这个图?很简单:
- 中间:股价走势图,左侧:买入力量分布(绿色),右侧:卖出力量分布(红色)。
- 绿色越浓的地方,表示在这个价格区间买入力量越强。红色越浓的地方,表示在这个价格区间卖出力量越强。
- 绿色虚线:买入最集中的价格位。红色虚线:卖出最集中的价格位。

比如上面PLTR是AI股,2025年涨107%,Q2营收1亿刀,增48%。但估值高,可能压股价。我们的图显示这180天的数据,买家总成交量占60.7%,峰值在100美元附近,中位90美元,VWAP 95美元。卖家占39.3%,分布广,峰值110美元。
指标 | 买家值 | 卖家值 |
---|---|---|
总成交量占比 | 60.7% | 39.3% |
峰值价 | 100美元 | 110美元 |
中位价 | 90美元 | 105美元 |
VWAP | 95美元 | 108美元 |
压力集中区 | 80-100美元 | 100-120美元 |
PLTR AI市场扩到了3794亿刀,目标价138美元。如图显示买家在低区强,支撑稳。卖家在上区,但弱。建议低买高卖,避高位追。最终的结论是:
买家像AI狂热粉,卖家像估值担忧者。但数据分析看,买家赢面大。
五、实战小贴士
这个工具在实际操作中很有用:
- 找支撑阻力:浓色区域往往是重要的支撑或阻力位。
- 判断强弱:对比左右两侧的面积,可以看出多空谁占优势。
- 发现突破:当价格突破浓色区域时,往往意味着趋势转变。
我总结了一个简单的决策表格:
市场信号 | 操作建议 | 风险等级 |
---|---|---|
买入力量远大于卖出 | 考虑买入 | 低 |
卖出力量远大于买入 | 考虑卖出 | 中 |
双方力量均衡 | 观望等待 | 高 |
突破密集买入区 | 加仓买入 | 中 |
跌破密集卖出区 | 止损离场 | 高 |
⚠️ 注意事项
这个工具很好用,但也有几点要注意:
- 不是万能的:它只是辅助工具,不能单独作为买卖依据。
- 参数调整:不同股票可能需要调整TICK_SIZE参数。
- 时间周期:VISIBLE_BARS的设置会影响分析结果。
- 结合其他指标:最好与MACD、RSI等其他指标一起使用。
最重要的是,这个工具反映的是历史情况,不能保证未来一定会重复历史模式。
📈 进阶玩法
等你熟悉了基础用法后,还可以尝试这些进阶玩法:
- 多时间周期分析:同时分析日线、周线、月线的力量对比。
- 板块对比:对比同一个板块内不同股票的多空力量。
- 自选股监控:批量分析自己股票池中的个股。
- 预警系统:设置当多空力量比达到一定阈值时发出警报。
六、观点总结
今天教大家的这个市场压力可视化工具,它最大的价值在于:让看不见的买卖力量变得一目了然。最后给大家总结一下重点:
- 核心原理:把成交量按价格和方向分类,直观展示多空力量对比。
- 关键技术:价格分桶、方向区分、累积计算。
- 实用价值:识别支撑阻力、判断多空强弱、发现突破机会。
- 使用建议:结合其他指标使用,不要单独依赖这个工具。
- 持续学习:股市分析没有圣杯,需要不断学习和实践。
#关键词
#Python量化 #Python可视化 #股票分析 #多空力量 #成交量分析 #量化投资 #股市压力图 #买家卖家分析 #交易神器
本文代码我已经尽量写得简单易懂,大家可以直接复制使用。如果对文中内容有任何疑问,欢迎留言,我会尽快回复。祝您投资顺利,收益长虹!
本文内容仅限技术探讨和学习,不构成任何投资建议。
Be First to Comment