Published on October 20, 2025
Volume Profile reveals where the majority of trading activity occurred within a range — a powerful insight for understanding market behavior. In this post, we’ll see how to generate a fixed-range volume profile from OHLCV data using Python. It is advisable that such volume profile is always generated on most granular data that is available. More granular data is used, more accurate it is.
timestamp, open, high, low, close, volume
2025-10-15 09:15, 21600, 21620, 21570, 21595, 125000
2025-10-15 09:16, 21595, 21610, 21580, 21605, 98000
...
price_min = df['low'].min()
price_max = df['high'].max()
bucket_size = 10
bins = np.arange(price_min, price_max + bucket_size, bucket_size)
for _, row in df.iterrows():
price_range = np.arange(row['low'], row['high'] + bucket_size, bucket_size)
vol_per_bucket = row['volume'] / len(price_range)
for p in price_range:
volume_profile[p] += vol_per_bucket
This POC (or LOC, line of control) is the price which will also act as a good resistance or support. Mostly, traders track the changing PoC to understand whether any reversal is about to come or not. This is one of my tools (in addition to Anchored VWAP) to take quick fire, momentum based trades.
Same concept can be used at higher timeframes (calculation will still occur at lowest possible timeframe) to understand positional trends.