To resample crypto OHLCV candles, group compatible lower-timeframe bars into explicitly aligned windows, then take the first open, maximum high, minimum low, last close and summed volume. Validate the expected source intervals before accepting each result. A bucket can contain plausible prices while missing a minute, starting halfway through the download, or still developing. Keep those states separate from a complete, finalized candle.
The arithmetic is short. The harder part is proving that the group contains the observations its label promises. This walkthrough builds five-minute candles from one-minute candles and carries that proof alongside the numbers.
Define the aggregation contract
Start with one venue, instrument, market type and price basis. Trade-price spot candles and perpetual mark-price candles describe different inputs. Group each source separately; combining their rows first creates a candle without a clear market identity.
The source interval must fit inside the target boundaries. Aligned one-minute candles can construct five-minute candles. Two-minute candles beginning at 09:00 cannot exactly construct a 09:00–09:05 window, because the 09:04–09:06 source candle crosses its endpoint. Recover finer data rather than allocating half that candle's range or volume.
Write down the following contract before running a resampler:
| Contract field | This article's example | Why it matters |
|---|---|---|
| Source timestamp | One-minute opening instant in UTC | Determines which interval a row represents |
| Target boundaries | Every five minutes from UTC midnight | Makes repeated downloads group identically |
| Membership | Start included, end excluded | Assigns a boundary observation exactly once |
| Output label | Target opening instant | Separates the label from the availability time |
| Volume unit | Base-asset units for one fictional pair | Makes addition meaningful |
| Eligibility | Exact source coverage, finalized inputs, elapsed target | Prevents incomplete results becoming signals |
For the window beginning at 09:00, membership is [09:00, 09:05). Its five source opens are 09:00, 09:01, 09:02, 09:03 and 09:04. The source candle opening at 09:05 belongs to the next window.
In pandas, closed controls which edge belongs to a bin, while label controls the timestamp attached to the result. origin and offset control alignment for fixed frequencies. Setting a right-edge label alone does not move a boundary observation into a different group. pandas resampling parameters
Changing a chart clock raises a different question. The candle time-zone guide explains when displayed labels change and when the underlying aggregation window changes. Here, every timestamp and boundary stays in UTC.
Work through complete, gapped and developing buckets
The following prices and volumes are hypothetical. Assume a collector checks its dataset at 09:11:30 UTC on one fictional trading day. Every supplied row below is finalized and has already arrived. The 09:07 row is missing for an unknown reason; the current 09:11 minute is excluded because it is unfinished.
| Minute opening UTC | Open | High | Low | Close | Base volume |
|---|---|---|---|---|---|
| 09:00 | 100 | 102 | 99 | 101 | 2 |
| 09:01 | 101 | 104 | 100 | 103 | 3 |
| 09:02 | 103 | 106 | 102 | 105 | 1 |
| 09:03 | 105 | 105 | 98 | 99 | 4 |
| 09:04 | 99 | 104 | 99 | 104 | 2 |
| 09:05 | 104 | 105 | 102 | 103 | 2 |
| 09:06 | 103 | 107 | 103 | 106 | 1 |
| 09:08 | 106 | 108 | 104 | 105 | 3 |
| 09:09 | 105 | 106 | 101 | 102 | 2 |
| 09:10 | 102 | 104 | 101 | 103 | 1 |
The first bucket opens at 100, reaches a high of 106 and a low of 98, then closes at 104. Its volume is 2 + 3 + 1 + 4 + 2 = 12 base units. All five expected source intervals are present, finalized and available after the target has ended.
Applying the same arithmetic to the other rows gives these observed summaries:
| Target UTC window | Observed OHLCV | Finalized source slots | State at 09:11:30 |
|---|---|---|---|
| 09:00–09:05 | 100 / 106 / 98 / 104 / 12 | 5 of 5 | Complete and eligible |
| 09:05–09:10 | 104 / 108 / 101 / 102 / 8 | 4 of 5 | Elapsed, unknown gap; withhold |
| 09:10–09:15 | 102 / 104 / 101 / 103 / 1 | 1 of 5 | Developing; withhold |
The second row is a summary of observed inputs, not a verified five-minute candle. The missing minute might change its range and volume. Its known final close does not repair the missing price path. The third row is developing normally: several required minutes have not finished yet. Waiting may complete the third bucket; waiting alone cannot recover the second bucket's historical gap.
If the download had started at 09:02, the first target would also be incomplete, containing only three of its five required minutes. Preserve the 09:00 boundary and mark partial coverage. Moving the origin to the first downloaded row would quietly change the requested series.
Aggregate each OHLCV field explicitly
Do not average the five closes to obtain the new close. In the first bucket, their arithmetic mean is (101 + 103 + 105 + 99 + 104) / 5 = 102.4; the correct final close remains 104.
Likewise, applying .ohlc() to only the close column returns the opening, highest, lowest and closing values among those closes. In this example it produces 101 / 105 / 99 / 104, losing the true opening price and both extremes. pandas documents .ohlc() as an aggregation of the supplied values, excluding missing values. pandas OHLC operation
For an already normalized, sorted table of finalized one-minute candles, use one source identity, a UTC DatetimeIndex of candle opens, unique aligned timestamps and finite numeric OHLCV. The aggregation stage can be written as:
r = df.resample(
"5min",
origin="epoch",
closed="left",
label="left",
)
out = r.agg({
"open": "first",
"high": "max",
"low": "min",
"close": "last",
})
v = r["volume"]
out["volume"] = v.sum(
min_count=5
)
Here, five valid volume inputs are required; pandas returns an unavailable sum when the group has fewer than min_count valid values. This protects the example's volume column from a four-minute subtotal masquerading as a complete total. It does not validate timestamp alignment, eliminate duplicates or prove finality. pandas resampled-sum requirements
The code still calculates observed prices for incomplete groups. Attach the state ledger and mask or exclude their OHLCV from consumers requiring completed candles. Use a different expected count when the source or target interval changes.
Prove coverage using identities and expected slots
A row count of five is insufficient. Four genuine minute records plus a duplicate also make five rows. Compare the exact set of source opening instants with the expected grid and require one canonical finalized record per slot. Reject off-grid timestamps rather than rounding them into place.
For example, Binance Spot identifies REST klines by their opening time within the requested symbol and interval. Preserve those request dimensions in your local identity key. Binance Spot kline identity
Live updates introduce another duplication risk. Binance Spot's kline stream reports updates to the current candle, with x indicating whether it is closed. These are updates to one candle's state. Summing the volume field across every received snapshot would count the evolving candle repeatedly. Maintain one record per source candle and apply a documented update policy before aggregating distinct intervals. Binance Spot kline stream fields
An unknown absent interval remains unknown. If the source deliberately omits no-trade intervals, establish that convention and collection completeness before defining synthetic rows. The missing-candle and zero-volume worksheet handles that classification. A synthetic row needs a construction flag even when it makes the calendar regular.
Check price consistency as well: each low must be no greater than either open or close, each high no less, and volume nonnegative. Reject missing or nonfinite fields before first/last/max/min operations can skip them and conceal a damaged constituent.
Preserve volume units and decision-time availability
Sum compatible base volume separately from compatible quote volume. Binance Spot's kline payload distinguishes these fields; neither should be added to the other. Binance Spot volume field definitions
The base, quote and contract volume guide explains the unit checks needed before aggregating across instruments or feeds.
Do not multiply the new close by total base volume and call it measured quote turnover. Transactions occurred at different prices. Similarly, averaging minute VWAPs equally discards their volume weights. These additional fields require their own sufficient inputs and aggregation rules.
Other market observations can require a different operation entirely. A funding rate has settlement timing and a rate basis; the funding-rate aggregation guide explains why carrying this OHLCV recipe over to funding history can change the quantity being measured.
Finally, an output labeled 09:00 is not known at 09:00. Its five-minute close depends on the interval ending at 09:05 and the subsequent arrival of the necessary finalized inputs. Retain the latest required arrival time alongside the target end. The multi-timeframe timing guide shows how that availability condition controls which candle a decision may use.
Keep a validation receipt for each output window
Before using a reconstructed candle, save its source identity, target endpoints, expected source slots, observed finalized slots, missing slots, synthetic flags and availability time. Record the aggregation-policy version so a future backfill or correction can be compared with the original result.
Validate one boundary case, one missing interval and one developing bucket whenever changing the input adapter or interval rule. Reversing source-row order must not change a result after chronological sorting. Replaying the same finalized record must not increase volume. Removing 09:07 must withhold the second example bucket, while the passage of 09:15 alone must not mark the third complete without its required inputs.
Use the complete first bucket as a small reconciliation fixture: 100 / 106 / 98 / 104 / 12, with exactly five distinct finalized minute slots. Keep the numerical result and its eligibility receipt together; a candle is usable only when both agree.
