Skip to content
Friday, 9 October 2026 · LondonENع
Rayan Azhari.Sustainability · Energy · Carbon · Built EnvironmentOccasional detours into philosophy, religion or programming, wherever curiosity leads
Production Quant Trading

Bar Timestamp Convention: The Open vs Close Stamp That Leaks a Full Bar of Look-Ahead

A bar carries one timestamp, but that stamp is ambiguous: is a bar labelled 09:00 the open of the coming interval or the close of the last one? Vendors disagree, and reading the wrong edge is a clean one-bar look-ahead that sails through review. Here is the war-story, why the leak is invisible, and the ingest rule I now enforce on every feed.

Rayan AzhariChartered Environmentalist, MISEP · 9 min read
Title card for Open-Stamped or Close-Stamped, showing a bar labelled 09:00 with a safe close-stamped arrow left and a look-ahead open-stamped arrow right.

A bar carries exactly one timestamp, and that single number is quietly ambiguous. A bar labelled 09:00 could mean two completely different things. It could be the open of the interval that runs from 09:00 to 10:00, in which case the bar's close price belongs to the world at 10:00 and does not exist yet at the stamped instant. Or it could be the close of the interval that ran from 08:00 to 09:00, in which case everything on that bar, open, high, low and close, was already known when the clock struck 09:00. Same label. A full bar apart. And nothing on the row tells you which one you are holding.

I shipped a strategy once that read an open-stamped feed as if the stamp were the close. Every decision it made used a price from the end of a bar that, at the timestamp it keyed off, had not happened yet. The backtest was gorgeous. It was also a clean one-bar look-ahead, manufactured not by a clever bug but by a disagreement about what a timestamp means. This is the essay I wish I had read before that.

One label, two meanings, a session apart

Ask a vendor for daily bars and you get a column of dates and, per date, an open, high, low and close. The date is the only temporal anchor. So which instant does it mark? There is no universal answer. Some feeds open-stamp: the timestamp is the moment the interval began, and the bar accumulates forward from there. Some feeds close-stamp: the timestamp is the moment the interval ended, and the bar is a finished, fully-known object at that instant. Both conventions are internally consistent. Both are common. Neither is wrong. They are simply different contracts, and the row does not carry its own contract.

Figure

Where the one-bar leak enters

A bar carries one timestamp, but that stamp is ambiguous, and the ambiguity is a full bar of look-ahead.

  1. 1

    A bar is labelled 09:00

    but is that the open or the close of the interval?

  2. 2

    Open-stamped: the interval runs 09:00 to 10:00

    its close price is only knowable at 10:00

  3. 3

    Act on that close 'at 09:00' and you reach a full bar into the future

    a clean one-bar look-ahead, invisible on a chart

A close-stamped bar carries a completed OHLC, so acting at the stamp is legitimate. An open-stamped bar does not.

Source: Building a Production Quant Trading System (Titan)

Here is why the difference is not cosmetic. The close price is the last thing a bar learns. On a close-stamped bar, the timestamp is the instant the close printed, so treating the close as knowable at the timestamp is simply true. You knew it because it had just happened. On an open-stamped bar, the timestamp is the instant the bar began. The close will not be known for one whole interval. So if your code does the natural thing, take the row whose timestamp is t and use its close to make a decision "at t", you have read a price from the future on every open-stamped feed. Not by a millisecond. By a full bar.

That is the leak. It enters at exactly one line, the line where you assume the close on a row is knowable at that row's timestamp, and whether that assumption is a truth or a look-ahead depends entirely on a convention nobody wrote down.

Why it survives review, and why the curve looks fine

Look-ahead bias, as I have argued before, is the default state of careless backtest code, not an exotic edge case, and it hides because it reads as ordinary. The stamp version is the purest example I know. There is no suspicious line. There is a dataframe indexed by timestamp and a decision that uses the close on the current row. That is what competent code looks like. The bug is not in the code at all. It is in the mismatch between what the code assumes about the index and what the vendor actually meant by it. You cannot proofread that mismatch away, because the code is locally correct for some convention, just not the one your feed happens to use.

And the equity curve does not warn you. A one-bar look-ahead on an autocorrelated price series produces a curve that climbs. It looks like an edge. It passes a robustness check, because nudging the parameters does not remove a leak that is baked into the data alignment rather than the parameters. It even survives an out-of-sample split, because the leak travels with the data into every slice. Every downstream diagnostic you trust is looking at numbers that were already poisoned upstream, at ingest, by a single unstated assumption.

