A middleware API for XAU/USD data built with Express + TypeScript. It stores real-time price points and historical OHLC candles in Firestore, then serves them via public endpoints for charting.
| Collection | Interval | Used For |
|---|---|---|
gold_prices |
2-minute realtime | Latest price endpoint |
gold_ohlc_daily |
1day |
3M, 6M, YTD charts |
gold_ohlc_weekly |
1week |
1Y, 2Y charts |
gold_ohlc_monthly |
1month |
5Y, 10Y charts |
Why split by interval:
- Twelve Data intraday depth is limited.
- Daily, weekly, and monthly series are better for long-range chart windows.
Query range |
Collection |
|---|---|
1h |
gold_prices (full 2-minute points) |
5h |
gold_prices (full 2-minute points) |
1d |
gold_prices (downsampled to 10-minute points) |
5d |
gold_prices (downsampled to 10-minute points) |
1w |
gold_prices (downsampled to 10-minute points) |
1m |
gold_prices (downsampled to 2-hour points) |
3m |
gold_ohlc_daily |
6m |
gold_ohlc_daily |
ytd |
gold_ohlc_daily |
1y |
gold_ohlc_weekly |
2y |
gold_ohlc_weekly |
5y |
gold_ohlc_monthly |
10y |
gold_ohlc_monthly |
- Node.js 18+
- Twelve Data API key
- Firebase project with Firestore
GOOGLE_APPLICATION_CREDENTIALSpointing to a service-account JSON file
- Install dependencies:
npm install- Create
.envin project root:
TWELVE_DATA_KEY=your_twelve_data_api_key
INTERNAL_API_KEY=your_private_scheduler_key
FIRESTORE_DATABASE=gold-api
PORT=3000Development:
npm run devProduction:
npm run build
npm startReturns latest cached realtime price.
Response 200:
{
"timestamp": 1741651200000,
"price": 3150.42
}Response 503 when service has no cached price yet.
Returns historical series sorted oldest to newest.
Allowed range values:
1h,5h,1d,5d,1w,1m,3m,6m,ytd,1y,2y,5y,10y
Sampling rules:
1h,5h: full 2-minute data fromgold_prices1d,5d,1w: downsampled to 10-minute steps fromgold_prices1m: downsampled to 2-hour steps fromgold_prices3m+: OHLC candles from daily/weekly/monthly collections
Response 200 example:
[
{ "timestamp": 1741651200000, "price": 3150.42 },
{ "timestamp": 1741651320000, "price": 3150.35 }
]Returns realtime points (gold_prices) plus summary values for the active or most recently completed trading day (XAU/USD). Gold trades 24 hours a day from Sunday 18:00 to Friday 17:00 New York time, with a daily 1-hour break from 17:00 to 18:00.
- During Active Market Hours: Returns all points for the current ongoing trading session (starting at 18:00 NY time the previous day).
- During Weekends & Daily Breaks: If requested outside of trading hours, the API automatically returns the full data of the previous completed trading day. This ensures clients always receive a complete set of data to render, even on a Saturday.
Response 200 example:
{
"tradingDay": "2026-03-26",
"previousClose": 3024.15,
"high": 3040.22,
"low": 3018.76,
"points": [
{ "timestamp": 1774473600000, "price": 3022.55 },
{ "timestamp": 1774473720000, "price": 3023.10 }
]
}Notes:
pointsincludes all stored points exactly matching the resolved NY trading session.previousCloseis taken from the previous daily candle close when available.- If no previous daily candle exists, it falls back to the latest realtime point before the active session.
OHLC response example (3m, 6m, ytd, 1y, 2y, 5y, 10y):
[
{ "date": "2026-02-12", "open": 3050.1, "high": 3080.5, "low": 3040.0, "close": 3070.2 },
{ "date": "2026-02-13", "open": 3071.0, "high": 3095.0, "low": 3060.0, "close": 3088.5 }
]Mobile clients connect to this endpoint and then send a subscribe message. The server opens and maintains a Twelve Data WS connection only while subscribers exist.
Client subscribe message:
{ "action": "subscribe", "symbol": "XAU/USD" }Server price message example:
{
"type": "price",
"symbol": "XAU/USD",
"price": 3150.42,
"timestamp": 1741651200000,
"source": "twelvedata-ws"
}Notes:
- Current implementation supports
XAU/USDonly. - If no subscribers remain, server closes the upstream Twelve Data WS connection after a short grace period.
All endpoints below require header:
x-api-key: your_private_scheduler_key
Returns 401 if the key is missing or invalid.
Realtime fetch endpoint for 2-minute scheduler.
Fetches missing daily candles (smart incremental).
Fetches missing weekly candles (smart incremental).
Fetches missing monthly candles (smart incremental).
Backfills older history in 5000-candle chunks.
Request body:
{ "interval": "daily" }interval must be one of: daily, weekly, monthly.
Response example:
{ "done": false, "stored": 5000, "oldestDate": "2012-03-14" }When no more historical candles are returned:
{ "done": true, "stored": 0, "oldestDate": "1969-12-31" }Set scheduler timezone to Asia/Kuala_Lumpur.
Cron format:
minute hour day-of-month month day-of-week
| Frequency | Cron (MYT) | Endpoint |
|---|---|---|
| Realtime market session (Mon 06:00-Mon 23:59) | */2 6-23 * * 1 |
POST /api/internal/gold/fetch |
| Realtime market session (Tue-Fri full day) | */2 * * * 2-5 |
POST /api/internal/gold/fetch |
| Realtime market session (Sat 00:00-Sat 05:59) | */2 0-5 * * 6 |
POST /api/internal/gold/fetch |
| Daily history (Tue-Sat 07:10) | 10 7 * * 2-6 |
POST /api/internal/gold/fetch-daily |
| Weekly history (Monday 08:15) | 15 8 * * 1 |
POST /api/internal/gold/fetch-weekly |
| Monthly history (day 1, 08:20) | 20 8 1 * * |
POST /api/internal/gold/fetch-monthly |
Run each backfill endpoint repeatedly until done: true:
- Daily interval: likely multiple calls for deep history
- Weekly interval: usually one call is enough
- Monthly interval: usually one call is enough
src/
index.ts
app.ts
config/
index.ts
db/
firestore.ts
middleware/
privateAuth.ts
routes/
index.ts
gold.routes.ts
internal/
index.ts
gold.routes.ts
services/
gold.service.ts
gold.history.service.ts
types/
gold.types.ts
- Node.js
- TypeScript
- Express
- Axios
- Firebase Admin SDK (Firestore)
- dotenv