sifting/io
Quant Research & Backtesting
7 min readSiftingIO Team

When does a daily candle open and close? Daily bar boundaries in stocks, forex, and crypto

When a daily candle opens and closes in US stocks, forex, and crypto, why weekend gaps exist, and why two providers' daily bars can legitimately differ.

When does a daily candle open and close? Daily bar boundaries in stocks, forex, and crypto

When does a daily candle open and close? It depends on the asset class, and on who built the bar. A US stock daily candle covers one fixed trading session. A forex daily candle covers 24 hours of a market with no official close, so every provider has to pick a cutoff. A crypto daily candle almost always runs from midnight UTC to midnight UTC, seven days a week. Those choices are why the same calendar day's EURUSD candle from two data sources can show different opens, highs, lows, and closes while both are internally correct. This post lays out the daily bar boundary conventions for each asset class, explains where weekend gaps come from, and shows how to build daily bars with a boundary you control. If bars themselves are unfamiliar, start with What is OHLCV data, which covers how providers construct them in the first place.

Daily bar boundaries by asset class#

Asset classTrading sessionTypical daily bar boundaryWeekend gap
US stocksFixed session, 09:30 to 16:00 Eastern (regular hours)One bar per trading date; regular session only, or extended hours includedYes, plus market holidays
Forex24 hours a day, Monday to Friday17:00 New York time, or 00:00 UTCYes, Friday evening to Sunday evening
Crypto (centralized)24/700:00 UTCNo
Commodities (spot)Near 24 hours on weekdays, with short breaks00:00 UTC or a venue-style close; varies by providerYes for most products
DEX / on-chain24/7, block by block00:00 UTCNo

US stocks are the simple case. The market has a fixed regular session, 09:30 to 16:00 Eastern time, so a daily bar maps cleanly to a trading date: the open is the first regular-session trade, the close is the official closing price, and there's simply no bar on weekends or holidays. The main ambiguity is extended hours. Some feeds fold pre-market and after-hours trades into the daily high and low, others exclude them, and the two versions of the same bar can disagree on the extremes while agreeing on open and close. Half days matter too: the session ends at 13:00 Eastern on certain days around holidays, which is why a holiday calendar (or the live status view at /market-hours) belongs in any pipeline that assumes a 16:00 close.

Forex has no official close at all. The market runs continuously from Sunday evening to Friday evening, New York time, passing from one regional session to the next. A daily candle therefore needs an arbitrary cut, and two conventions dominate. The older one closes the day at 17:00 New York time, which aligns each bar with the institutional FX trading day. The other closes at 00:00 UTC, which is fixed and simple but splits the New York afternoon across two bars. Weekend handling adds a second fork: under a New York close, the few hours between the Sunday open and the first cutoff either become a small standalone Sunday candle or get merged into Monday's bar. That single decision changes whether a week holds five daily candles or six.

Crypto is the easy one. Centralized venues trade around the clock, and a daily candle running 00:00 UTC to 00:00 UTC is close to universal. There's no weekend gap: Saturday and Sunday get full bars like any other day. On-chain DEX activity works the same way, except the tape advances block by block rather than trade by trade. Spot commodities sit in between: metals and energy pairs such as XAUUSD and WTIUSD trade nearly around the clock on weekdays with short maintenance pauses, and daily boundaries vary more across providers here than in any other class, so check the convention before comparing sources.

Why two providers' daily bars can legitimately differ#

Take EURUSD on an ordinary Tuesday. A provider that closes the day at 17:00 New York and one that closes at 00:00 UTC are summarizing two different 24-hour windows, so all four of open, high, low, and close can differ with nothing wrong on either side. The common causes stack up:

  • Boundary time: 17:00 New York, 00:00 UTC, and venue-local midnight cover different windows.
  • Daylight saving time: a New York close is a moving target in UTC, 22:00 in winter and 21:00 in summer. A provider that fixes the cut at 22:00 UTC year round matches the New York convention for only half the year.
  • Session definition: for stocks, extended hours in or out of the high and low.
  • Sunday handling: a separate Sunday bar, or those hours folded into Monday.
  • Venue set: bars aggregated from different sets of venues print different extremes even over the identical window.
  • Labeling: some sources stamp a bar with its open time, others with its close date, so the same candle can appear under Tuesday in one dataset and Wednesday in another.

The main FX conventions in UTC terms:

ConventionUTC boundary (winter)UTC boundary (summer)Trait
17:00 New York close22:0021:00Follows the FX trading day; moves with US daylight saving
00:00 UTC00:0000:00Fixed and reproducible; splits the New York afternoon
Venue-local midnightVariesVariesCommon in charting tools; hardest to reproduce

None of these is wrong. What breaks research is mixing them silently, for example validating a daily backtest built on midnight UTC bars against closes quoted on the New York convention.

Building daily bars with a boundary you control#

For US stocks, SiftingIO serves daily bars directly (intervals run from 1m to 1mo). Historical bar endpoints require gzip, so include compression or the API answers 406 gzip_required:

curl --compressed -H "X-API-Key: $SIFTING_KEY" \
  "https://api.sifting.io/v1/hist/stocks/AAPL/bars?interval=1d&limit=200"

For forex and crypto, timestamps come back in UTC, and when you need a daily boundary other than midnight UTC you build it from hourly bars. That puts the cut in your own code, where it's explicit and reproducible: fetch hourly bars once, then roll them up wherever your research needs.

import requests
import pandas as pd

r = requests.get(
    "https://api.sifting.io/v1/hist/forex/EURUSD/bars",
    headers={"X-API-Key": KEY, "Accept-Encoding": "gzip"},
    params={"interval": "1h", "limit": 200},
)
df = pd.DataFrame(r.json()["bars"])  # o/h/l/c plus a UTC timestamp; see /docs for the exact shape
df.index = pd.to_datetime(df["t"], unit="ms", utc=True)
agg = {"o": "first", "h": "max", "l": "min", "c": "last"}

daily_utc = df.resample("1D").agg(agg)              # midnight UTC days

ny = df.tz_convert("America/New_York")
daily_ny = ny.resample("1D", offset="17h").agg(agg)  # 17:00 New York close days

Resampling in the America/New_York timezone, rather than applying a fixed UTC offset, is the detail that keeps the 17:00 boundary correct across daylight saving transitions. Run both resamples over the same hourly data and compare the close columns. They'll disagree on most days, and that disagreement is the boundary convention made visible.

Common pitfalls#

Forgetting gzip on historical bars. The /v1/hist/* bar endpoints require compressed transfer. Without Accept-Encoding: gzip (or curl's, compressed) the request fails with 406 and the body { "error": "gzip_required" }. It looks like an auth or path problem at first glance; it's a missing header.

Fixed-offset resampling across DST. Cutting daily FX bars at a hardcoded 21:00 or 22:00 UTC reproduces the New York close for only part of the year. Around the March and November transitions your daily closes drift one hour from any New York close reference, and the error surfaces as small differences in daily returns that are hard to trace.

Comparing closes across conventions. Before flagging a discrepancy between your daily bar and a number from another source, check the boundary time, the Sunday rule, and whether bars are stamped at the open or the close. Most bad-data reports about daily candles turn out to be two correct answers to two different questions.

Daily candles look like the simplest dataset in market data until two of them disagree. Pin the boundary down, keep it in one timezone rule, and build FX and crypto days from hourly bars so the cut lives in your own code. Read the docs for the full bar endpoint reference across all six asset classes.

Keep reading

Related posts