Skip to content
All library documents

Building OHLC Bars from a Chosen Price Stream

Article Quant Q&A · Author: Doctor J

Summary

The document explains how to construct periodic open, high, low, and close values from a stream of market prices. Its central rule is to choose one price series first—such as bids, asks, or last trades—and compute the bar from that series alone. For traded-price bars, the open is the first trade in the interval, the high and low are the interval extremes, and the close is the final trade. This means bid and ask data do not automatically enter a last-trade bar; they can instead be used to build separate bid or ask bars.

The discussion does not establish a universal market-wide standard or resolve whether adjacent intraday bars share a close and open, since that depends on the bar interval and event timing. An included code example shows one implementation based on bid ticks, while another answer says bid ticks are commonly used for some OHLC data. That comment is not supported with evidence, so feed conventions should be checked before comparing bars across sources.

Key ideas

  • An OHLC bar summarizes one selected price series over a defined time interval.
  • For traded-price bars, the first, maximum, minimum, and last trades determine open, high, low, and close.
  • Bid, ask, and trade prices can each be summarized separately rather than blended by default.
  • Bar boundaries and data-feed conventions affect whether one interval's close matches the next interval's open.
  • The claim that most OHLC data uses bid ticks is presented without supporting evidence.

Tags

Full text
# How are OHLC bars made from bid, ask, and last trade prices?


# How are OHLC bars made from bid, ask, and last trade prices?












This seems like a very basic question, but the Internet does not seem to know, so:

If you have a stream of bid, ask, and last trade prices, how do you convert those into periodic open/high/low/close bars? Is there a standard definition?

The main question is whether the summaries incorporate the bid and ask or just last trade prices. The other question is whether the previous close is equal to the next open (talking intraday bars here, excluding the session open and close).

My guess is that bars just use last trade prices and the previous close generally equals the next open, but that seems to drop a lot of information, especially for intraday bars.

## Answer by SRKX (score 1, accepted)

https://quant.stackexchange.com/a/31814

Bars represent an summarized view of what happened during a given period of time of a single given value.

Therefore, you need to first pick the value you want to summarize: Bid, Ask or Last Trade and use values of only these measures to build your bars.

## Answer by Alex Turnbull (score 1)

https://quant.stackexchange.com/a/31828

Pick a time range of traded prices, open is the first value in the range, high is the max of the range, low is the min and close is last value in the range.

## Answer by Marcelius (score 1)

https://quant.stackexchange.com/a/32089

I made the next C++ conversion function.

```
int Convert( Bar *bars, const Tick *tick, int tickCount, int lookback  )
{
    #define Normalize(a)    double((int((a)*m_scale+0.5))*m_point)
    unsigned int m_end = 0;
    int count = 0, i = 0;
    Bar *pBars = bars[count++];

   // lookback - bar's timeframe in seconds
    const Tick &t = tick[i++];
    pBars->Time = t.Time / lookback;
    pBars->Time *= m_lookback;
    pBars->Open = pBars->Close = pBars->High = pBars->Low = Normalize(t.Bid);
    pBars->Volume = t.Volume();
    m_end = pBars->Time + lookback;
    while (i < tickCount)
    {
        const Tick &t = tick[i++];

        if (t.Time < m_end)
        {
            double price = t.Bid;

            if (pBars->Low > price)
                pBars->Low = price;
            else if (pBars->High < price)
                pBars->High = price;

            pBars->Close = price;
            pBars->Volume += t.Volume();
        }
        else
        {
            pBars->Close = Normalize(pBars->Close);
            pBars->High = Normalize(pBars->High);
            pBars->Low = Normalize(pBars->Low);

            pBars = bars[count++]
            pBars->Time = t.Time / lookback;
            pBars->Time *= m_lookback;
            pBars->Open = pBars->Close = pBars->High = pBars->Low = Normalize(t.Bid);
            pBars->Volume = t.Volume();
            m_end = pBars->Time + lookback;
        }
    }
    return barIdx;
}
```

## Answer by cardycakes (score -2)

https://quant.stackexchange.com/a/31819

My understanding is that most OHLC data is made from Bid ticks

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.