# ADR 0011 — Providers de prix : exchanges directs (crypto) + Yahoo Finance best-effort (stocks) - Status: Accepted - Date: 2026-04-26 - Successor of: ADR 0009 (architecture proxy) — précise les providers concrets - Milestone: `spec-price-fetching` + `prices-proxy` (maximus-api) ## Context ADR 0009 a établi qu'un proxy `maximus-api` mutualisé sert le price-fetching premium pour préserver la privacy (IP cachée, headers strippés). La revue spec du contrat `/v1/prices` (2026-04-26) a soulevé deux risques critiques : 1. **Yahoo Finance n'a pas d'API publique officielle.** Les endpoints `query1/query2.finance.yahoo.com` sont non documentés, leur ToS interdit l'usage commercial et la redistribution. Un IP-ban du VPS coupe le feature pour 100% des premium en même temps. 2. **CoinGecko free tier interdit le proxy commercial.** Seul le plan Demo/Pro payant (~129 $/mo Analyst) le permet contractuellement. Quatre options ont été considérées (cf. revue inline `docs/api-contract-prices.md` §0) : | Option | Coût/mois | Légalité commercial | Stabilité | Couverture | |--------|-----------|---------------------|-----------|------------| | Polygon.io Starter | 29 $ | ✅ contractuelle | ✅ haute | Stocks NYSE/NASDAQ + crypto | | Tiingo Power + exchanges directs (crypto) | 10 $ | ✅ Tiingo, ✅ exchanges (public market data OSS-légal) | ✅ haute | Stocks + crypto | | **Exchanges directs (crypto) + Yahoo best-effort (stocks)** | **0 $** | ⚠️ Yahoo ToS risqué (data publique mais redistribution interdite) ; ✅ exchanges | ⚠️ Yahoo fragile, exchanges stables | Stocks + crypto | | Polygon Stocks + CoinGecko Pro | 158 $ | ✅ | ✅ | Best-of-both | ## Decision **Adopter l'option « tout-OSS / best-effort »** pour le MVP : - **Crypto** : interrogation directe des exchanges majeurs via la lib `ccxt` (MIT). Les données de marché publiques (ticker, OHLC) sont gratuites et explicitement autorisées en commercial par les ToS de Kraken, Coinbase, Binance, etc. Implémentation initiale : Kraken d'abord, Coinbase en fallback si Kraken 404. - **Stocks** : interrogation de Yahoo Finance via `query1.finance.yahoo.com/v7/finance/quote` (et v8 chart pour historique) avec un User-Agent navigateur. **Best-effort assumé** : peut échouer ou changer sans préavis. Le client paie pour **l'infrastructure d'anonymisation**, pas pour la donnée. Cette distinction est centrale au modèle économique : la valeur premium = privacy (proxy mutualisé) + commodité (auto-fill), pas la donnée elle-même. ### Garde-fous obligatoires 1. **Label UX explicite** : sur les catégories de bilan en stocks, le bouton fetch affiche un badge « best-effort » + warning au premier usage. Sur crypto : pas de warning. 2. **Circuit breaker côté maximus-api** : seuil `5 erreurs Yahoo / 60 sec → breaker ouvert pour 15 min`. Notification automatique Telegram/email à `maxime2tremblay@protonmail.com`. 3. **Quota baissé** : 200 req/jour/licence (vs 2000 initialement). Suffit pour ~50 actifs × snapshot mensuel. Réduit l'incitation à abuser. 4. **Saisie manuelle toujours active** : aucun chemin d'erreur ne bloque la saisie d'un snapshot. 5. **Headers stripping rigoureux** : tous les headers entrants supprimés avant call sortant. Vers Yahoo : UA browser-like (`Mozilla/5.0 ...`). Vers exchanges : UA `maximus-api/`. 6. **Logs séparés** : pas de log conjoint `(license_id, symbol)`. Implémentation via wrapper logger injectable (`src/logger.ts` pino). ### Plan de migration si Yahoo devient inutilisable Triggers de migration vers un provider payant : - Plus de 1 incident IP-ban / mois pendant 2 mois consécutifs, OU - Plus de 30% des requêtes stocks tombent en circuit-breaker `service_degraded` sur 7 jours, OU - Plainte légale formelle de Yahoo / Verizon Media. Provider de bascule prioritaire : **Tiingo plan Power** (~10 $/mo, 1000 req/jour, ToS-clean). - Implémentation : ajouter un module `providers/tiingo.ts` parallèle à `providers/yahoo.ts`. Switch via env var `STOCKS_PROVIDER=yahoo|tiingo`. - Délai de bascule : ≤ 30 jours après déclenchement d'un trigger. - Communication : entrée CHANGELOG explicite + email aux licences premium actives. Si l'audience grandit (>500 licences premium actives), bascule vers Polygon Starter (~29 $/mo) considérée. ## Consequences ### Positives - **0 $ de coût récurrent au MVP** — pas de cash burn avant que le produit ait validé son marché. - **Crypto 100% OSS-légal** — voie pérenne, ne nécessitera jamais de migration. - **Justification premium cohérente** — privacy comme valeur, pas la donnée. Aligne avec les principes du projet. - **Plan de bascule pré-engagé** — pas pris au dépourvu si Yahoo devient hostile. ### Négatives / Risques actés - **ToS Yahoo en zone grise** — le proxy commercial de leur data publique n'est pas formellement autorisé. Yahoo a déjà émis des cease-and-desist contre yfinance (lib Python). Risque légal théorique mais peu probable à petite échelle. - **IP-ban probable à un moment ou l'autre** — Yahoo bloque les UA non browser et les patterns de requête trop réguliers. Le circuit breaker absorbe l'événement, mais le feature devient temporairement HS pour tous les premium. - **Pas de garantie de stabilité de schéma** — Yahoo peut renommer un champ JSON sans préavis. Tests d'intégration `nock` ne capturent pas ça (mock = donnée figée). - **Charge ops accrue** — il faudra surveiller le taux d'erreur Yahoo et réagir vite si dégradation. ### Neutre - Première implémentation un peu plus complexe côté serveur (deux providers + circuit breaker), mais le code reste contained dans `src/providers/` et est testable. ## Suivi - ADR à reviewer dans 6 mois (2026-10-26) ou plus tôt si trigger de migration déclenché. - Métriques à tracker dans le log applicatif maximus-api : `yahoo_success_rate_7d`, `yahoo_breaker_open_count_30d`, `crypto_provider_distribution`. - Issue de suivi : créer une issue `ops` dans `maximus-api` pour le monitoring continu une fois deployé. ## References - [Yahoo Finance ToS](https://legal.yahoo.com/us/en/yahoo/terms/index.html) — sec. 7-8 sur l'usage commercial - [CoinGecko API ToS](https://www.coingecko.com/en/api/terms) — restrictions free tier - [Kraken API public market data](https://docs.kraken.com/rest/) — explicite : free public tier, commercial OK pour data publique - [CCXT (MIT)](https://github.com/ccxt/ccxt) — abstraction multi-exchange, lib OSS - ADR 0009 — Architecture du proxy - `docs/api-contract-prices.md` — Contrat figé `/v1/prices`