When does the weekly candle open and close For US stocks it runs from the first regular session open of the week to the last session close. For crypto it opens Monday 00:00 UTC and closes at the end of Sunday, by convention. For forex there's no single answer, which is why a weekly candle drawn by your own code so often disagrees with the one on your chart. This post gives the boundary for each asset class, then shows how to rebuild whichever convention your chart uses from timestamped bars. It follows on from the daily candle post, which covers the daily boundaries these weekly bars are built from. If bars themselves are new to you, what OHLCV data is explains how one is formed.
Forex: the week opens Sunday 5:00 pm New York time#
The forex trading week begins on Sunday at 5:00 pm New York time, when the Asia-Pacific session opens, and ends on Friday at 5:00 pm New York time. That much is broadly agreed. Where the daily bars inside that week get cut varies. Platforms slice their daily forex bars anywhere from 2:00 pm to 6:00 pm New York time, and some cut at midnight in the server's own timezone instead. Because a weekly candle is the aggregate of its daily bars, two charts can draw different-looking weekly candles for the same pair and the same week.
The visible symptom is the Sunday bar. A platform whose daily cut falls exactly at 5:00 pm New York time draws a clean five-day week, because Sunday evening's trading is absorbed into Monday's bar. A platform that cuts at midnight draws a thin extra Sunday bar covering only the hours between the open and midnight, followed by five full bars. Both charts contain the same hours, so the weekly open, high, low, and close usually match. They stop matching when one platform drops the Sunday-evening hours altogether and opens its week at Monday 00:00 UTC, or cuts Friday earlier than the other. Then the weekly open moves, and sometimes the high or low moves with it.
The SiftingIO forex history is labeled in UTC. Daily bars carry a 00:00 UTC timestamp, and the native 1w bar carries a Monday 00:00 UTC timestamp and spans the UTC calendar week, Monday through Sunday. That has one consequence worth knowing. When the feed contains Sunday-evening bars, those hours fold into the previous week's 1w bar, so its close is Sunday evening's last price rather than Friday's 5:00 pm close. If you want the trading-week convention instead, build it yourself from hourly bars, as shown below.
Crypto: Monday 00:00 UTC by convention#
Crypto trades around the clock, so there's no session to anchor on and the convention is borrowed from the calendar. Daily bars roll at 00:00 UTC, and the weekly bar opens Monday 00:00 UTC and closes at the end of the following Sunday. The SiftingIO crypto history follows this exactly: daily bars are stamped 00:00 UTC and 1w bars are stamped Monday 00:00 UTC. The one variant you'll meet is a chart that starts weeks on Sunday, US calendar style. That candle contains the same seven days shifted by one, so its open and close differ from a Monday-start candle every single week.
US stocks: first session open to last session close#
A weekly stock candle opens at the first regular session open of the week and closes at the last regular session close. In a normal week that is Monday 9:30 am to Friday 4:00 pm New York time. A holiday week is shorter: the week of a Monday holiday opens on Tuesday, and a week with a Friday holiday closes on Thursday. The bar keeps the week's label even when its first trading day is Tuesday. In the SiftingIO stock history there is no daily bar for Monday May 25, 2026 (the Memorial Day holiday), and the 1w bar for that week still carries the Monday 00:00 UTC timestamp while its open is Tuesday's open:
{"t":1779667200000,"o":310.77,"h":315,"l":307.65,"c":311.18,"v":6182577}
Aggregating the four daily bars of that week gives the same numbers. Upcoming holidays and half days for all 23 markets are listed on the market hours page, which is the quickest way to check whether a given week is short.
Reproducing a weekly candle from SiftingIO bars#
Every /v1/hist/* bar carries its open time in field t as Unix epoch milliseconds UTC, and these endpoints require gzip. The stock, forex, and crypto bar endpoints all accept interval values from 1m up to 1w and 1mo, so the native weekly bar is one call:
curl -H "X-API-Key: $SIFTING_KEY" -H "Accept-Encoding: gzip" --compressed \
"https://api.sifting.io/v1/hist/stocks/AAPL/bars?interval=1w&start=2026-05-18&end=2026-06-06"
To reproduce a chart that uses a different week boundary, pull a finer interval and aggregate it. The rules are the ones from the resampling post: first open, highest high, lowest low, last close. The function below fetches bars with cursor pagination, then keys each bar to a trading week defined by a daily cut hour in a chosen timezone. A cut of 17 in New York time reproduces the Sunday 5:00 pm convention. A cut of 0 in UTC reproduces the Monday 00:00 UTC calendar week, which is what the native 1w bars use.
import requests
import pandas as pd
BASE = "https://api.sifting.io/v1/hist"
HEADERS = {"X-API-Key": SIFTING_KEY, "Accept-Encoding": "gzip"}
def bars(cls, symbol, interval, start, end):
rows, cursor = [], None
while True:
params = {"interval": interval, "start": start, "end": end, "limit": 200}
if cursor:
params["cursor"] = cursor
r = requests.get(f"{BASE}/{cls}/{symbol}/bars", headers=HEADERS, params=params)
r.raise_for_status()
body = r.json()
rows += body["data"]
cursor = body["meta"].get("next_cursor")
if not cursor:
break
df = pd.DataFrame(rows)
df["t"] = pd.to_datetime(df["t"], unit="ms", utc=True)
return df.set_index("t").sort_index()
def weekly(df, cut_hour=17, tz="America/New_York"):
local = df.index.tz_convert(tz)
# shift so the cut hour becomes midnight, then take the trading date
if cut_hour:
day = (local + pd.Timedelta(hours=24 - cut_hour)).normalize()
else:
day = local.normalize()
week = day - pd.to_timedelta(day.weekday, unit="D") # Monday of that trading week
grouped = df.groupby(week.tz_localize(None))
return grouped.agg(o=("o", "first"), h=("h", "max"), l=("l", "min"), c=("c", "last"))
fx = bars("forex", "EURUSD", "1h", "2026-06-07T20:00:00Z", "2026-06-13T00:00:00Z")
print(weekly(fx, cut_hour=17)) # Sunday 5:00 pm New York trading week
print(weekly(fx, cut_hour=0, tz="UTC")) # Monday 00:00 UTC calendar week
us = bars("stocks", "AAPL", "1d", "2026-05-18", "2026-06-06")
print(weekly(us, cut_hour=0, tz="UTC")) # matches the native 1w bars above
The forex week of June 8, 2026 is a good test case because the feed has bars from Sunday 21:00 UTC that evening. With the 5:00 pm cut those hours open the new week. With the UTC calendar cut they close the old one, and the two weekly opens differ. The same function works on hourly crypto bars, and on daily stock bars because those are stamped 00:00 UTC on the trading date.
Common pitfalls#
A mid-week start returns a partial first weekly bar. Requesting interval=1w with start=2026-08-05, a Wednesday, returns a bar labeled Monday August 3 whose open is Wednesday's first price, for stocks, forex, and crypto alike. The bar is built only from data after your start. Align start to a Monday, or to the Sunday afternoon before it for forex, and drop the first bar if you can't.
A date-only end is the start of that date, so the last bar in a range comes back short. Requesting EURUSD daily bars with end=2026-08-28 returned a Friday bar with a range of a few pips, because only the first hours of that day fell inside the window. Ending at 2026-08-28T23:59:59Z returned the full bar. Set end to the day after the last day you want, or use an explicit RFC 3339 timestamp.
Don't assume the first forex bar of the week is a Sunday bar. Coverage of the Sunday-evening hours varies in the history, and some weeks begin at Monday 00:00 UTC. Derive the week from the timestamp as the function above does, and never count bars to find Monday. The same goes for the cut hour: 5:00 pm New York is 21:00 UTC in summer and 22:00 UTC in winter, so convert through a real timezone rather than hardcoding a UTC hour.
Endpoint parameters, the full interval list, and the cursor format are in the docs.



