Loading content...
In algorithmic trading and quantitative finance, traditional time-based candlesticks (such as 1-minute or 5-minute OHLCV bars) have a fundamental limitation: they sample market data at uniform time intervals regardless of actual trading activity. During periods of high volatility, substantial price movements and information are compressed into a single bar, while quiet market periods generate bars with minimal informational value.
Transaction-based bars (also known as tick bars) offer a superior alternative by aggregating data based on a fixed number of individual trades rather than fixed time intervals. This approach ensures that each bar contains a more consistent amount of market information, as bars are formed only when a specified number of transactions have occurred.
Consider a stream of live market data where each trade (tick) contains:
Instead of grouping trades by time windows, transaction-based bars group them by transaction count. When bar_size trades have accumulated, a new OHLCV bar is created:
$$\text{OHLCV Bar} = {\text{Open}, \text{High}, \text{Low}, \text{Close}, \text{Volume}}$$
Where:
Write a Python function that transforms raw tick data into transaction-based OHLCV bars.
Requirements:
bar_size ticksbar_size is invalid (≤ 0)ticks = [(1, 100.0, 10), (2, 101.0, 20), (3, 99.0, 15), (4, 102.0, 25)]
bar_size = 2[{'timestamp': 2, 'open': 100.0, 'high': 101.0, 'low': 100.0, 'close': 101.0, 'volume': 30}, {'timestamp': 4, 'open': 99.0, 'high': 102.0, 'low': 99.0, 'close': 102.0, 'volume': 40}]With 4 ticks and bar_size=2, we create 2 complete bars.
Bar 1 (ticks 1-2): • Open: 100.0 (price of first tick) • High: 101.0 (maximum price) • Low: 100.0 (minimum price) • Close: 101.0 (price of last tick) • Volume: 10 + 20 = 30 • Timestamp: 2 (timestamp of last tick)
Bar 2 (ticks 3-4): • Open: 99.0, High: 102.0, Low: 99.0, Close: 102.0 • Volume: 15 + 25 = 40 • Timestamp: 4
ticks = [(1, 50.0, 5), (2, 55.0, 10), (3, 52.0, 8), (4, 58.0, 12), (5, 60.0, 15), (6, 57.0, 7)]
bar_size = 3[{'timestamp': 3, 'open': 50.0, 'high': 55.0, 'low': 50.0, 'close': 52.0, 'volume': 23}, {'timestamp': 6, 'open': 58.0, 'high': 60.0, 'low': 57.0, 'close': 57.0, 'volume': 34}]With 6 ticks and bar_size=3, we create exactly 2 complete bars.
Bar 1 (ticks 1-3): • Open: 50.0, High: 55.0, Low: 50.0, Close: 52.0 • Volume: 5 + 10 + 8 = 23 • Timestamp: 3
Bar 2 (ticks 4-6): • Open: 58.0, High: 60.0, Low: 57.0, Close: 57.0 • Volume: 12 + 15 + 7 = 34 • Timestamp: 6
ticks = [(1, 100.0, 10), (2, 105.0, 20), (3, 102.0, 15), (4, 108.0, 25), (5, 110.0, 30)]
bar_size = 2[{'timestamp': 2, 'open': 100.0, 'high': 105.0, 'low': 100.0, 'close': 105.0, 'volume': 30}, {'timestamp': 4, 'open': 102.0, 'high': 108.0, 'low': 102.0, 'close': 108.0, 'volume': 40}]With 5 ticks and bar_size=2, we can only create 2 complete bars (4 ticks). The 5th tick is discarded as it cannot form a complete bar.
Bar 1 (ticks 1-2): Open=100.0, High=105.0, Low=100.0, Close=105.0, Volume=30 Bar 2 (ticks 3-4): Open=102.0, High=108.0, Low=102.0, Close=108.0, Volume=40
Tick 5 is not included in any bar since it cannot form a complete bar of size 2.
Constraints