Pre-rendered historical Binance Spot klines for the top 10 USDT pairs, served as plain static JSON on GitHub Pages.
Goal: offer a static, easily accessible, fast API and matching client libraries (TypeScript, Python) for historical Binance Spot klines. Built as a zero-setup dataset for AI model training, backtesting, and other crypto data experiments where you just want candles in a fetch call without signing up, paying, or managing rate limits.
Every (interval, symbol, window) tuple is pre-rendered at build time into a plain JSON file on GitHub Pages. No rate limits, no server-side compute, infinitely cacheable, globally CDN'd. The repo is the dataset.
Under the hood it's a Vovk.ts back-end deployed as a static segment — controllers are materialized into JSON files at build time, so the whole API ships as plain static assets with no runtime.
⚠️ Experimental — not audit-grade data. This is a community cache of Binance's public REST API, refreshed once a day. Binance occasionally restates historical candles; a daily cache can't reflect that. Don't use it for trading or compliance — fine for ML datasets, charts, backtests, and exploratory analysis.
- 📖 Full API documentation (interactive, Scalar): https://finom.github.io/static-klines/ — every endpoint with schemas, parameter enums, and copy-paste code samples in TS / Python / curl.
- 🤖 OpenAPI 3.1 spec (machine-readable): https://finom.github.io/static-klines/api/openapi.json — feed this to any OpenAPI-compatible client generator.
- 📦 TypeScript package docs: https://www.npmjs.com/package/static-klines
- 🐍 Python package docs: https://pypi.org/project/static-klines/
- https://finom.github.io/static-klines/api/klines/symbols.json — list of supported trading pairs
- https://finom.github.io/static-klines/api/klines/start-dates/1d.json — every valid
startDatefor the 1d interval - https://finom.github.io/static-klines/api/klines/1d/BTCUSDT/2018-01-01.json — 2 years of BTCUSDT daily candles starting Jan 1, 2018
- https://finom.github.io/static-klines/api/klines/1h/ETHUSDT/2024-01-01.json — January 2024 hourly candles for ETHUSDT
- https://finom.github.io/static-klines/api/klines/15m/SOLUSDT/2025-01-06.json — first full week of 2025, 15-minute SOLUSDT candles
BTCUSDT, ETHUSDT, BNBUSDT, SOLUSDT, XRPUSDT, ADAUSDT, DOGEUSDT, AVAXUSDT, LINKUSDT, DOTUSDT.
Every startDate is a real, predictable calendar boundary — you can guess the next URL in sequence without looking it up. Windows are sized to fit within Binance's 1000-candles-per-request cap.
| Interval | Window | Anchor (first window) | ≤ candles/file |
|---|---|---|---|
15m |
1 ISO week (Mon) | 2024-12-30 | 672 |
30m |
2 ISO weeks (Mon) | 2024-01-01 | 672 |
1h |
1 month (1st) | 2022-01-01 | 744 |
2h |
2 months (1st) | 2017-07-01 | 732 |
4h |
1 quarter (Jan/Apr/Jul/Oct) | 2017-07-01 | 546 |
6h |
6 months (Jan/Jul) | 2017-07-01 | 732 |
8h |
6 months (Jan/Jul) | 2017-07-01 | 546 |
12h |
1 year (Jan 1) | 2017-01-01 | 732 |
1d |
2 years (Jan 1, even years) | 2016-01-01 | 732 |
3d |
5 years (Jan 1) | 2015-01-01 | 609 |
1w |
10 years (Jan 1) | 2010-01-01 | 522 |
1M |
20 years (Jan 1) | 2010-01-01 | 240 |
Pairs that listed later than the interval's anchor return empty [] for leading windows; iterate forward. Future windows (through 2040-01-01) are scaffolded empty and populated daily.
Call GET /api/klines/start-dates/{interval}.json (or KLinesAPI.getStartDates({ interval }) in any client) for the full ordered enum of valid startDates.
Or: see ENDPOINTS.md for a flat, human-browsable list of every static URL served by this site (17,784 of them, through 2040-01-01).
Auto-generated from the same Zod schemas the server uses.
📚 Full API reference: npmjs.com/package/static-klines — auto-generated, includes every endpoint with type signatures + runnable code samples.
npm install static-klinesimport { KLinesAPI } from 'static-klines';
// List supported trading pairs
const symbols = await KLinesAPI.getSymbols();
// → ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', ...]
// List valid startDates for an interval
const starts = await KLinesAPI.getStartDates({ params: { interval: '1d' } });
// → ['2016-01-01', '2018-01-01', '2020-01-01', ...]
// Fetch a window of candles (Binance's native 12-tuple shape)
const candles = await KLinesAPI.getKlines1d({
params: { symbol: 'BTCUSDT', startDate: '2018-01-01' },
});
// → [[1514764800000, "13715.65000000", "13818.55000000", ...], ...]The default apiRoot is baked into the client, so no extra wiring is needed. You can pass it explicitly if you want to be explicit:
await KLinesAPI.getKlines15m({
params: { symbol: 'SOLUSDT', startDate: '2025-01-06' },
apiRoot: 'https://finom.github.io/static-klines/api',
});📚 Full API reference: pypi.org/project/static-klines — auto-generated, includes every endpoint with type hints + runnable code samples.
pip install static-klinesfrom static_klines import KLinesAPI
symbols = KLinesAPI.get_symbols()
# ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', ...]
starts = KLinesAPI.get_start_dates(params={"interval": "1d"})
# ['2016-01-01', '2018-01-01', '2020-01-01', ...]
candles = KLinesAPI.get_klines_1_d(
params={"symbol": "BTCUSDT", "startDate": "2018-01-01"},
)
# [[1514764800000, '13715.65000000', '13818.55000000', ...], ...]
# The default api_root is already set; pass it explicitly if you want to:
candles = KLinesAPI.get_klines_15_m(
params={"symbol": "SOLUSDT", "startDate": "2025-01-06"},
api_root="https://finom.github.io/static-klines/api",
)- TypeScript —
npx vovk bundle→./dist→npm publish ./dist - Python —
npx vovk generate --from py --out ./dist_python→python -m build && twine upload
npm run patch chains the whole release: bump version → bundle both → publish to npm and PyPI → tag + push.
Or bypass the generators entirely: point any OpenAPI 3.1 tool at /api/openapi.json.
.github/workflows/fetch-daily.yml runs at 03:17 UTC daily (and on workflow_dispatch):
npm run fetch:klines— pulls new fully-closed candles. Uses a fallback chain of Binance hosts (data-api.binance.vision→api.binance.com→api1-4→data.binance.com) so US-hosted runners work despite the geo-block onapi.binance.com.- Commits
.klines-cache/if anything changed. next buildre-renders every static page from the refreshed cache.- Deploys
out/to GitHub Pages via the Pages deployment API (no push-loop).
npm run dev # Next.js + Vovk dev server
npm run fetch:klines # pull latest candles into .klines-cache
npm run fetch:klines:dry # log intended writes, no fs changes
npm run build # vovk dev --exit → next build → ./out
npm test # node --test tests/*.mts (API + TS client integration)
npm run check # Biome format + lintRequires Node 24+ (native TypeScript stripping + decorators).
This repo ships a Claude Code skill at skills/static-klines-usage/SKILL.md (also symlinked into .claude/skills/ for local auto-discovery). It teaches the agent how to call every endpoint, install the TypeScript or Python client, and resolve the calendar-aligned startDate enum — so you can say "fetch me BTCUSDT daily candles for 2018 from static-klines" and Claude will know exactly which URL to hit.
npx skills add finom/static-klines --skill static-klines-usage -g -a claude-code -yThis drops the skill into ~/.claude/skills/static-klines-usage/. The skill autoloads on any prompt mentioning Binance klines, OHLCV history, or candle-fetching from this API.
Already installed if you cloned this repo — the skill is committed at skills/static-klines-usage/ (with a symlink at .claude/skills/static-klines-usage/ so Claude Code auto-discovers it when you open the directory).
npx skills add finom/static-klines --skill static-klines-usage -a claude-code -y
# (omit -g → installs to ./.claude/skills/ in the current project)git clone https://github.com/finom/static-klines /tmp/sk
cp -r /tmp/sk/skills/static-klines-usage ~/.claude/skills/ # global
# or into your project's ./.claude/skills/Verify with ls ~/.claude/skills/ — no further setup; the next Claude Code session picks it up.
.klines-cache/and.vovk-schema/are both intentionally committed. The cache is the dataset; the schema is needed byvovk generatein CI.- The root
package.jsonisprivate: true— it isn't itself an npm package. Published client libraries live under./dist(TypeScript) and./dist_python(Python), each with its own manifest. - If you shift a start date or add an interval, wipe the corresponding cache subdirectory and re-scaffold — window alignment depends on the anchor.