SPB Git forge

spb/hfmarketdata

Public

Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)

127commits 1branches 0releases
24.7 MBsize
maindefault branch
11 days agolast push
JavaScript 53.7% Python 38.3% CSS 4.6% TypeScript 3.1%

web: pas de tarification — page Limits (/limits, /pricing redirige), libellés « free, higher limits on request », x-pricing OpenAPI

Simon-Pierre Boucher committed 20 days ago (Sep 4, 2026) parent c27e5c5

7 changed files +13 −8

modified .gitignore +3 −0
@@ -29,3 +29,6 @@ hfmarketdata/venv/
29 29 .venv/
30 30 .pytest_cache/
31 31 .ruff_cache/
32 +
33 +# worktrees des agents / état local Claude
34 +.claude/
modified docs/UPGRADE-PLAN.md +1 −1
@@ -149,7 +149,7 @@ Getting started Guides Reference (OpenAPI)
149 149 └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
150 150 ```
151 151
152 −### 4.3 Pricing / Limits (`/pricing`)
152 +### 4.3 Access & limits (`/limits`) — tout est gratuit
153 153 Tableau 3 colonnes (Keyless · Free account · High usage) avec les 6 chiffres, CTA « Create free account » et « Request high usage → contact@spboucher.ai », encart « incitations » (Parquet = ½ coût, bulk hors quota, ETag/304 gratuits).
154 154
155 155 ### 4.4 Homepage
modified hfmarketdata/api/openapi.py +1 −0
@@ -97,6 +97,7 @@ def build(app: FastAPI) -> dict:
97 97 responses["422"]["description"] = "`VALIDATION_ERROR` — " + CODES["VALIDATION_ERROR"]
98 98 responses["422"]["content"] = {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
99 99 schema["info"]["x-logo"] = {"url": settings.public_url + "/logo.svg"}
100 + schema["info"]["x-pricing"] = {"free": True, "note": "HF Market Data is free. Higher limits are granted on request (free) — e-mail %s." % settings.contact_email}
100 101 schema["info"]["x-tiers"] = {
101 102 "keyless": {"window": "1h", "requests": 30, "rows": 100_000, "max_rows_per_request": 5_000},
102 103 "free": {"window": "1m", "requests": 120, "rows": 1_000_000, "max_rows_per_request": 50_000},
modified hfmarketdata/web/src/App.jsx +4 −3
@@ -1,14 +1,14 @@
1 1 // Route table — one lazy chunk per area. Owners: web-core (home, pricing, docs, status, layout),
2 2 // web-app (playground, auth, dashboard, admin), mcp-skills (integrations).
3 3 import React, { Suspense, lazy } from 'react'
4 −import { Route, Routes } from 'react-router-dom'
4 +import { Navigate, Route, Routes } from 'react-router-dom'
5 5 import Layout from './app/Layout.jsx'
6 6
7 7 const Home = lazy(() => import('./pages/home/Home.jsx'))
8 8 const Docs = lazy(() => import('./pages/docs/Docs.jsx'))
9 9 const Playground = lazy(() => import('./pages/playground/Playground.jsx'))
10 10 const Integrations = lazy(() => import('./pages/integrations/Integrations.jsx'))
11 −const Pricing = lazy(() => import('./pages/pricing/Pricing.jsx'))
11 +const Limits = lazy(() => import('./pages/limits/Limits.jsx'))
12 12 const Status = lazy(() => import('./pages/status/Status.jsx'))
13 13 const Auth = lazy(() => import('./pages/auth/Auth.jsx'))
14 14 const Dashboard = lazy(() => import('./pages/dashboard/Dashboard.jsx'))
@@ -24,7 +24,8 @@ export default function App() {
24 24 <Route path="/docs/*" element={<Docs />} />
25 25 <Route path="/playground" element={<Playground />} />
26 26 <Route path="/integrations/*" element={<Integrations />} />
27 − <Route path="/pricing" element={<Pricing />} />
27 + <Route path="/limits" element={<Limits />} />
28 + <Route path="/pricing" element={<Navigate to="/limits" replace />} />
28 29 <Route path="/status" element={<Status />} />
29 30 <Route path="/signin" element={<Auth mode="signin" />} />
30 31 <Route path="/signup" element={<Auth mode="signup" />} />
modified hfmarketdata/web/src/app/Layout.jsx +1 −1
@@ -5,7 +5,7 @@ import { CONTACT_EMAIL } from './api.js'
5 5
6 6 const NAV = [
7 7 ['/docs', 'Docs'], ['/playground', 'Playground'], ['/integrations', 'Integrations'],
8 − ['/pricing', 'Pricing / Limits'], ['/status', 'Status'],
8 + ['/limits', 'Limits'], ['/status', 'Status'],
9 9 ]
10 10
11 11 export default function Layout({ children }) {
modified hfmarketdata/web/src/app/api.js +1 −1
@@ -7,7 +7,7 @@ export const CONTACT_EMAIL = 'contact@spboucher.ai'
7 7 export const TIERS = [
8 8 { id: 'keyless', name: 'Keyless (per IP)', window: 'hour', requests: 30, rows: 100_000, maxRows: 5_000 },
9 9 { id: 'free', name: 'Free account + API key', window: 'minute', requests: 120, rows: 1_000_000, maxRows: 50_000 },
10 − { id: 'high_usage', name: 'High usage (on request)', window: 'minute', requests: 600, rows: 10_000_000, maxRows: 200_000 },
10 + { id: 'high_usage', name: 'Higher limits (free, on request)', window: 'minute', requests: 600, rows: 10_000_000, maxRows: 200_000 },
11 11 ]
12 12
13 13 export function rateHeaders(res) {
renamed hfmarketdata/web/src/pages/pricing/Pricing.jsx → hfmarketdata/web/src/pages/limits/Limits.jsx +2 −2
@@ -1,5 +1,5 @@
1 1 import React from 'react'
2 2 // Placeholder — implemented by the owning agent (see App.jsx header). Keep the default export name.
3 −export default function Pricing() {
4 − return <main className="page"><h1>Pricing</h1><p className="muted">Coming soon.</p></main>
3 +export default function Limits() {
4 + return <main className="page"><h1>Limits</h1><p className="muted">Coming soon.</p></main>
5 5 }
6 6