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.

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.

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.

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;
}


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

• That's about the source but that doesn't answer the whole question. – Bob Jansen Jan 6 '17 at 13:23