package pipeline import ( "bytes" "context" "encoding/json" "fmt" "net/http" ) // exchSuffix mappe le code bourse OpenFIGI vers le suffixe Yahoo Finance var exchSuffix = map[string]string{ "FP": ".PA", // Euronext Paris "GY": ".DE", // Xetra "LN": ".L", // London "SM": ".MC", // Madrid "IM": ".MI", // Milan "NA": ".AS", // Amsterdam "BB": ".BR", // Bruxelles "UN": "", // NYSE "UQ": "", // NASDAQ "UW": "", // NASDAQ (alt) } type openFIGIRequest struct { IDType string `json:"idType"` IDValue string `json:"idValue"` } type openFIGIData struct { Ticker string `json:"ticker"` ExchCode string `json:"exchCode"` Name string `json:"name"` } type openFIGIResult struct { Data []openFIGIData `json:"data"` Error string `json:"error"` } // ResolveISIN résout un ISIN en ticker Yahoo Finance via OpenFIGI. func ResolveISIN(ctx context.Context, apiKey, isin string) (string, error) { body, _ := json.Marshal([]openFIGIRequest{{IDType: "ID_ISIN", IDValue: isin}}) req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.openfigi.com/v3/mapping", bytes.NewReader(body)) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") if apiKey != "" { req.Header.Set("X-OPENFIGI-APIKEY", apiKey) } resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() var results []openFIGIResult if err := json.NewDecoder(resp.Body).Decode(&results); err != nil { return "", fmt.Errorf("decode openfigi response: %w", err) } if len(results) == 0 || len(results[0].Data) == 0 { return "", fmt.Errorf("no result for ISIN %s", isin) } if results[0].Error != "" { return "", fmt.Errorf("openfigi error: %s", results[0].Error) } d := results[0].Data[0] suffix := exchSuffix[d.ExchCode] return d.Ticker + suffix, nil }