A vw outside the high and low of a Massive stock aggregate bar is not a data error. The high and low come only from trades that are allowed to set them, and one large contingent trade at a negotiated price can pull vw well outside that range. Minute values combine into longer intraday bars to the fourth decimal place, but not into the daily bar.
Applies to
- Plans: every Stocks plan returns bars with vw. Checking a bar against its trades needs /v3/trades, which Stocks Developer, Stocks Advanced and Stocks Business include, per the trades documentation.
- Endpoints: /v2/aggs/ticker/{stocksTicker}/range/{multiplier}/{timespan}/{from}/{to} for the bars, /v3/trades/{stockTicker} for the trades, and /v3/reference/conditions for what each sale condition may update.
- Asset classes: US stocks. Options and crypto bars also carry vw, and this article does not cover them.
Which trades the VWAP includes
The VWAP on a stock bar, vw, includes every trade that counts toward the bar's volume, v, weighted by the trade's decimal_size. That set of trades is wider than the set allowed to set the high and low. The conditions endpoint reports both rules for each sale condition, as updates_volume and updates_high_low under update_rules.consolidated, and the trade eligibility post explains that Massive's bars follow those consolidated rules.
The conditions endpoint lists ten sale conditions that add to volume without being allowed to set the high or low. Two of them, Form T (12) and Extended Hours Sold Out Of Sequence (13), mark extended-hours trades. The other eight can print in regular hours, so a trade carrying any of them moves vw but cannot move h or l during regular trading hours:
| Condition | Name |
|---|---|
| 2 | Average Price Trade |
| 7 | Cash Sale |
| 20 | Next Day |
| 21 | Price Variation Trade |
| 29 | Seller |
| 37 | Odd Lot Trade |
| 52 | Contingent Trade |
| 53 | Qualified Contingent Trade |
Pre-market and after-hours bars differ. Outside regular hours almost every trade carries Form T (condition 12), which the conditions endpoint lists with updates_high_low false, and the bars still take their high and low from the Form T trades that are not also odd lots (condition 37). Outside regular hours, read the endpoint's updates_high_low value for condition 12 as the regular-hours rule.
Why the VWAP falls outside the range
A minute bar's vw falls outside its high and low when trades from the table above print outside the range with enough of the volume. On liquid ETFs and large stocks, a common cause is a qualified contingent trade (condition 53): a stock trade executed as one leg of a multi-part order, at a price set by the package rather than by the current market, as What do Massive's stock trade condition codes mean? describes. This SPY minute, at 14:04 UTC on 2 October 2026, has a vw below its low:
curl -X GET "https://api.massive.com/v2/aggs/ticker/SPY/range/1/minute/1790949840000/1790949840000?adjusted=false&apiKey=YOUR_API_KEY"
Response
{
"ticker": "SPY",
"adjusted": false,
"results": [
{ "v": 1427028.868773, "vw": 770.0764, "o": 771.4301, "c": 771.63, "h": 771.66, "l": 771.24, "t": 1790949840000, "n": 2299 }
],
"status": "OK"
}
t 1790949840000 is 14:04 UTC (10:04 AM ET) on 2 October 2026, in milliseconds. The trades between 14:04:30 and 14:04:31 UTC include one for 1,350,000 shares at 770.00:
curl -X GET "https://api.massive.com/v3/trades/SPY?timestamp.gte=1790949870000000000×tamp.lt=1790949871000000000&limit=50000&order=asc&sort=timestamp&apiKey=YOUR_API_KEY"
Response, trimmed to that trade:
{
"results": [
{ "conditions": [53, 52, 41], "price": 770, "sip_timestamp": 1790949870783046676, "decimal_size": "1350000.0" }
],
"status": "OK"
}
sip_timestamp is 14:04:30.783 UTC, in nanoseconds. Condition 53 adds to volume and cannot set the high or low:
curl -X GET "https://api.massive.com/v3/reference/conditions?asset_class=stocks&data_type=trade&id=53&apiKey=YOUR_API_KEY"
Response
{
"results": [
{
"id": 53,
"name": "Qualified Contingent Trade",
"update_rules": {
"consolidated": { "updates_high_low": false, "updates_open_close": false, "updates_volume": true }
}
}
],
"status": "OK"
}
That one trade is about 95% of the minute's 1,427,028.868773 shares, so it pulls vw to 770.08 while every trade allowed to set the range printed between 771.24 and 771.66. A VWAP computed only from those range-setting trades comes to 771.4083 for this minute. If you need a VWAP that stays inside a regular-hours bar, compute it yourself from /v3/trades, keeping only trades whose conditions all have updates_high_low: true.
How to combine minute VWAPs into a longer bar
Multiply each minute bar's vw by its v, add the products, and divide by the sum of v. That reproduces the vw of a 5-, 15- or 30-minute or hourly stock bar to within one unit in the fourth decimal place, because each minute's vw is already rounded. These are the five SPY minute bars from 14:00 to 14:04 UTC on 2 October 2026:
curl -X GET "https://api.massive.com/v2/aggs/ticker/SPY/range/1/minute/1790949600000/1790949840000?adjusted=false&apiKey=YOUR_API_KEY"
Response, trimmed to v, vw and t:
{
"ticker": "SPY",
"results": [
{ "v": 126063.605416, "vw": 770.1589, "t": 1790949600000 },
{ "v": 128426.643091, "vw": 770.6748, "t": 1790949660000 },
{ "v": 104637.312975, "vw": 771.0739, "t": 1790949720000 },
{ "v": 89041.849731, "vw": 771.2717, "t": 1790949780000 },
{ "v": 1427028.868773, "vw": 770.0764, "t": 1790949840000 }
],
"status": "OK"
}
Combined, they give 770.23535. The five-minute bar for the same window:
curl -X GET "https://api.massive.com/v2/aggs/ticker/SPY/range/5/minute/1790949600000/1790949600000?adjusted=false&apiKey=YOUR_API_KEY"
Response
{
"ticker": "SPY",
"adjusted": false,
"results": [
{ "v": 1875198.2799860002, "vw": 770.2354, "o": 770.56, "c": 771.63, "h": 771.66, "l": 769.88, "t": 1790949600000, "n": 14186 }
],
"status": "OK"
}
The five-minute v is the sum of the five minute volumes, and its vw of 770.2354 matches the combined 770.23535 to the fourth decimal place, give or take one in the last digit.
The daily stock bar does not combine this way. It is built separately from the minute bars and counts trades that no minute bar includes, so its vw does not reproduce from them. SPY's daily bar for 2 October 2026 has a v of 46,335,295.918728, while that day's minute bars sum to 44,484,899.05 shares. How does Massive create aggregate bars? describes how each timespan is assembled.
Why this happens
The two plans that govern US stock trade reporting, CTA and UTP, give each sale condition separate rules for price and for volume. A trade can be real volume that changed hands while its price says nothing about the market at that moment, such as an average-price print, an odd lot or one leg of a contingent package. Massive's bars follow the consolidated rules, so those trades go into v and vw and stay out of h and l.
If you see an error
vw below l or above h on a stock bar is not an error. Pull the bar's trades from /v3/trades and look for a large trade outside the range that carries a condition from the table above.
A daily vw that does not match your combination of minute bars is expected, because the daily bar counts trades the minute bars do not.

