Python中合并多Regime对应的Volume Profile与Candlestick图表为单图的实现需求
Python中合并多Regime对应的Volume Profile与Candlestick图表为单图的实现需求
看起来你现在需要把三个不同Regime对应的成交量分布(Volume Profile)和5分钟K线图合并到同一个可视化图表里,而不是生成三个独立的图。我来帮你调整原代码,实现这个需求👇
首先,我们会统一所有Regime的价格区间计算,用不同颜色区分每个Regime的成交量分布、K线主体和POC(成交量密集点),最终在同一个画布上展示所有内容:
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 初始DataFrame创建 ds = { 'Date' : ['2025-08-22 16:00:00', '2025-08-22 16:01:00', '2025-08-22 16:02:00', '2025-08-22 16:03:00', '2025-08-22 16:04:00', '2025-08-22 16:05:00', '2025-08-22 16:06:00', '2025-08-22 16:07:00', '2025-08-22 16:08:00', '2025-08-22 16:09:00', '2025-08-22 16:10:00', '2025-08-22 16:11:00', '2025-08-22 16:12:00', '2025-08-22 16:13:00', '2025-08-22 16:14:00', '2025-08-22 16:15:00', '2025-08-22 16:16:00', '2025-08-22 16:17:00', '2025-08-22 16:18:00', '2025-08-22 16:19:00', '2025-08-22 16:20:00', '2025-08-22 16:21:00', '2025-08-22 16:22:00', '2025-08-22 16:23:00', '2025-08-22 16:24:00'], 'Open': [ 11717.9, 11717.95, 11716.6, 11717.4, 11719.5, 11727.25, 11725.55, 11724.35, 11725.45, 11724.15, 11728.2, 11726.6, 11727.6, 11729.1, 11724.1, 11722.8, 11721.8, 11720.8, 11718.8, 11716.7, 11716.9, 11722.5, 11721.6, 11727.8, 11728.1], 'Low': [ 11715.9, 11716, 11715.35, 11716.45, 11719.5, 11724.3, 11723.55, 11723.15, 11723.85, 11724.15, 11725.2, 11726.6, 11727.6, 11724.2, 11722.6, 11721.6, 11719.7, 11715.8, 11716.5, 11716, 11716.9, 11721.3, 11721.4, 11726.35, 11727], 'High': [ 11718.1, 11718.1, 11717.9, 11719.4, 11727.15, 11727.45, 11726, 11725.65, 11727.2, 11727.85, 11728.2, 11728.7, 11729.5, 11729.1, 11725.5, 11723.9, 11722, 11720.8, 11719.8, 11717.7, 11722.9, 11724.3, 11727.8, 11728.3, 11728.8], 'Close' : [11718.05, 11716.5, 11717, 11719.3, 11727.15, 11725.65, 11724.15, 11725.35, 11724.05, 11727.65, 11726.7, 11727.8, 11729.2, 11724.2, 11722.6, 11721.7, 11721.2, 11718.7, 11716.6, 11716.8, 11722.6, 11721.5, 11727.6, 11728, 11727.2], 'Volume': [ 130, 88, 125, 93, 154, 102, 118, 92, 105, 116, 84, 88, 108, 99, 82, 109, 98, 130, 71, 86, 96, 83, 80, 93, 73], 'Regime': [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3], } df = pd.DataFrame(data=ds) # 数据预处理 df['Date'] = pd.to_datetime(df['Date']) df.set_index('Date', inplace=True) # 重采样为5分钟K线 df_5min = df.resample('5T').agg({ 'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last', 'Volume': 'sum', 'Regime':'last' }) df_5min = df_5min.dropna().reset_index() # 颜色映射(区分不同Regime) regime_colors = {1: '#1f77b4', 2: '#ff7f0e', 3: '#2ca02c'} # 计算全局价格区间(统一所有Regime的bin,保证可比性) global_min = df['Low'].min() global_max = df['High'].max() num_bins = 200 bins = np.linspace(global_min, global_max, num_bins + 1) bin_size = bins[1] - bins[0] bin_centers = (bins[:-1] + bins[1:]) / 2 chart_width = len(df_5min) # 预计算每个Regime的成交量分布和POC regime_profiles = {} for regime in df['Regime'].unique(): subset_1min = df[df['Regime'] == regime] vol_profile = np.zeros(num_bins) # 计算成交量分布 for _, row in subset_1min.iterrows(): low, high, vol = row['Low'], row['High'], row['Volume'] if high == low: bin_idx = np.digitize(low, bins) - 1 if 0 <= bin_idx < num_bins: vol_profile[bin_idx] += vol else: vol_per_unit = vol / (high - low) start_bin, end_bin = np.digitize(low, bins), np.digitize(high, bins) for b in range(start_bin, end_bin + 1): if 0 < b <= num_bins: bin_start, bin_end = bins[b-1], bins[b] overlap_start, overlap_end = max(low, bin_start), min(high, bin_end) vol_profile[b-1] += (overlap_end - overlap_start) * vol_per_unit # 缩放成交量到图表宽度 scaled_vol = vol_profile / vol_profile.max() * chart_width if vol_profile.max() > 0 else vol_profile # 找到POC(成交量最大的价格) poc_idx = np.argmax(vol_profile) poc_price = bin_centers[poc_idx] regime_profiles[regime] = { 'scaled_vol': scaled_vol, 'poc_price': poc_price, 'color': regime_colors[regime] } # 创建合并图表 fig, ax = plt.subplots(figsize=(12,7)) # 1. 绘制各Regime的成交量分布背景(带透明度,避免遮挡) for regime in sorted(regime_profiles.keys(), reverse=True): profile = regime_profiles[regime] ax.fill_betweenx( bin_centers, 0, profile['scaled_vol'], color=profile['color'], alpha=0.25, step='mid', label=f'Regime {regime} 成交量分布' ) # 2. 绘制各Regime的POC线 for regime in regime_profiles.keys(): profile = regime_profiles[regime] ax.axhline( profile['poc_price'], color=profile['color'], linestyle='--', linewidth=1.5, label=f'Regime {regime} POC: {profile["poc_price"]:.2f}' ) # 3. 绘制5分钟K线 xdates = np.arange(len(df_5min)) candle_width = 0.6 for i in range(len(df_5min)): o, h, l, c, regime = df_5min.loc[i, ['Open','High','Low','Close','Regime']] color = regime_colors[regime] # 影线(统一黑色,保证清晰) ax.vlines(xdates[i], l, h, color='black', linewidth=0.7) # K线主体 if c > o: ax.bar(xdates[i], c-o, candle_width, o, color=color, edgecolor='black', linewidth=0.5) else: ax.bar(xdates[i], o-c, candle_width, c, color=color, edgecolor='black', linewidth=0.5) # 图表样式调整 ax.set_xlim(-1, chart_width+1) ax.set_ylim(global_min - bin_size, global_max + bin_size) ax.set_xticks(xdates) ax.set_xticklabels(df_5min['Date'].dt.strftime('%H:%M'), rotation=45) ax.set_title('合并多Regime的5分钟K线与成交量分布图表', fontsize=14) ax.set_xlabel('时间', fontsize=12) ax.set_ylabel('价格', fontsize=12) ax.legend(loc='upper right', bbox_to_anchor=(1.18,1)) plt.tight_layout() plt.show()
关键修改说明
- 统一价格区间:基于全局最高最低价计算成交量分布的bin,确保三个Regime的分布在同一价格轴上对齐,方便对比
- 颜色统一区分:每个Regime从背景成交量分布、K线主体到POC线都用专属颜色,视觉上清晰区分不同阶段
- 叠加式背景:用透明度控制不同Regime的成交量分布背景,避免相互遮挡,同时保留各阶段的分布信息
- 整合K线展示:所有5分钟K线按时间顺序排列,影线统一黑色保证清晰度,主体用Regime对应颜色,直观展示不同阶段的价格走势
内容来源于stack exchange