The mirror image is just as expensive and far quieter. Assume close-stamped when the feed is open-stamped in the other direction, treat a finished bar as if its close were still an interval away, and you are not leaking, you are lagging. You act on every bar one interval late. No look-ahead, no phantom edge, just a real edge slowly bled out through a systematic delay you never see, because a strategy that is merely a bit worse than it should be looks exactly like a strategy that is merely a bit worse than you hoped.

The war-story: the stamp that read the future

The incident that made me hard-code this rule came from a corner of Titan, my live multi-strategy system, that had been fed happily by one vendor for months. I brought in a second feed for the same instrument to cross-check coverage, and I wired a strategy to the new series without checking one thing: the new vendor open-stamped its bars, and my alignment code, written against the old close-stamped feed, treated the row timestamp as the moment I could act.

So every decision the strategy made at a bar's timestamp used that bar's close. On the old feed that was legitimate: the timestamp was the close, the close was known. On the new feed the timestamp was the open, and the close it read belonged to a bar that, at that instant, was still an entire interval from finishing. The strategy was, with a completely straight face, deciding today's position using a price that would not exist until tomorrow. The backtest on the new feed looked better than on the old one, which is the cruel part, because a fresh full-bar of look-ahead flatters a momentum-flavoured signal beautifully.

Figure

The ingest rule that closes the leak

Fix the convention once, at the boundary, before any strategy sees the data.

Establish

per feed

Read each vendor's convention from the docs and confirm it empirically, then record it in the data contract. Vendors disagree; one feed's 09:00 is another's 10:00.

Normalise at ingest

one house convention

Convert every feed to a single convention (close-stamped, one timezone) at load, so everything downstream speaks one clock.

Act only after close

complete bars only

A strategy may use a bar only once it is complete, keeping the decision window and the return window disjoint.

The leak is closed at the boundary, not policed in every strategy.

Source: Building a Production Quant Trading System (Titan)

Nothing crashed. Nothing threw. The curve got prettier. The only reason I caught it was that I ran a causality check that poisons future prices and asserts the past does not move, and the past moved. The test pointed at the alignment, and the alignment pointed at the stamp, and the stamp pointed at a one-line assumption that had silently become false the moment I swapped feeds. The fix was not clever. It was to establish, in writing, what each feed's timestamp meant, and to convert both to the same convention before a single line of strategy code touched them.

The portable rule: one convention, established at ingest, act only after close

Here is the artefact to keep. It is three sentences, and it closes the whole family of stamp bugs at the boundary of your system, before any strategy can inherit them.

First, for every feed, establish which edge the timestamp marks. Open or close, and in which timezone. This is not a guess and it is not an inference from the numbers. It is a fact you get from the vendor's documentation, confirm empirically against a bar you can independently time, and then record as part of the data contract, the same way you record the column names and the units. A feed whose stamp convention you have not written down is a feed you do not actually understand, no matter how clean the numbers look.

