# Equity/ETF provider integration: OpenFIGI + FMP

Use this when making the FinanceManager Instrument Search / `Position hinzufügen` wizard use real public market-data providers while preserving the no-secret/no-live-render rules.

## Runtime secrets

- Load provider keys from the external runtime file, not the repo: `~/jarvis_runtime/finance-system/secrets/.env`.
- The file should be mode `600`; the secrets directory should be restrictive.
- Supported provider variables for this workflow:
  - `OPENFIGI_API_KEY` or `JARVIS_OPENFIGI_API_KEY`
  - `FMP_API_KEY`, `FINANCIAL_MODELING_PREP_API_KEY`, or `JARVIS_FMP_API_KEY`
  - `FINNHUB_API_KEY` as optional fallback only
  - `EODHD_API_KEY` optional/status-only unless explicitly prioritized later
- Never print, commit, test-fixture, log, or report actual key values. In tests, avoid literal `API_KEY=...` strings when a Git-safety scanner flags assignment-like patterns; construct dummy env lines from split strings instead.
- Provider status may show `key_missing`, `key_loaded`, `auth_failed`, `rate_limited`, `endpoint_restricted`, `network_error`, `no_results`, or `provider_error`; it must never show a key prefix/value. Without a live probe, show key presence such as “Key geladen”, not “aktiv”.

## Provider priority and responsibilities

1. Local instrument catalog: always first. Existing local catalog matches must be shown before public candidates.
2. OpenFIGI: priority public provider for identifier mapping.
   - Use `/v3/mapping` for ISIN (`ID_ISIN`) and ticker+exchange (`TICKER` + `exchCode`) when the query shape allows.
   - Use `/v3/search` only as a fallback search mode.
   - Return structured candidates with name, ISIN when evidenced, FIGI/provider symbol, ticker, exchange, currency, inferred asset class, provider, confidence, and manual-selection status.
3. FMP / Financial Modeling Prep: second public provider.
   - Prefer the `stable` endpoints when available: `/stable/search-symbol`, `/stable/search-name`, `/stable/search-isin`, `/stable/search-exchange-variants`, and `/stable/profile`.
   - Query multiple search modes by input shape: ISIN-shaped input tries `search-isin`; short single-token input tries `search-symbol` and exchange variants; all non-empty inputs may try `search-name`.
   - Treat FMP HTTP `402` as `endpoint_restricted` (plan/paywall), not auth/network failure; skip restricted endpoints and continue with the others.
   - Use profile lookup to enrich ISIN/currency/country/ETF classification and to provide a price preview when profile includes `price`/`lastPrice`.
   - Use FMP prices only in explicit update workflows, not dashboard render.
4. Finnhub: optional fallback, not primary.
5. Manual creation: always available with warnings/auditability.
6. EODHD: do not prioritize for MVP provider search unless user explicitly changes direction.

## Merge and review rules

- Ticker alone is never unique; require manual selection.
- One ISIN can have multiple listings; include exchange/currency in the candidate key where possible.
- If OpenFIGI and FMP return the same ISIN/listing, merge candidates, combine provider labels, and raise confidence.
- If provider evidence conflicts on ticker/exchange/currency, keep a single review candidate where appropriate but degrade confidence and mark/manual-label it as needing review; do not auto-select.
- Cache external provider results locally as candidates; do not save positions from provider responses.

## Dashboard / Streamlit behavior

- Page render must not call external APIs. Online lookup happens only after an explicit user click.
- User Mode should hide internal IDs, raw provider internals, FIGI/composite FIGI and debug fields. Show human fields: name, ISIN, ticker, exchange, currency, asset class, provider/source, confidence/review status, and price preview if already available.
- Provider status belongs near the wizard/search controls and must degrade gracefully when keys are missing or auth/rate-limit/plan errors occur.
- If the user wants to search before choosing Aktie vs ETF, include an “Alle” asset-class option and infer class from provider evidence; manual creation can default to stock only when the user did not choose a class.
- Display local, OpenFIGI, FMP and other provider groups separately when useful so the user can see provenance without exposing technical IDs.
- Price preview in the wizard may use explicit-click provider lookup results or local `market_prices`; normal dashboard/report views still consume local `market_prices` only.
- Missing price displays `Preis noch nicht verfügbar` / “nicht verfügbar”, never `0`.

## Explicit price update workflow

- Provide an explicit CLI/button flow such as `update-equity-prices` for active Equity/ETF instruments with confirmed provider mappings.
- If no confirmed mappings exist, the safe result is `total_mappings=0` with no provider calls.
- Store fetched prices in `market_prices` with provider, provider symbol, date, currency, status/timestamp fields as supported by schema.
- Dashboard/report views consume local `market_prices` only.

## Tests to preserve

Mock-based tests should cover:

- Missing OpenFIGI/FMP keys do not crash.
- Runtime `.env` loading is shared by CLI/dashboard and does not require a repo `.env`.
- OpenFIGI ISIN lookup returns structured candidates.
- OpenFIGI 401/403, 429 and empty 2xx responses are classified distinctly (`auth_failed`, `rate_limited`, `no_results`) without exposing keys.
- FMP name/ticker/ISIN search returns structured candidates and profile enrichment, including stable endpoint fallbacks when one endpoint is restricted.
- FMP profile price preview is surfaced as provider-result fields without saving a position.
- Local catalog precedence.
- Multiple matches require selection.
- Provider agreement merges and increases confidence.
- Provider conflict becomes/manual-remains review-required.
- No external API call on dashboard render; only explicit click/workflow.
- Price preview shows local price when present and `Preis noch nicht verfügbar` when absent.
- API keys are never logged or exposed in outputs.
- Git-safety remains clean after tests; remove `.pytest_cache`/`__pycache__` before safety scans.

## Verification sequence

1. `python -m compileall -q src tests`
2. `pytest -q`
3. remove `.pytest_cache` and `__pycache__`
4. `python -m jarvis_finance.cli.main git-safety-scan`
5. `git diff --check`
6. `git status --short`
7. commit and push only after the safety checks pass.

Optional real-provider smoke tests should be aggregate-only and use neutral public examples such as ISIN `US9229087690`, ticker `VTI`, name `Vanguard Total Stock`; do not read/write portfolio data and do not print provider payloads. Report only categories/count booleans such as key present, endpoint reachable, candidates found, price preview possible, and error category. A stored key can still yield OpenFIGI `401/auth_failed`; treat that as a provider-auth result to report and keep FMP/local search functioning rather than blocking the whole wizard.