# Minute chart APIs (TradingView)

Use these endpoints for the advanced chart (price + volume).

- `GET /api/mkt-day-end-data/minute-price-series`
- `GET /api/mkt-day-end-data/minute-volume-series`

`NFML` below is only an example. Replace with the selected `security_code`.

---

## Two modes (do not mix them on first load)

| Mode | Query | When to use | Live data? |
|------|--------|-------------|------------|
| **Rolling (default)** | `?security_code=NFML` | First chart load + live refresh | **Yes** during market hours (10:00–14:30 Asia/Dhaka) |
| **History** | `?security_code=NFML&start=YYYY-MM-DD&end=YYYY-MM-DD` | User scrolls left for older bars | **No** |

### Wrong (do not use this as the first load)

```
GET /api/mkt-day-end-data/minute-price-series?security_code=NFML&start=2026-08-06&end=2026-08-11
```

`start` + `end` forces **history mode**. The backend will **not** append today’s live minute bars.

### Correct first load

```
GET /api/mkt-day-end-data/minute-price-series?security_code=NFML
GET /api/mkt-day-end-data/minute-volume-series?security_code=NFML
```

This returns the last **7 days** from cache/DB and, while the market is open, merges new `mkistat` minute bars plus a live tip.

---

## TradingView `getBars` contract

```text
1. firstDataRequest === true
   → call WITHOUT start/end
   → paint last ~7 days + live (if session open)

2. User scrolls left (firstDataRequest === false)
   → call WITH start & end
   → end must be BEFORE the earliest bar already on the chart
   → do not send “today” again

3. No more data
   → empty data / meta.no_data === true
   → onHistoryCallback([], { noData: true })
```

### Example

```js
async function getBars(symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) {
  const { from, to, firstDataRequest } = periodParams;
  const code = encodeURIComponent(symbolInfo.ticker);

  const qs = firstDataRequest
    ? `security_code=${code}`
    : `security_code=${code}&start=${formatDate(from)}&end=${formatDate(to)}`;

  const res = await fetch(`/api/mkt-day-end-data/minute-price-series?${qs}`);
  const json = await res.json();
  const rows = json.data || [];

  if (!rows.length || json.meta?.no_data) {
    onHistoryCallback([], { noData: true });
    return;
  }

  onHistoryCallback(rows.map(toTvBar), { noData: false });
}
```

Do the same for volume (`minute-volume-series`).

`formatDate` can be `YYYY-MM-DD` (time optional). Date-only `end` includes that whole calendar day.

---

## History page rules

- `start` and `end` are both required for history.
- Inclusive range. Max span: **7 days**. Larger range returns **422**.
- Time is optional:

```
?security_code=NFML&start=2026-07-20&end=2026-07-25
?security_code=NFML&start=2026-07-20 10:00:00&end=2026-07-25 14:30:00
```

- History must **not** overlap the already-loaded 7-day window. Example: if rolling data starts `2026-08-04 12:00`, the next history `end` should be before that.

---

## Live updates during market hours

- Session: **10:00–14:30 Asia/Dhaka**.
- Poll or `subscribeBars` using the **rolling URL only** (no `start`/`end`).
- Do **not** poll the history URL for live ticks.
- New bars come from `mkistat` (written when today’s market data is ingested). The rolling endpoint merges them and may append one snapshot tip for the current minute.

Suggested poll: every 15–30s while the first-load series is on screen and the session is open. Prefer updating/appending the **last bar(s)** instead of refetching a dated history range.

---

## Response shapes

### Price

```json
{
  "success": true,
  "data": [
    {
      "time": "2026-08-11 12:32:00",
      "open": "10.00",
      "high": "10.20",
      "low": "9.90",
      "close": "10.10"
    }
  ],
  "meta": { "mode": "rolling", "no_data": false }
}
```

`meta.mode` is `"rolling"` or `"history"`.

### Volume

```json
{
  "success": true,
  "data": [
    { "time": "2026-08-11 12:32:00", "value": "12345.0" }
  ],
  "meta": { "mode": "rolling", "no_data": false }
}
```

`time` is a wall-clock string `YYYY-MM-DD HH:mm:ss` (as stored in `mkistat`). Convert to TradingView unix seconds in **Asia/Dhaka**.

---

## Checklist

- [ ] Initial chart: **no** `start`/`end`
- [ ] Scroll left: `start` + `end`, older than loaded data, ≤ 7 days
- [ ] Live poll: same as initial (no range)
- [ ] Empty page → `{ noData: true }`
- [ ] Price and volume use the same `from`/`to` / first-load rules
