DEV Community

Emily
Emily

Posted on

Handling UTC vs ET in Stock Market APIs: A Practical Guide with Python

If you’ve ever pulled historical stock data and found your charts shifted by an hour, you’re not alone. As a tech lead at a FinTech startup, I hit this wall hard. In this post, I’ll walk you through why it happens and how to fix it cleanly in your code.

Our Real-World Encounter

We were building a cross-market backtesting platform. Things were smooth until we combined two data feeds for US stocks. The minute bars were identical in price but off in time. This small discrepancy broke our intraday signal timing and caused a lot of confusion. The root cause: one API returned UTC, the other ET. Without explicit handling, our pandas dataframes treated both as naive timestamps.

The UTC/ET Dilemma Explained

  • UTC is consistent year-round, perfect for storage and computation.
  • ET reflects the actual US market hours but switches between EST (UTC-5) and EDT (UTC-4).

When you store data in ET, you risk duplicate or missing hours during DST transitions. When you store in UTC, you lose the quick visual mapping to Wall Street’s clock. Best practice: keep everything in UTC internally, convert to ET at the display or strategy layer.

How to Request and Process Time Zones

Always explicitly set the timezone parameter when fetching historical data:

GET /api/v1/history?symbol=AAPL&interval=1m&timezone=UTC
Enter fullscreen mode Exit fullscreen mode

Once you have the data, use pandas to enforce UTC and derive an ET column:

import pandas as pd

df["timestamp"] = pd.to_datetime(df["timestamp"], utc=True)
df["timestamp_et"] = df["timestamp"].dt.tz_convert("US/Eastern")
Enter fullscreen mode Exit fullscreen mode

For real-time streams, you want the provider to give you a reliable timestamp. AllTick’s WebSocket, for example, sends a ts field that’s ready to use:

from websocket import WebSocketApp
import json

def on_message(ws, message):
    data = json.loads(message)
    ts = data["ts"]
    price = data["price"]
    print(ts, price)

ws = WebSocketApp("wss://stream.alltick.co/v1/stock")
ws.run_forever()
Enter fullscreen mode Exit fullscreen mode

Time Well Spent

After implementing this pattern, our data pipeline became much more robust. Adding a new data source no longer required guessing its timezone conventions—we simply normalized everything on ingestion. It’s a small fix with huge returns in terms of code maintainability and backtest accuracy. If you’re dealing with financial data, make timezone handling a first-class citizen.

Top comments (0)