# Single File Data Dashboard

> Build and maintain single-file HTML dashboards that fetch live data from public APIs and render interactive charts (ECharts, Canvas). Covers CORS workarounds, dual-API fallback patterns, Chinese stock market data sources, and real-time polling architectures.

- Skill: `geraltvitas/single-file-data-dashboard` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add geraltvitas/single-file-data-dashboard`
- Raw SKILL.md: https://api.skillmd.com/api/skills/geraltvitas/single-file-data-dashboard/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: GeraltVitas (https://skillmd.com/u/geraltvitas)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/geraltvitas/single-file-data-dashboard

---


# Single-File Data Dashboard

## Core Pattern

Single `index.html` with embedded ECharts (CDN), fetch-based data layer, and
client-side computation. No server, no build step, no API keys (use public APIs).

## Pitfalls

### 1. CORS: file:// blocks API fetches
When opening `file:///path/dashboard.html`, the browser origin is `null`.
Most public APIs reject `null` origin even if they otherwise support CORS.

✅ **Always serve via local HTTP server:**
```bash
cd /path/to/project && python -m http.server 8760
# Then open http://localhost:8760/dashboard.html
```

This is mandatory — never tell the user to double-click the HTML file.

### 2. Eastmoney API doesn't support ETFs
The standard stock K-line endpoint (`push2his.eastmoney.com/api/qt/stock/kline/get`)
returns empty data for ETFs (codes starting with 5 on Shanghai, 1 on Shenzhen).

✅ **Use Tencent API as fallback for ETFs and all stocks:**

| Priority | Source | Coverage |
|---|---|---|
| 1 (primary) | Eastmoney `push2his.eastmoney.com` | Regular A-shares (6/0/3/2xxxxx) |
| 2 (fallback) | Tencent `web.ifzq.gtimg.cn` | ETFs, all A-shares |

### 3. Tencent API is JSONP-wrapped
The Tencent minute/quote endpoint returns JSONP:
```
min_data=({...actual JSON...});
```

✅ **Strip the wrapper before JSON.parse:**
```js
const text = await (await fetch(url)).text();
const jsonStr = text.replace(/^min_data=/, '').replace(/;$/, '');
const data = JSON.parse(jsonStr);
```

### 4. Tencent qt array index conventions
The real-time quote is a flat array with positional fields:
```js
const qt = data.data[txKey].qt[txKey];
// qt[1] = name (Chinese)
// qt[3] = current price
// qt[4] = prev close
// qt[5] = open
// qt[6] = volume (today, shares)
// qt[33] = today high
// qt[34] = today low
// qt[37] = amount (today, yuan)
```

### 5. Tencent K-line format differs from Eastmoney
Eastmoney K-line: CSV string `"date,open,close,high,low,volume,amount"`
Tencent K-line: array `[date, open, close, high, low, volume]`
Note: Tencent does NOT include amount (成交额), set to 0.

### 6. Dual-API fallback pattern
Structure each fetch function to try primary first, fall through silently:
```js
async function fetchX(code, market, prefix) {
  // Try Eastmoney
  try {
    const data = await fetchEM(url);
    if (data?.data?.klines?.length > 0) { dataSource = 'em'; return parse(data); }
  } catch(e) { /* fall through */ }
  // Fallback
  addLog('切换到腾讯数据源...', 'info');
  dataSource = 'tx';
  return fetchTX(code, prefix);
}
```

Log the switch so the user knows which source is active.

## Chinese Stock Data APIs

### Eastmoney (primary — regular stocks)
- **Real-time quote**: `https://push2.eastmoney.com/api/qt/stock/get?secid={market}.{code}&fields=f43,f57,f58,f169,f170,...`
  - `market`: 1=SH, 0=SZ
  - `f43`: price×100, `f58`: name, `f169`: change×100, `f170`: changePct×100
- **Daily K-line**: `https://push2his.eastmoney.com/api/qt/stock/kline/get?secid={market}.{code}&klt=101&fqt=1&lmt=400&fields2=f51,f52,f53,f54,f55,f56,f57`
  - `klt=101`: daily, `fqt=1`: forward-adjusted
  - Response: `data.klines` — array of CSV strings: `date,open,close,high,low,volume,amount`
- **Minute intraday**: `https://push2his.eastmoney.com/api/qt/stock/trends2/get?secid={market}.{code}&ndays=1&fields2=f51,f52,f53,f54,f55,f56,f57,f58`
  - `data.prevClose`: yesterday close, `data.trends`: array of CSV strings
  - Minute CSV: `time,prevClose?,price,avgPrice?,?,volume,?,avgPrice`

### Tencent (fallback — ETFs and all stocks)
- **Daily K-line**: `https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={prefix}{code},day,,,{count},qfq`
  - `prefix`: `sh` or `sz`, `qfq`: forward-adjusted
  - Response: `data.{prefix}{code}.qfqday` — array of `[date, open, close, high, low, volume]`
- **Minute + Quote (combined)**: `https://web.ifzq.gtimg.cn/appstock/app/minute/query?_var=min_data&code={prefix}{code}`
  - JSONP wrapper: `min_data=(...)`
  - Minute data: `data.{key}.data.data` — array of `"HHMM price volume amount"`
  - Real-time quote: `data.{key}.qt.{key}` — positional array

### Market detection
```js
function detectMarket(code) {
  if (code.startsWith('6')) return [1, '1.'+code, 'sh'];       // Shanghai stock
  if (code.startsWith('5')) return [1, '1.'+code, 'sh'];       // Shanghai ETF
  if (code.startsWith('0')||code.startsWith('3')||code.startsWith('2')||code.startsWith('1'))
    return [0, '0.'+code, 'sz'];                                // Shenzhen
  return [0, '0.'+code, 'sz'];
}
// Returns: [eastmoneyMarket, eastmoneySecid, tencentPrefix]
```

## ECharts Integration

Load from CDN in `<head>`:
```html
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
```

Always call `.dispose()` before `.init()` to prevent memory leaks on re-render:
```js
function getOrCreateChart(domId) {
  if (chartInstances[domId]) { chartInstances[domId].dispose(); }
  return echarts.init(document.getElementById(domId), 'dark');
}
```

Register `window.addEventListener('resize', ...)` to call `.resize()` on all instances.

## Verification

For single-file HTML dashboards, check:
1. The page loads without JS errors (open browser console)
2. CORS is handled — verify via `http://localhost:8760/`, not `file://`
3. Try both a regular stock (600519) and an ETF (515880) to test fallback
4. Charts render with actual data points (not empty axes)

## References

- `references/chinese-stock-apis.md` — exact API response formats with field indices for Eastmoney and Tencent endpoints

