docs(adr): 0013 — stocks provider evaluation, AV retained as bascule target #196
1 changed files with 83 additions and 64 deletions
|
|
@ -1,22 +1,24 @@
|
||||||
# ADR 0013 — Évaluation provider stocks : Alpha Vantage retenu (override partiel ADR 0011)
|
# ADR 0013 — Évaluation provider stocks : Alpha Vantage retenu comme cible de bascule (override partiel ADR 0011)
|
||||||
|
|
||||||
- Status: **Proposed** (pending written ToS confirmation from Alpha Vantage business support)
|
- Status: **Accepted**
|
||||||
- Date: 2026-05-07
|
- Date: 2026-05-07
|
||||||
- Successor of: ADR 0011 (override partiel — la pré-désignation Tiingo Power devient invalide)
|
- Successor of: ADR 0011 (override partiel — la pré-désignation **Tiingo Power** comme cible de bascule devient invalide ; **Alpha Vantage Premium** la remplace)
|
||||||
- Issue: [maximus-api#41](https://git.lacompagniemaximus.com/maximus/maximus-api/issues/41)
|
- Issue: [maximus-api#41](https://git.lacompagniemaximus.com/maximus/maximus-api/issues/41)
|
||||||
- Phase 1 research note: [maximus-api/docs/research/0013-stocks-providers-phase1.md](https://git.lacompagniemaximus.com/maximus/maximus-api/src/branch/issue-41-stocks-providers-research/docs/research/0013-stocks-providers-phase1.md)
|
- Phase 1 research note: [maximus-api/docs/research/0013-stocks-providers-phase1.md](https://git.lacompagniemaximus.com/maximus/maximus-api/src/branch/issue-41-stocks-providers-research/docs/research/0013-stocks-providers-phase1.md)
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
L'ADR 0011 (2026-04-26) a adopté Yahoo Finance en best-effort pour les stocks, avec un plan de bascule pré-désigné vers **Tiingo Power (~10 $/mo, 1000 req/jour)** déclenché par triggers (1+ IP-ban/mois × 2 mois consécutifs, ou 30 %+ requêtes en service_degraded sur 7 jours, ou plainte légale).
|
L'ADR 0011 (2026-04-26) a adopté Yahoo Finance en best-effort pour les stocks, **avec un plan de bascule pré-désigné vers Tiingo Power (~10 $/mo, 1000 req/jour)** déclenché par triggers (1+ IP-ban/mois × 2 mois consécutifs, ou 30 %+ requêtes en service_degraded sur 7 jours, ou plainte légale).
|
||||||
|
|
||||||
Le smoke test 2026-05-04 (issue #25) a confirmé que Yahoo bloque l'IP du VPS OVH de manière stable (`502 provider_unavailable` sur AAPL). Un trigger ADR 0011 est de fait actif. La feature stocks est non-fonctionnelle en production.
|
Le smoke test 2026-05-04 (issue #25) a confirmé que Yahoo bloque l'IP du VPS OVH de manière stable. Un trigger ADR 0011 est de fait actif. Le feature stocks est non-fonctionnel en production.
|
||||||
|
|
||||||
Avant de basculer mécaniquement vers Tiingo Power, la décision (AskUserQuestion 2026-05-05) a été d'élargir l'évaluation à 3 providers — **Alpha Vantage, Tiingo, Polygon** — pour éventuellement override la pré-désignation 0011 si un autre provider domine.
|
**Décision encadrante (le présent ADR ne la modifie pas)** : on reste dans l'esprit MVP de l'ADR 0011 — **0 $ de cash burn tant que le produit n'a pas validé son marché**. La bascule vers un provider payant est repoussée jusqu'à un trigger plus net (1ère licence payée, OU 1ère plainte client active, OU saturation des plaintes "stocks cassé"). Le scope du présent ADR est de **valider empiriquement quel provider sera la cible de bascule** quand un trigger réel se déclenchera, **pas** de déclencher la bascule maintenant.
|
||||||
|
|
||||||
## Phase 1 — Recherche documentaire (3 axes parallèles, sources publiques uniquement)
|
Avant de figer mécaniquement Tiingo Power comme dans 0011, l'évaluation a été élargie à 3 providers — Alpha Vantage, Tiingo, Polygon — pour potentiellement override la pré-désignation 0011 si un autre provider domine.
|
||||||
|
|
||||||
3 sous-agents WebSearch ont produit une synthèse 6-axes par provider (couverture, pricing, ToS, API, TSX, réputation). Synthèse complète dans `maximus-api/docs/research/0013-stocks-providers-phase1.md`.
|
## Phase 1 — Recherche documentaire (sources publiques uniquement)
|
||||||
|
|
||||||
|
3 sous-agents WebSearch ont produit une synthèse 6-axes par provider. Synthèse complète dans `maximus-api/docs/research/0013-stocks-providers-phase1.md`.
|
||||||
|
|
||||||
Findings critiques :
|
Findings critiques :
|
||||||
|
|
||||||
|
|
@ -24,12 +26,12 @@ Findings critiques :
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| **TSX coverage** | ✅ via `.TRT` / `.TRV` | ❓ non confirmé publiquement | ❌ non couvert |
|
| **TSX coverage** | ✅ via `.TRT` / `.TRV` | ❓ non confirmé publiquement | ❌ non couvert |
|
||||||
| **Plan technique min pour 1500 rpm × 10k/jour** | aucun palier public ≥ 1500 rpm (top 1200 rpm @ ~$249.99/mo) | Power suffit techniquement (~$30/mo, 100k/jour) | Starter suffit techniquement ($29/mo "unlimited") |
|
| **Plan technique min pour 1500 rpm × 10k/jour** | aucun palier public ≥ 1500 rpm (top 1200 rpm @ ~$249.99/mo) | Power suffit techniquement (~$30/mo, 100k/jour) | Starter suffit techniquement ($29/mo "unlimited") |
|
||||||
| **ToS proxy mutualisé pour clients tiers payants** | ⚠️ zone grise, pas de clause explicite, email business requis | ❌ Power = "internal consumption only" → Commercial $500+/mo + redistribution license | ❌ Individuals ToS interdit explicitement → Business négocié obligatoire |
|
| **ToS proxy mutualisé pour clients tiers payants** | ⚠️ zone grise, pas de clause explicite, email business pour cas commercial | ❌ Power = "internal consumption only" → Commercial $500+/mo + redistribution license | ❌ Individuals ToS interdit explicitement → Business négocié obligatoire |
|
||||||
| **HTTP error model** | ⚠️ 200 OK + champ `Note`/`Information` | ⚠️ 200 OK + body non-JSON sur quota | ✅ HTTP 429 standard |
|
| **HTTP error model** | ⚠️ 200 OK + champ `Note`/`Information` | ⚠️ 200 OK + body non-JSON sur quota | ✅ HTTP 429 standard |
|
||||||
| **Header `Retry-After`** | ❌ non | ❓ non documenté | ❓ non documenté |
|
|
||||||
| **Profondeur historique daily** | 20+ ans | 30+ ans US | 5 ans Starter |
|
| **Profondeur historique daily** | 20+ ans | 30+ ans US | 5 ans Starter |
|
||||||
|
| **Free tier viable pour dev** | ✅ 25 req/jour, 5 req/min — OK pour valider l'intégration | ⚠️ 1000 req/jour mais ToS interdit le commercial sans Commercial plan | ⚠️ 5 req/min, EOD only, ToS interdit le commercial sans Business |
|
||||||
|
|
||||||
**Finding majeur** : la pré-désignation ADR 0011 « Tiingo Power ~10 $/mo » est obsolète sur le prix (réel 2026 ≈ $30/mo) ET invalide sur le ToS. Notre cas d'usage force Tiingo en plan **Commercial** ($500+/mo) avec **redistribution license négociée**. Polygon idem (Business plan, prix non public). Alpha Vantage seul reste en zone grise sans interdiction explicite.
|
**Finding majeur** : la pré-désignation ADR 0011 « Tiingo Power ~10 $/mo » est obsolète sur le prix (réel 2026 ≈ $30/mo) ET invalide sur le ToS (Power = internal-use only). Notre cas d'usage cible (proxy multi-tenant) forcerait Tiingo en plan Commercial ($500+/mo) avec redistribution license négociée. Polygon idem (Business plan, prix non public). Alpha Vantage seul reste en zone grise sans interdiction explicite et offre un free tier exploitable pour valider l'intégration en dev.
|
||||||
|
|
||||||
## Phase 2 — Smoke test live Alpha Vantage (2026-05-07, free tier)
|
## Phase 2 — Smoke test live Alpha Vantage (2026-05-07, free tier)
|
||||||
|
|
||||||
|
|
@ -51,85 +53,94 @@ Findings critiques :
|
||||||
| 12 | `SYMBOL_SEARCH keywords=shopify` | 5 résultats incluant `SHOP.TRT` Toronto | Convention `.TRT` confirmée par AV |
|
| 12 | `SYMBOL_SEARCH keywords=shopify` | 5 résultats incluant `SHOP.TRT` Toronto | Convention `.TRT` confirmée par AV |
|
||||||
| 13 | `TIME_SERIES_DAILY_ADJUSTED` AAPL outputsize=full | `Information` field — premium endpoint | ⚠️ Premium-gate global sur l'historique ajusté |
|
| 13 | `TIME_SERIES_DAILY_ADJUSTED` AAPL outputsize=full | `Information` field — premium endpoint | ⚠️ Premium-gate global sur l'historique ajusté |
|
||||||
|
|
||||||
**Headers HTTP** : `Retry-After` absent sur les 13 réponses. Toutes en HTTP 200 (confirme la doc — pas de 4xx propres). Content-Type `application/json` sur toutes.
|
**Headers HTTP** : `Retry-After` absent sur les 13 réponses. Toutes en HTTP 200 (confirme la doc — pas de 4xx propres). Content-Type `application/json` partout.
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
**Adopter Alpha Vantage Premium (tier minimum $49.99/mo, 75 rpm)** comme provider stocks de remplacement direct de Yahoo, **sous condition suspensive** d'autorisation écrite d'usage commercial multi-tenant obtenue par email à `support@alphavantage.co`.
|
**Override partiel de l'ADR 0011 — uniquement le provider de bascule désigné** :
|
||||||
|
|
||||||
Override partiel de l'ADR 0011 : la pré-désignation **Tiingo Power devient invalide** (prix obsolète + ToS internal-use only). Tiingo reste plausible comme fallback secondaire si Alpha Vantage refuse l'usage commercial — mais à un coût ~10× supérieur (Commercial $500+/mo + redistribution license).
|
- L'ADR 0011 reste en vigueur sur tout le reste : Yahoo best-effort en prod, garde-fous (badge UX, circuit breaker, quota 200 req/jour/licence, saisie manuelle toujours active), triggers de migration inchangés.
|
||||||
|
- **Le provider de bascule désigné passe de Tiingo Power à Alpha Vantage Premium $49.99/mo (75 rpm)** quand un trigger ADR 0011 se déclenchera réellement.
|
||||||
|
- **Aucune bascule immédiate.** Yahoo best-effort reste en prod tant qu'aucun trigger réel (1ère licence payée, plainte client formelle, saturation des incidents) ne justifie le cash burn.
|
||||||
|
|
||||||
### Justification du choix Alpha Vantage
|
### Pourquoi Alpha Vantage plutôt que Tiingo (pré-désignation 0011)
|
||||||
|
|
||||||
1. **Drop-in Yahoo via `.TO` natif** — découverte Phase 2 : AV accepte le suffixe Yahoo `.TO` silencieusement comme alias de `.TRT`. Aucune mapping table à coder. Le code `yahooProvider.ts` existant peut être copié quasi-tel-quel en `alphaVantageProvider.ts`.
|
1. **Tiingo Power est invalide pour notre cas** : "internal consumption only" dans le ToS. Notre proxy multi-tenant force Tiingo en plan Commercial ~$500/mo + redistribution license — ~10× plus cher que la pré-désignation 0011 ($10/mo). Le rapport coût/bénéfice supposé par 0011 ne tient plus.
|
||||||
2. **Couverture TSX confirmée empiriquement** — `.TRT` (TSX) et `.TRV` (TSX Venture) supportés. Smallcaps non-encore validés mais big caps + symbol search OK.
|
2. **Alpha Vantage Premium $49.99/mo** est le palier le moins cher qui (a) couvre le besoin technique avec marge (75 rpm × 1440 = ~108k req/jour, vs cible 10k/jour), (b) inclut `TIME_SERIES_DAILY_ADJUSTED` confirmé empiriquement comme premium-gate, (c) couvre le TSX nativement.
|
||||||
3. **Mutual funds couverts** (VTSAX testé) — pertinent pour le scope long-terme.
|
3. **Drop-in Yahoo via `.TO` natif** — découverte Phase 2 majeure : AV accepte le suffixe Yahoo `.TO` silencieusement comme alias de `.TRT`. **Aucune mapping table à coder.** Le code `yahooProvider.ts` existant peut être copié quasi-tel-quel en `alphaVantageProvider.ts`. C'est l'argument décisif pour la bascule rapide quand elle sera déclenchée — délai d'implémentation ~quelques heures, pas quelques jours.
|
||||||
4. **Coût façade le plus bas** des 3 providers viables : $49.99/mo vs $500+/mo Tiingo Commercial vs Polygon Business (non public mais probablement >$100/mo).
|
4. **ToS en zone grise = négociable au moment voulu** : pas d'interdiction explicite (vs Polygon Individuals qui interdit, vs Tiingo Power qui interdit, vs Yahoo qui interdit). Email à `support@alphavantage.co` peut être envoyé au moment du déclenchement, pas avant.
|
||||||
5. **ToS en zone grise = négociable** : pas d'interdiction explicite (vs Yahoo qui interdit, vs Polygon Individuals qui interdit, vs Tiingo Power qui interdit). Email à `support@alphavantage.co` peut transformer la zone grise en autorisation écrite.
|
|
||||||
|
|
||||||
### Variantes implémentation
|
### Polygon écarté
|
||||||
|
|
||||||
**Variante A — Remplacement direct (recommandé)** : `STOCKS_PROVIDER=alphavantage` après confirmation ToS. Yahoo retiré du code (ou kept en deadcode commenté pour rollback rapide).
|
Polygon est techniquement supérieur (data quality, "unlimited" rpm sur Starter $29) mais **disqualifié seul par l'absence de couverture TSX**. Une stratégie hybride Polygon US + AV CA serait plus complexe et plus chère pour un bénéfice marginal vs AV seul.
|
||||||
|
|
||||||
**Variante B — Fallback chain** : `STOCKS_PROVIDER=alphavantage` primary, `yahoo` secondary sur erreur AV (rate limit / `Information` field / circuit breaker ouvert). Garde Yahoo en best-effort résiduel le temps que le marché confirme la stabilité AV. Plus de code mais plus résilient pendant la transition.
|
### État du free tier AV (statu quo dev)
|
||||||
|
|
||||||
**Recommandation** : démarrer en variante A. Le risque de bascule unique est limité — si AV devient indisponible, on peut redéployer Yahoo en quelques minutes via env var. La complexité fallback chain n'est justifiée qu'avec 2+ incidents AV avérés.
|
La clé free tier obtenue pendant l'évaluation reste active pour :
|
||||||
|
- **Dev / smoke test continu** : valider l'intégration en local avant tout déploiement payant.
|
||||||
|
- **Smoke test périodique de la cible de bascule** : 1× par mois, 5-10 calls pour vérifier que la convention `.TO` fonctionne toujours, que les premium-gates n'ont pas changé, que `support@alphavantage.co` n'a pas resserré le free tier.
|
||||||
|
|
||||||
### Garde-fous obligatoires (mirror ADR 0011)
|
La clé reste hors-Coolify (jamais déployée en prod), dans `~/.maximus-research-keys/av.txt` côté machine de dev. **À ne pas confondre avec un déploiement de prod** — le free tier 25 req/jour est 400× insuffisant pour servir 50 licences réelles.
|
||||||
|
|
||||||
|
## Plan de bascule (déclenché par trigger ADR 0011, pas maintenant)
|
||||||
|
|
||||||
|
Quand un trigger réel se déclenchera :
|
||||||
|
|
||||||
|
1. **Décision business** : confirmer que la bascule est justifiée vs amender ADR 0011 (rester sur Yahoo + mitigations alternatives).
|
||||||
|
2. **Email ToS** à `support@alphavantage.co` (draft inclus en annexe ci-dessous) — à envoyer **à ce moment-là**, pas maintenant. Délai de réponse standard 3-5 j ouvrables. Use case précisé : "server-side proxy serving N paying B2B licensees".
|
||||||
|
3. **Sur réponse positive** : signup Premium $49.99/mo (75 rpm). Clé en var Coolify `ALPHAVANTAGE_API_KEY` (secret). Issue follow-up `feat(api): integrer Alpha Vantage comme provider stocks` créée à ce moment-là.
|
||||||
|
4. **Sur réponse négative ou zone grise prolongée** : amender cet ADR pour retomber sur Tiingo Commercial ($500+/mo) — financièrement justifiable seulement si l'audience est suffisamment monétisée pour absorber le coût.
|
||||||
|
5. **Implémentation variante A** (remplacement direct, switch via env var `STOCKS_PROVIDER=alphavantage`). Yahoo retiré du code dans une seconde PR séquencée pour rollback rapide.
|
||||||
|
6. **Smoke test prod** : `?symbol=AAPL` et `?symbol=SHOP.TO` doivent renvoyer 200 + prix non-stale.
|
||||||
|
7. **Bascule + monitoring 7 jours**.
|
||||||
|
8. **Cleanup** : `~/.maximus-research-keys/` supprimé.
|
||||||
|
|
||||||
|
## Garde-fous obligatoires (mirror ADR 0011, applicables à AV au moment de la bascule)
|
||||||
|
|
||||||
1. **Label UX inchangé** : badge "best-effort" reste sur les catégories stocks. AV est plus stable que Yahoo mais reste un provider tiers — pas de SLA contractuel pour notre cas d'usage à $49.99/mo.
|
1. **Label UX inchangé** : badge "best-effort" reste sur les catégories stocks. AV est plus stable que Yahoo mais reste un provider tiers — pas de SLA contractuel pour notre cas d'usage à $49.99/mo.
|
||||||
2. **Circuit breaker côté maximus-api** : seuil identique 5 erreurs AV / 60 sec → breaker ouvert 15 min. Notification Telegram/email à `maxime2tremblay@protonmail.com`.
|
2. **Circuit breaker côté maximus-api** : seuil identique 5 erreurs AV / 60 sec → breaker ouvert 15 min. Notification Telegram/email à `maxime2tremblay@protonmail.com`.
|
||||||
3. **Quota côté maximus-api** : 200 req/jour/licence — inchangé. Avec 75 rpm × 1440 min = 108 000 req/jour de capacité, on a la marge pour 50 licences × 200 req/jour = 10 000 req/jour (~10 % du quota AV).
|
3. **Quota côté maximus-api** : 200 req/jour/licence — inchangé. Avec 75 rpm × 1440 min = 108 000 req/jour de capacité, marge ample pour 50 licences.
|
||||||
4. **Saisie manuelle toujours active** : aucun chemin d'erreur ne bloque la saisie d'un snapshot.
|
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. Vers AV : UA `maximus-api/<version>` (pas besoin de UA browser-like contrairement à Yahoo). Auth via query string `?apikey=` (limitation AV — pas de header support).
|
5. **Headers stripping rigoureux** : tous les headers entrants supprimés. Vers AV : UA `maximus-api/<version>` (pas besoin de UA browser-like contrairement à Yahoo). Auth via query string `?apikey=` (limitation AV — pas de header support).
|
||||||
6. **Logs** : URL avec `?apikey=` masquée dans les logs Coolify/Traefik via une regex de filtre côté pino logger.
|
6. **Logs** : URL avec `?apikey=` masquée dans les logs Coolify/Traefik via une regex de filtre côté pino logger.
|
||||||
|
|
||||||
### Parsing défensif (issu des findings Phase 2)
|
## Parsing défensif (issu des findings Phase 2 — applicable au moment de l'implémentation)
|
||||||
|
|
||||||
Le module `alphaVantageProvider.ts` doit gérer **4 cas distincts** sur HTTP 200 :
|
Le module `alphaVantageProvider.ts` doit gérer **5 cas distincts** sur HTTP 200 :
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 1. Happy path — body.Global Quote populated
|
// 1. Happy path — body['Global Quote'] populated
|
||||||
if (body['Global Quote'] && Object.keys(body['Global Quote']).length > 0) { /* ok */ }
|
if (body['Global Quote'] && Object.keys(body['Global Quote']).length > 0) { /* ok */ }
|
||||||
// 2. Symbol unknown — body.Global Quote = {} empty object
|
// 2. Symbol unknown — body['Global Quote'] = {} empty object
|
||||||
else if (body['Global Quote'] && Object.keys(body['Global Quote']).length === 0) { /* symbol_not_found */ }
|
else if (body['Global Quote'] && Object.keys(body['Global Quote']).length === 0) { /* symbol_not_found */ }
|
||||||
// 3. Premium endpoint blocked — body.Information field with subscribe message
|
// 3. Premium endpoint blocked — body['Information'] field with subscribe message
|
||||||
else if (body['Information']) { /* premium_required or rate_limit */ }
|
else if (body['Information']) { /* premium_required or rate_limit */ }
|
||||||
// 4. Error — body.Error Message field (param malformed)
|
// 4. Error — body['Error Message'] field (param malformed)
|
||||||
else if (body['Error Message']) { /* invalid_request */ }
|
else if (body['Error Message']) { /* invalid_request */ }
|
||||||
// 5. Rate limit hit — body.Note field (legacy free tier message)
|
// 5. Rate limit hit — body['Note'] field (legacy free tier message)
|
||||||
else if (body['Note']) { /* rate_limit */ }
|
else if (body['Note']) { /* rate_limit */ }
|
||||||
```
|
```
|
||||||
|
|
||||||
Pas de fallback sur HTTP status (toujours 200). Le code de parsing yahoo existant ne couvre pas ces cas — adaptation requise dans la PR follow-up (Phase 4).
|
Pas de fallback sur HTTP status (toujours 200). Le code de parsing yahoo existant ne couvre pas ces cas — adaptation requise dans la PR follow-up déclenchée par la bascule.
|
||||||
|
|
||||||
## Plan de migration (séquentiel)
|
|
||||||
|
|
||||||
1. **Email ToS** envoyé à `support@alphavantage.co` (draft inclus en annexe ci-dessous). Délai d'attente standard ~3-5 jours ouvrables.
|
|
||||||
2. **Sur réponse positive** : signup Premium $49.99/mo (75 rpm), transférer la clé en var Coolify `ALPHAVANTAGE_API_KEY` (secret).
|
|
||||||
3. **Issue follow-up** `feat(api): integrer Alpha Vantage comme provider stocks` créée → implémentation en variante A.
|
|
||||||
4. **Smoke test prod** : `?symbol=AAPL` et `?symbol=SHOP.TO` doivent renvoyer 200 + prix non-stale.
|
|
||||||
5. **Bascule** : `STOCKS_PROVIDER=alphavantage` en var Coolify, redéploiement, monitoring 7 jours.
|
|
||||||
6. **Cleanup** : `~/.maximus-research-keys/` supprimé. Si variante A : retrait `yahooProvider.ts` du code dans une seconde PR (séquencée pour rollback rapide).
|
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
### Positives
|
### Positives
|
||||||
|
|
||||||
- **Coût récurrent bas** : $49.99/mo plancher (avec marge pour upgrade 150-300 rpm si croissance audience).
|
- **0 $ de cash burn maintenu** — l'esprit MVP de l'ADR 0011 est préservé. Pas de bascule prématurée à un provider payant.
|
||||||
- **TSX natif via `.TO` Yahoo style** — implémentation triviale, pas de breaking change pour les clients qui passent déjà des tickers `.TO`.
|
- **Cible de bascule validée empiriquement** — `.TO` natif, TSX confirmé, mutual funds OK, format API simple. Au moment du trigger, la bascule prendra des heures, pas des jours.
|
||||||
- **Profondeur historique 20+ ans daily** — couvre largement le cas d'usage portefeuille long-terme.
|
- **Override propre de la pré-désignation Tiingo** — la décision 0011 ne s'auto-déclenche pas mécaniquement vers un provider mal calibré.
|
||||||
- **Mutual funds couverts** — pertinent pour la roadmap.
|
- **Email ToS reporté** — pas d'effort gaspillé tant qu'il n'y a pas d'enjeu réel.
|
||||||
- **Symbol search natif** — utile pour l'auto-complétion côté client si jamais.
|
|
||||||
|
|
||||||
### Négatives / risques actés
|
### Négatives / risques actés
|
||||||
|
|
||||||
- **Adjusted close = premium endpoint** : `TIME_SERIES_DAILY_ADJUSTED` n'est pas dans le free tier. Confirmé empiriquement — `Information` field renvoyé sur free. Le tier Premium $49.99 inclut cet endpoint (à reconfirmer sur la page pricing au moment du signup). Si jamais Premium ne l'inclut pas, upgrade vers tier supérieur ou recalcul côté client à partir des splits/dividends séparés.
|
- **Yahoo reste cassé en prod** — feature stocks non-fonctionnel jusqu'au déclenchement du trigger ou résolution Yahoo (improbable). Acceptable tant qu'aucun client payant ne se plaint.
|
||||||
- **Indices broad-market non couverts via `GLOBAL_QUOTE` free** : SPX, ^GSPC, GSPTSE retournent objet vide. Hors-scope tant que la roadmap ne demande pas d'indices ; sinon ETF proxy (`SPY`, `XIC.TO`) ou endpoint premium dédié.
|
- **Adjusted close = premium endpoint** chez AV : confirmé empiriquement. Au moment de la bascule, le tier Premium $49.99 sera nécessaire (pas de chemin gratuit pour `TIME_SERIES_DAILY_ADJUSTED`).
|
||||||
|
- **Indices broad-market non couverts via `GLOBAL_QUOTE`** : SPX, ^GSPC, GSPTSE retournent objet vide. Hors-scope tant que la roadmap ne demande pas d'indices ; sinon ETF proxy (`SPY`, `XIC.TO`).
|
||||||
- **HTTP 200 sur toutes les erreurs** : parsing fragile, code défensif obligatoire (5 cas distincts à gérer).
|
- **HTTP 200 sur toutes les erreurs** : parsing fragile, code défensif obligatoire (5 cas distincts à gérer).
|
||||||
- **Pas de `Retry-After` natif** : exponential backoff côté client requis sur détection de `Note`/`Information`.
|
- **Pas de `Retry-After` natif** : exponential backoff côté client requis sur détection de `Note`/`Information`.
|
||||||
- **Auth `?apikey=` query string uniquement** : leak risk dans les logs Coolify/Traefik si pas filtré. Mitigation = regex de masking côté pino logger.
|
- **Auth `?apikey=` query string uniquement** : leak risk dans les logs Coolify/Traefik. Mitigation = regex de masking pino.
|
||||||
- **ToS en zone grise jusqu'à confirmation écrite** : si AV refuse l'usage commercial après email, retomber sur Tiingo Commercial $500+/mo (ADR à amender) ou rester sur Yahoo best-effort en attendant un trigger ADR 0011 plus net.
|
- **ToS en zone grise jusqu'à confirmation écrite future** : risque de suspension de clé sans préavis si AV détecte un pattern multi-tenant. Probabilité faible à petite échelle, à monitorer.
|
||||||
- **Profondeur smallcaps TSXV non validée** : risque sur ~5-10 % des positions clients (à mitiger en Phase 4 par smoke test sur échantillon représentatif des holdings réels).
|
- **Profondeur smallcaps TSXV non validée** : risque sur ~5-10 % des positions clients (à mitiger en Phase 4 par smoke test sur échantillon représentatif des holdings réels).
|
||||||
- **Free tier érodé historiquement** (500 → 100 → 25 req/jour) : signal qu'AV peut resserrer aussi les paid tiers à terme. Risque budget sur 12-24 mois.
|
- **Free tier érodé historiquement** (500 → 100 → 25 req/jour) : signal qu'AV peut resserrer aussi les paid tiers à terme. Risque budget sur 12-24 mois.
|
||||||
|
|
||||||
|
|
@ -137,19 +148,28 @@ Pas de fallback sur HTTP status (toujours 200). Le code de parsing yahoo existan
|
||||||
|
|
||||||
- Le code reste `src/services/providers/<provider>Provider.ts` parallèle, switch via env var. Pattern déjà en place pour Yahoo, extension triviale.
|
- Le code reste `src/services/providers/<provider>Provider.ts` parallèle, switch via env var. Pattern déjà en place pour Yahoo, extension triviale.
|
||||||
|
|
||||||
|
## Triggers de bascule (rappel ADR 0011, inchangés)
|
||||||
|
|
||||||
|
- 1+ incidents IP-ban Yahoo / mois pendant 2 mois consécutifs, OU
|
||||||
|
- 30 %+ requêtes stocks tombent en `service_degraded` sur 7 jours, OU
|
||||||
|
- Plainte légale formelle de Yahoo / Verizon Media, OU
|
||||||
|
- (nouveau) 1ère licence payée active OU 1ère plainte client formelle sur le feature stocks.
|
||||||
|
|
||||||
|
Le 4ème trigger est ajouté pour aligner la décision avec la réalité business : tant qu'il n'y a pas de licence payée ou de plainte active, le 0 $ recurring l'emporte sur le service-quality.
|
||||||
|
|
||||||
## Suivi
|
## Suivi
|
||||||
|
|
||||||
- ADR à reviewer dans 6 mois (2026-11-07) ou plus tôt si :
|
- ADR à reviewer dans 6 mois (2026-11-07) ou plus tôt si :
|
||||||
- AV refuse l'usage commercial après email ToS,
|
- Trigger de bascule déclenché (réévaluer Yahoo vs AV en fonction du contexte du moment),
|
||||||
- bascule complète déclenche >5 % erreurs AV / jour pendant 7 jours,
|
- AV resserre le free tier au point que le smoke test mensuel devient impossible,
|
||||||
- tier $49.99/mo s'avère insuffisant (>50 % du quota saturé en burst).
|
- Yahoo redevient stable (improbable mais possible).
|
||||||
- Métriques à tracker dans le log applicatif maximus-api : `alphavantage_success_rate_7d`, `alphavantage_premium_block_count_30d`, `alphavantage_rate_limit_count_30d`, `provider_distribution`.
|
- Métriques à tracker dans le log applicatif maximus-api : `yahoo_success_rate_7d`, `yahoo_breaker_open_count_30d`, `crypto_provider_distribution`, `paid_licenses_active_count`.
|
||||||
- Issue de suivi : `feat(api): integrer Alpha Vantage comme provider stocks` à créer en Phase 4 (acceptance criteria détaillés à partir de la section "Parsing défensif" + "Plan de migration").
|
- Smoke test mensuel AV free tier : entrée TODO dans le calendrier ou cron `claude` skill.
|
||||||
|
|
||||||
## Annexe — Draft email à `support@alphavantage.co`
|
## Annexe — Draft email à `support@alphavantage.co` (à envoyer au moment de la bascule, pas maintenant)
|
||||||
|
|
||||||
```
|
```
|
||||||
Subject: Commercial use authorization — server-side proxy for ~50 paying B2B licensees
|
Subject: Commercial use authorization — server-side proxy for ~N paying B2B licensees
|
||||||
|
|
||||||
Hello Alpha Vantage support team,
|
Hello Alpha Vantage support team,
|
||||||
|
|
||||||
|
|
@ -157,11 +177,10 @@ I am evaluating Alpha Vantage Premium for a small B2B SaaS use case and would li
|
||||||
to confirm the licensing model in writing before subscribing.
|
to confirm the licensing model in writing before subscribing.
|
||||||
|
|
||||||
Use case:
|
Use case:
|
||||||
- Server-side proxy (single VPS, single API key) on behalf of ~50 paying B2B licensees
|
- Server-side proxy (single VPS, single API key) on behalf of ~N paying B2B licensees
|
||||||
- Delayed/EOD US equities (NYSE/NASDAQ/AMEX) and Canadian equities (TSX via .TRT/.TO)
|
- Delayed/EOD US equities (NYSE/NASDAQ/AMEX) and Canadian equities (TSX via .TRT/.TO)
|
||||||
- Mutual funds (limited)
|
- Mutual funds (limited)
|
||||||
- ~10 000 requests/day total, ~1500 req/min peak (well under the 75 rpm tier
|
- ~Y 000 requests/day total, ~Z req/min peak
|
||||||
if we batch, otherwise we would consider a higher tier)
|
|
||||||
- No client-side redistribution: only the licensee's own portfolio holdings are
|
- No client-side redistribution: only the licensee's own portfolio holdings are
|
||||||
fetched, and the response data is consumed by the licensee's own desktop app
|
fetched, and the response data is consumed by the licensee's own desktop app
|
||||||
(no public-facing data feed, no resale to non-licensees)
|
(no public-facing data feed, no resale to non-licensees)
|
||||||
|
|
@ -182,7 +201,7 @@ Maxime Tremblay
|
||||||
maxime2tremblay@protonmail.com
|
maxime2tremblay@protonmail.com
|
||||||
```
|
```
|
||||||
|
|
||||||
À envoyer après merge de cet ADR (ou en parallèle si ADR mergé en Proposed). Réponse écrite à archiver dans `simpl-resultat/docs/adr/0013-attachments/alphavantage-tos-confirmation-YYYY-MM-DD.txt` une fois reçue, et passer le status de l'ADR de Proposed à Accepted.
|
Réponse écrite à archiver dans `simpl-resultat/docs/adr/0013-attachments/alphavantage-tos-confirmation-YYYY-MM-DD.txt` une fois reçue.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
|
|
@ -192,7 +211,7 @@ maxime2tremblay@protonmail.com
|
||||||
- [Alpha Vantage — Customer Support](https://www.alphavantage.co/support/)
|
- [Alpha Vantage — Customer Support](https://www.alphavantage.co/support/)
|
||||||
- [Macroption — Alpha Vantage Symbols (suffixes)](https://www.macroption.com/alpha-vantage-symbols/)
|
- [Macroption — Alpha Vantage Symbols (suffixes)](https://www.macroption.com/alpha-vantage-symbols/)
|
||||||
- ADR 0009 — Architecture du proxy
|
- ADR 0009 — Architecture du proxy
|
||||||
- ADR 0011 — Providers best-effort Yahoo (override partiel)
|
- ADR 0011 — Providers best-effort Yahoo (override partiel sur le provider de bascule désigné)
|
||||||
- `maximus-api/docs/research/0013-stocks-providers-phase1.md` — Synthèse 3-way Phase 1
|
- `maximus-api/docs/research/0013-stocks-providers-phase1.md` — Synthèse 3-way Phase 1
|
||||||
- `~/.maximus-research-keys/raw-av.json` — Réponses brutes Phase 2 smoke test (à supprimer après merge)
|
- `~/.maximus-research-keys/raw-av.json` — Réponses brutes Phase 2 smoke test (à supprimer après merge)
|
||||||
- Issue Forgejo `maximus-api#41`
|
- Issue Forgejo `maximus-api#41`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue