data_updater_v2.data_clients.bars
bars.py — the one bar shape every client’s prices come back in, whoever served them.
The raw price tables’ column set (nc-data models/core_data/prices.py): one row per bar,
keyed (symbol, date) daily and (symbol, date, bar_interval) intraday.
symbol the ticker as the vendor serves itdate the bar's START as a naive UTC datetime (the key)utc_date · utc_time that instant's UTC date and time of dayest_date · est_time the same instant on the US/Eastern wall clock (EST or EDT)bar_interval intraday only: 1min, 5min, ...open · high · low · close as traded (unadjusted)volume shares for stocks and ETFs (as traded: FMP raw minutes and EODHD daily volume are put back on that scale), contracts for commodities, the vendor's number for indices, DOLLARS (the quote currency) for crypto; None where the vendor's number cannot be trusted (a minute day FMP mis-adjusted, EODHD crypto minutes)coin_volume crypto only: the base currency's units (BTC for BTCUSD)A DAILY bar carries day identity, not an instant: date is the day at 00:00, utc_date
= est_date = the day, both times 00:00. The day is the venue’s: the ET session date for
listings, the UTC day for crypto (FMP’s crypto daily closes on the UTC day: its close matches
Bitstamp’s last UTC minute to ~1 bp, the ET day’s by 17-44 bp; probed 2026-10-04).
Crypto volume both ways, from whichever unit the source served: FMP serves dollars (composite, all venues: BTC ~$37B a day) and Bitstamp coins (one venue: ~1,900 BTC a day). The other unit is derived over the bar’s own price: the daily VWAP where the vendor gives one, else the bar’s typical price (high + low + close) / 3. Within a source the two agree; across sources they never will (composite vs one venue), so a row’s source decides which is served.
Functions
daily_bar
daily_bar(symbol: str, day: dt.date | str, open_: Any, high: Any, low: Any, close: Any, volume: Any, **extra: Any) -> dict[str, Any]One daily bar with day identity. extra carries coin_volume for crypto.
finished
finished(bars: list[dict[str, Any]], interval: str) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]Intraday bars whose span has ended: (kept, the bar still forming taken out).
in_window
in_window(bars: list[dict[str, Any]], lo: dt.date | None, hi: dt.date | None, field: str) -> list[dict[str, Any]]The bars whose day (field: utc_date or est_date) lies in [lo, hi]: what was asked
(FMP’s /api/v3 answers an inverted window with history; a chunked walk returns whole
days past the ask). Not a drop: rows outside the ask are not the answer.
intraday_bar
intraday_bar(symbol: str, start: dt.datetime, interval: str, open_: Any, high: Any, low: Any, close: Any, volume: Any, **extra: Any) -> dict[str, Any]One intraday bar from its START instant (timezone-aware: FMP’s Eastern wall clock
or Bitstamp’s UTC epoch, converted before this). extra carries coin_volume.
ny_now
ny_now() -> dt.datetimeNow on New York’s clock (a sensor’s window is New York hours).
ny_today
ny_today() -> dt.dateToday in New York: the day a split, a payout, a listing or the calendar is judged by, whatever zone the machine runs in (a container runs on UTC, a day ahead from 20:00 ET).
on_the_minute
on_the_minute(bars: list[dict[str, Any]]) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]Intraday bars stamped on the minute: a lone stamp off the minute (11:57:04) moved to its minute (the closest clean one: the vendor’s tick, not a lost minute); one whose minute is already served taken out as its duplicate (^DJI 2023-12-27 twice, FMP).
one_each
one_each(bars: list[dict[str, Any]]) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]One bar per instant (a daily bar’s instant is its day): the first served is kept, a second for the same instant taken out.
priced
priced(bars: list[dict[str, Any]]) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]The bars with every price (open, high, low, close): a row the vendor served without one is no bar — taken out, named — before anything reads its prices.
process_intraday_bars
process_intraday_bars(bars: list[dict[str, Any]], interval: str, lo: dt.date, hi: dt.date, field: str) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]One symbol’s intraday bars (EODHD’s, Bitstamp’s) processed (each row already in the bar shape, zero volume kept at zero): the family’s days asked, stamps on the minute, one bar per instant, the bar still forming out, a row with no price out. Returns (bars, dropped).
sessions_between
sessions_between(lo: dt.date, hi: dt.date) -> list[dt.date]NYSE’s sessions in [lo, hi] (mcal): none in a weekend or a holiday.
settled
settled(bars: list[dict[str, Any]], family: str) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]The daily bars of finished days only, for a family (crypto, or a listing family:
equity, etf, index, commodity): (kept, the day still trading taken out). Vendors serve
the day still trading (mid-session 2026-10-05: FMP’s SPY row with 15.4M of the day’s
volume, FMP’s and EODHD’s BTC UTC day so far, Bitstamp’s current candle). Crypto’s day ends
at 00:00 UTC; a listing’s at that day’s NYSE close (mcal) — commodities and indices go by
the NYSE close too. A finished day with volume 0 stays, at 0 (FMP’s BTC days before
2016-01-02 carry real prices and no volume: Sam, 2026-10-08).
typical
typical(high: Any, low: Any, close: Any) -> float | NoneThe bar’s typical price, (high + low + close) / 3, or None when a leg is missing.
utc_today
utc_today() -> dt.dateToday’s UTC date: crypto’s day, and the latest day any family can have a bar on.