DEV Community

Emily
Emily

Posted on

Handling DST in Forex API K-Line Data: A Practical Guide for Developers

#ai

When building a forex analytics system, time handling is often treated as an afterthought. That was true for us until we noticed some historical hourly candles sitting in the wrong positions. The price data was correct, but the time axis had shifted. The cause? Daylight saving time transitions that weren’t accounted for in our data pipeline.

This post covers how we now handle DST shifts when working with a forex API and historical K-line data. We’ll walk through the problem, the schema we use, and the code that prevents future time-axis corruption.

The Problem: DST Start Day Changes UTC Mapping

On the day DST starts, the trading session doesn’t lose data. What changes is the UTC offset for local trading hours.

For U.S. markets during standard time, 09:00 New York = 14:00 UTC. During DST, 09:00 New York = 13:00 UTC.

Time Status Local Trading Time UTC Time
Standard Time 09:00 14:00
DST Active 09:00 13:00

If your K-line generator uses a fixed offset, candles around the switch date may be assigned to the wrong hourly bucket. This effect is most visible on minute and hourly charts.

Data Model: Add Time Metadata, Don’t Overwrite

Our rule is simple: keep the original timestamp, but add fields that describe the time context.

We store these four fields for every candle:

Field Purpose
utc_time Unified time standard
local_time Market local time
timezone Timezone identifier
dst_status DST active or not

Example record:

{
  "symbol": "EURUSD",
  "local_time": "2026-03-08 09:00:00",
  "utc_time": "2026-03-08T13:00:00Z",
  "dst_status": "active"
}
Enter fullscreen mode Exit fullscreen mode

With this, you always know the exact time environment for each candle.

Code: Avoid Fixed Offsets, Use Timezone Rules

Many developers convert timezones by adding or subtracting hours. That breaks on DST transition days because the offset changes.

Use timezone-aware conversion instead. Here’s a Python example:

from datetime import datetime
import pytz

timezone = pytz.timezone("US/Eastern")
time_str = "2026-03-08 09:00:00"
local_time = datetime.strptime(
    time_str,
    "%Y-%m-%d %H:%M:%S"
)
local_time = timezone.localize(local_time)
utc_time = local_time.astimezone(pytz.utc)
print(utc_time)
Enter fullscreen mode Exit fullscreen mode

This method requires no manual DST tables and remains accurate across years.

Real-Time and Historical Data: Keep Them Consistent

If real-time ticks and historical candles use different time standards, you’ll get gaps in your analysis. We always normalize timestamps before generating K-lines.

For example, when receiving live forex data through AllTick API, we convert the tradeTime field to UTC first, then build minute and hourly bars. The following WebSocket snippet shows the normalization step:

import websocket
import json
from datetime import datetime
import pytz

def on_message(ws, message):
    data = json.loads(message)
    trade_time = data["tradeTime"]
    tz = pytz.timezone("US/Eastern")
    dt = datetime.strptime(
        trade_time,
        "%Y-%m-%d %H:%M:%S"
    )
    dt = tz.localize(dt)
    utc_time = dt.astimezone(pytz.utc)
    print(data["symbol"], utc_time)

ws = websocket.WebSocketApp(
    "wss://api.alltick.co/stock/websocket",
    on_message=on_message
)
ws.run_forever()
Enter fullscreen mode Exit fullscreen mode

Practical Checklist for Developers

Based on our experience, we recommend:

  1. Add time metadata during ingestion, not during analysis.
  2. Use UTC as the internal standard; local time is for display only.
  3. Never use fixed hour offsets for K-line generation.
  4. Apply the same time-handling logic to both real-time and historical pipelines.

A forex API provides raw market data. Building a reliable system means handling timezones and DST at the storage level. Treat UTC as your source of truth and local time as presentation; this approach reduces long-term data inconsistencies.

Top comments (0)