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)
JavaScript 53.7%
Python 38.3%
CSS 4.6%
TypeScript 3.1%
1/**2 * MCP resources: `hfmarketdata://status` (dataset inventory) and `hfmarketdata://limits`3 * (the three access levels — all free — + the caller's current headroom when the server exposes /v1/limits).4 */5import { HfmdClient, HfmdError } from './client.js';67/** The platform is entirely free; these are rate limits, not a price list. */8export const LIMITS = [9 { access: 'keyless (per IP, low hourly limits)', window: '1 hour', requests: 30, rows: 100_000, max_rows_per_request: 5_000 },10 { access: 'free API key (free account)', window: '1 minute', requests: 120, rows: 1_000_000, max_rows_per_request: 50_000 },11 { access: 'higher limits (granted on request by e-mail to contact@spboucher.ai, also free)', window: '1 minute', requests: 600, rows: 10_000_000, max_rows_per_request: 200_000 },12];1314export interface ResourceDef {15 name: string;16 uri: string;17 title: string;18 description: string;19 mimeType: string;20 read: (client: HfmdClient) => Promise<string>;21}2223export const statusResource: ResourceDef = {24 name: 'status',25 uri: 'hfmarketdata://status',26 title: 'HF Market Data — dataset status',27 description: 'Live inventory of the data lake: number of symbols per asset class / timeframe / adjustment, futures roots, options quarters, last update.',28 mimeType: 'application/json',29 async read(client) {30 const r = await client.get('/v1/status');31 return JSON.stringify({ base_url: client.baseUrl, fetched_ms: r.ms, ...(r.body as Record<string, unknown>) }, null, 1);32 },33};3435export const limitsResource: ResourceDef = {36 name: 'limits',37 uri: 'hfmarketdata://limits',38 title: 'HF Market Data — rate limits',39 description: 'The platform is free. Three access levels (keyless / free API key / higher limits on request) with their request and row quotas, whether this server runs with an API key, and the live headroom when /v1/limits is available.',40 mimeType: 'application/json',41 async read(client) {42 const out: Record<string, unknown> = {43 mode: client.keyless ? 'keyless (low hourly limits — set HFMD_API_KEY, a free API key gives 120 req/min)' : 'api key configured',44 everything_is_free: true,45 limits: LIMITS,46 notes: [47 'Parquet responses count half the rows against the quota; bulk downloads are quota-exempt; 304 responses do not count.',48 'Every response carries X-RateLimit-Limit-Requests / -Remaining-Requests / -Limit-Rows / -Remaining-Rows / -Reset; 429 adds Retry-After.',49 'Create a free account at https://www.hfmarketdata.io/signup — keys look like hfmd_live_…. Higher limits: e-mail contact@spboucher.ai (also free). Details: https://www.hfmarketdata.io/limits',50 ],51 };52 try {53 const r = await client.get('/v1/limits');54 out.live = r.body;55 out.rate_headers = r.rate;56 } catch (e) {57 out.live = e instanceof HfmdError ? `unavailable (${e.status} ${e.code})` : 'unavailable';58 }59 return JSON.stringify(out, null, 1);60 },61};6263export const RESOURCES: ResourceDef[] = [statusResource, limitsResource];64