Loading problem...
In quantitative finance and algorithmic trading, traditional time-based candlestick charts (such as 1-minute, hourly, or daily candles) have a significant limitation: they treat all time periods equally, regardless of actual market activity. During low-volume periods, these candles may contain minimal price action, while during high-volume bursts, they may compress critical information into a single bar.
Volume-Based Candlestick Aggregation (also known as Volume Bars) offers an alternative approach used extensively in financial machine learning and high-frequency trading systems. Instead of forming bars based on fixed time intervals, volume bars aggregate trades until a cumulative volume threshold is reached, at which point a new candlestick is formed.
This methodology provides several key advantages:
OHLCV Format: Each candlestick bar is represented in the standard OHLCV format:
Bar Formation Rules:
Your Task: Write a function that takes an array of trade prices, their corresponding volumes, and a volume threshold, then returns a list of volume-based OHLCV bars.
prices = [100.0, 101.0, 99.0, 102.0, 98.0, 100.0]
volumes = [50.0, 30.0, 40.0, 60.0, 20.0, 50.0]
volume_threshold = 100.0[[100.0, 101.0, 99.0, 99.0, 120.0], [102.0, 102.0, 98.0, 100.0, 130.0]]Bar 1 Formation: • Trade 1: price=100.0, volume=50 → cumulative=50 (threshold not reached) • Trade 2: price=101.0, volume=30 → cumulative=80 (threshold not reached) • Trade 3: price=99.0, volume=40 → cumulative=120 ≥ 100 (threshold reached!)
Bar 1 closes with: Open=100.0, High=101.0, Low=99.0, Close=99.0, Volume=120.0
Bar 2 Formation: • Trade 4: price=102.0, volume=60 → cumulative=60 (threshold not reached) • Trade 5: price=98.0, volume=20 → cumulative=80 (threshold not reached) • Trade 6: price=100.0, volume=50 → cumulative=130 ≥ 100 (threshold reached!)
Bar 2 closes with: Open=102.0, High=102.0, Low=98.0, Close=100.0, Volume=130.0
prices = [10.0, 12.0, 11.0, 13.0]
volumes = [25.0, 25.0, 25.0, 25.0]
volume_threshold = 50.0[[10.0, 12.0, 10.0, 12.0, 50.0], [11.0, 13.0, 11.0, 13.0, 50.0]]With uniform volumes of 25 each and a threshold of 50:
Bar 1: Trades at 10.0 (vol=25) and 12.0 (vol=25) combine for exactly 50 volume. Result: Open=10.0, High=12.0, Low=10.0, Close=12.0, Volume=50.0
Bar 2: Trades at 11.0 (vol=25) and 13.0 (vol=25) combine for exactly 50 volume. Result: Open=11.0, High=13.0, Low=11.0, Close=13.0, Volume=50.0
When volume exactly equals the threshold, the bar completes on that trade.
prices = [50.0, 52.0, 48.0]
volumes = [10.0, 15.0, 20.0]
volume_threshold = 100.0[[50.0, 52.0, 48.0, 48.0, 45.0]]The total volume across all trades is only 45.0, which is less than the threshold of 100.0. Since the threshold is never reached, all trades form a single incomplete bar:
• Open: 50.0 (first trade price) • High: 52.0 (maximum price) • Low: 48.0 (minimum price) • Close: 48.0 (last trade price) • Volume: 45.0 (total accumulated volume)
Incomplete bars at the end of the data stream are included in the output.
Constraints