Second, convert everything to a single convention at ingest. Pick one house convention (I close-stamp everything, so that a row's timestamp always means "this bar is finished and fully known as of here"), and normalise every incoming feed to it at the edge, once, before it lands in storage. After that point nothing downstream has to remember which vendor a series came from or which way it stamped, because they all speak the same clock. The bug factory is the middle ground where two conventions coexist and every consumer has to get the alignment right individually. Collapse them to one and the question stops being askable.

Third, only ever act at or after a bar's close. Whatever the stamp says, a decision may only use information that was genuinely knowable at the instant you claim to act. Once every feed is close-stamped, "act at the timestamp" is safe by construction, because the timestamp is a moment when the bar is complete. A decision and the return it earns then live in disjoint windows automatically, which is the whole point of the shift discipline, but the shift discipline only protects you if the edge it shifts around is the edge you think it is.

Figure

The ingest rule that closes the leak

Fix the convention once, at the boundary, before any strategy sees the data.

Establish

per feed

Read each vendor's convention from the docs and confirm it empirically, then record it in the data contract. Vendors disagree; one feed's 09:00 is another's 10:00.

Normalise at ingest

one house convention

Convert every feed to a single convention (close-stamped, one timezone) at load, so everything downstream speaks one clock.

Act only after close

complete bars only

A strategy may use a bar only once it is complete, keeping the decision window and the return window disjoint.

The leak is closed at the boundary, not policed in every strategy.

Source: Building a Production Quant Trading System (Titan)

That is the entire rule: establish the convention, normalise at ingest, act only after close. It is boring. It lives in the least glamorous part of the pipeline, the ingest boundary, and it will never show up as a line on an equity curve. Which is exactly why it is worth pinning above the desk, because the bugs it prevents will never show up as errors either. They show up as a curve that is too good, or an edge that is quietly too small, and by the time you are looking at those it is far too late to ask what your timestamps meant.

Where this sits, and where the machinery lives

The stamp convention is one hazard in a larger layer I have learned to respect: the clock beneath the data. Exchange calendars that make a coarse "is the market open?" heuristic wrong in both directions on holidays and half-days. Daylight saving quietly shifting a local-time rebalance by an hour, twice a year, on different dates for different asset classes. A single wall-clock schedule that is correct for at most one venue in a multi-asset book. Each of those is a silent off-by-one waiting for the season, or the holiday, or the feed swap that trips it, and each fails the same way the stamp bug does: not with an exception, but with a number that is subtly, plausibly wrong.

I keep the full treatment, the calendar layer, the DST-aware session anchoring, the data contract schema and the ingest normalisation that enforces all of it, in the paid half of the book, because the value is in the implementation and the thresholds, not in the slogan. This essay gives you the war-story, the reason the leak is invisible, and the one rule that closes it. If you want the machinery, Building a Production Quant Trading System is where the time-and-sessions chapter lives, as a living digital copy on Leanpub and a print paperback on Amazon, and the sanitised, Apache-2.0 companion framework shows the shape the ingest boundary takes in code.

Carry one sentence out of here: a bar's timestamp is a claim about which instant it means, and until you have established, normalised and asserted that claim, every decision keyed off it is trading on a convention you never checked.

This is an engineering essay, not investment advice, and it contains no tradable strategy. All figures are illustrative and sanitised, and the war-stories are about bugs, not profits.

Figure

Where the one-bar leak enters

A bar carries one timestamp, but that stamp is ambiguous, and the ambiguity is a full bar of look-ahead.

  1. 1

    A bar is labelled 09:00

    but is that the open or the close of the interval?

  2. 2

    Open-stamped: the interval runs 09:00 to 10:00

    its close price is only knowable at 10:00

  3. 3

    Act on that close 'at 09:00' and you reach a full bar into the future

    a clean one-bar look-ahead, invisible on a chart

A close-stamped bar carries a completed OHLC, so acting at the stamp is legitimate. An open-stamped bar does not.

Source: Building a Production Quant Trading System (Titan)

Figure

The ingest rule that closes the leak

Fix the convention once, at the boundary, before any strategy sees the data.

Establish

per feed

Read each vendor's convention from the docs and confirm it empirically, then record it in the data contract. Vendors disagree; one feed's 09:00 is another's 10:00.

Normalise at ingest

one house convention

Convert every feed to a single convention (close-stamped, one timezone) at load, so everything downstream speaks one clock.

Act only after close

complete bars only

A strategy may use a bar only once it is complete, keeping the decision window and the return window disjoint.

The leak is closed at the boundary, not policed in every strategy.

Source: Building a Production Quant Trading System (Titan)

Further reading

Office energy, part 13 of 25

Related posts

Adjusted vs Unadjusted Close: The Dividend Double-Count That Fakes a Backtest Edge

Total-return and price-return series look identical on a chart and differ by percent-per-year underneath. Mix them, or fold dividends in twice, and a long-horizon backtest drifts a few percent above the honest one every year and compounds into a phantom edge. Here is the reconstruction check I now run: rebuild total return from price plus the dividend stream yourself and diff it against the vendor's adjusted series.

· 9 min

Survivorship Bias in a Backtest: The Delisted-Fraction Smell Test

Survivorship bias is the term every quant knows and almost nobody makes actionable. Here is the one-number diagnostic I run before I trust any cross-sectional backtest: count the dead names as a share of your universe over a decade. If it is near zero, your data quietly deleted the losers and every result is biased upward.

· 9 min

Capacity and Crowding: Why a Real Edge Still Decays at Size

Even a genuine edge dies if you deploy it too large. This is the field note on alpha-side risk: how your own market impact (capacity) and everyone else trading the same signal (crowding) shrink the size at which the edge is still yours, and the crossover test that tells you where your ceiling sits before the market finds it for you.

· 9 min

Essays in your inbox

New writing on Syria, sustainability and finance, a few times a month.

Unsubscribe anytime. Read by 4,200+ professionals.