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%
5.8 KB

# hfmarketdata — conventions de travail (lues par tous les agents)

Plateforme : www.hfmarketdata.io — API FastAPI + DuckDB sur un lac Parquet (350 Go, FirstRate Data), site React/Vite servi par l'API. Plan complet : docs/UPGRADE-PLAN.md (lire en premier). Prod (depuis le 2026-09-14) : serveur OVH BHS128 (ssh BHS128, ubuntu@51.161.112.69, Ubuntu 24.04, 12 threads / 128 Go) — ~/hfmarketdata (venv Python 3.14 via uv, versions épinglées dans requirements-prod-freeze.txt), lac ~/firstratedata (359 Go Parquet + state/hfmd.db + edgar/), Redis natif, PM2 sous systemd (pm2-ubuntu) avec ~/apps/pm2.hfmarketdata.config.cjs généré depuis le manifeste mld par ~/apps/.manifests/gen-pm2.py : hfmarketdata-api (uvicorn :8090, 2 workers), edgar-incremental, crons frd-refresh (lun 03:00), contracts-backfill (04:30), edgar-reconcile (dim 06:00) ; edgar-backfill et rowgroups à la main (pm2 start … --only). Route publique : BHS64 Caddy → wg1 10.67.0.60:8090 (mlt add www.hfmarketdata.io BHS128:8090), ufw ouvert sur wg1 depuis 10.67.0.1. Hors mld (retirée du registre ; l'ancienne copie M3U96b ~/hfmarketdata + ~/firstratedata + Redis a été effacée le 2026-09-14 — BHS128 détient la seule copie du lac et de state/hfmd.db : prévoir une sauvegarde hors serveur ; manifeste mld sauvegardé sur le laptop ~/Desktop/Cluster/secrets/mld-manifests-retired-20260914/hfmarketdata.json). Release : rsync -a --exclude venv --exclude .git --exclude 'hfmarketdata/web/node_modules' --exclude 'hfmarketdata/web/dist' --exclude mcp/node_modules . BHS128:hfmarketdata/ puis ssh BHS128 'cd hfmarketdata && ~/.local/bin/uv pip install --python venv/bin/python -r hfmarketdata/requirements.txt && (cd hfmarketdata/web && npm ci && npm run build) && pm2 restart hfmarketdata-api hfmarketdata-edgar-incremental && pm2 save'. Dépôt de vérité : spbgit gitsrv:srv/git/hfmarketdata.git (branche main).

# Règles absolues

  • Aucun breaking change : les endpoints /v1/* existants (main.py) gardent paths, paramètres, formes de réponse ({"count","data"}) et codes. Tout le neuf est additif sous /v1/.
  • Erreurs : lever core.errors.ApiError(status, CODE, message, type=…, details=…) ; les codes vivent dans core/errors.py::CODES (en ajouter si besoin, jamais de code inconnu). Jamais de HTTPException dans le code v2.
  • Réponses v2 : core.responses.frame_response(df, fmt, meta=…, request=…) pour les tableaux (json/csv/parquet, enveloppe {"data","meta"}, X-Row-Count), json_response(...) pour le reste, clamp_limit(...) pour limit, curseurs via encode_cursor/decode_cursor. Timestamps UTC ISO 8601.
  • Données : DuckDB via core.duck.con() (connexion par thread) + core.duck.cached(key, builder) pour les scans de répertoires. settings.parquet = racine du lac. Jamais de valeur inventée : absence → null + raison dans coverage.
  • Métadonnées : SQLite via core.db (Base, session(), get_session dépendance FastAPI, create_all() idempotent au démarrage du module). Un module = un fichier models.py.
  • Config : uniquement core.config.settings (variables HFMD_*). Secrets jamais en dur, jamais dans les exemples publics.
  • Structure : hfmarketdata/api/<module>/{routes.py,models.py,service.py,…} ; routes.py expose router (APIRouter avec prefix="/v1/…", tags=[…]) OU install(app) (middleware). main.py charge les modules listés dans V2_MODULES — ne pas éditer main.py au-delà de cette liste. Imports absolus depuis hfmarketdata/api (ex. from core.errors import ApiError).
  • Quota lignes : toujours poser X-Row-Count (fait par frame_response). Endpoints coûteux : request.state.request_cost = 2 (screener, frames). Bulk : request.state.quota_exempt = True.
  • Style : Python 3.12+ typé, docstrings en anglais (le produit est en anglais), commentaires courts. Frontend : React 18 + Vite, dark par défaut, pas de framework CSS lourd (CSS modules / variables), composants dans hfmarketdata/web/src.
  • Tests : pytest dans tests/ (pytest.ini met hfmarketdata/api sur le path) ; lac synthétique tests/fixtures/make_fixtures.py (l'étendre si un module a besoin d'autres fichiers) ; Redis = fakeredis quand HFMD_REDIS_URL=fakeredis://. Chaque module livre ses tests unitaires + intégration (TestClient). ./.venv/bin/python -m pytest doit rester vert.
  • OpenAPI 3.1 : chaque route a summary, description (markdown), response_model ou responses={…} avec exemples réels, et déclare ses erreurs possibles via openapi_extra={"x-errors": ["CONTRACT_NOT_FOUND", …]}. La doc du site est générée depuis /openapi.json : la qualité des descriptions EST la doc.
  • Git : commits atomiques en français, préfixe du chantier (futures:, accounts:, ratelimit:, fundamentals:, web:, mcp:, docs:). Ne pas committer .venv, node_modules, dist, données.

# Données réelles (référence, pas pour les tests)

Layout : parquet/{stock|etf|crypto|index|fx}/{1min|5min|30min|1hour|1day}/{adj}/{TICKER}_{tf}.parquet · parquet/futures/{tf}/{contin_UNadj|contin_adj_ratio|contin_adj_absolute}/{ROOT}_{tf}.parquet · parquet/futures_contracts/{tf}/{archive|update}/{ROOT}_{MonthCode}{YY}_{tf}.parquet (142 racines, ~15 000 contrats/tf, la colonne ticker = racine ; archive ≤ 2025, update ≥ 2025 avec chevauchement → dédupliquer sur datetime, priorité update) · parquet/options/{yyyy}_{qN}/{TICKER}_month_option_chain.parquet · meta/futures/futures.csv (Ticker, Name, First Date, Last Date). Colonnes barres : ticker, datetime (TIMESTAMP naïf, heure US/Eastern pour l'intraday), open, high, low, close, volume, open_interest (futures 1day). API publique pour vérifier : https://www.hfmarketdata.io/v1/status. Accès au nœud si indispensable : ssh M3U96b (lecture seule sur ~/firstratedata).