# Provider command overrides Use a command provider when the user explicitly wants a documented API, a licensed feed, or another local market-data source. Do not modify the plugin checkout: upgrades replace repository files. ## Install safely 1. Confirm the provider, coverage, expected delay, API limits, and terms with the user. 2. Create one executable under `~/.config/portfolio-tracker/providers/PROVIDER_NAME`. 3. Keep API keys in a separate user-only file outside the repository. Never print a key to stdout, logs, the widget snapshot, or a response. 4. Set both files to mode `0600`; add user execute permission to the adapter (`0700`). 5. Configure and verify it: ```bash portfolio config \ --price-provider command \ --provider-command /absolute/path/to/provider portfolio refresh portfolio summary --account all ``` The configured path must be absolute. The tracker rejects adapters that are not executable, are owned by another user, or are writable by group or others. The adapter runs as the signed-in user, so inspect it before enabling it. Return to a built-in mode with either: ```bash portfolio config --price-provider yahoo portfolio config --price-provider manual ``` ## Command protocol Write exactly one JSON object to stdout. Write diagnostics to stderr and exit nonzero on failure. Numeric values may be JSON numbers or decimal strings. Prices and rates must be positive. Every `asOf` value must be ISO 8601 with a timezone. ### Current quote Invocation: ```text PROVIDER quote SYMBOL ``` Response: ```json { "price": "123.45", "previousClose": "120.00", "currency": "USD", "asOf": "2026-08-14T20:00:00Z" } ``` `previousClose` may be `null`. `currency` must be the instrument's trading currency. ### FX rate Invocation: ```text PROVIDER fx BASE_CURRENCY QUOTE_CURRENCY ``` Response uses the quote schema. `price` is the number of quote-currency units for one base-currency unit, and `currency` is the quote currency. ### Historical prices Invocation: ```text PROVIDER history SYMBOL START_ISO END_ISO INTERVAL ``` `INTERVAL` is currently `5m` or `1d`. The date range is half-open: include points at or after `START_ISO` and before `END_ISO`. For FX history the tracker passes `BASE/QUOTE` as `SYMBOL`, for example `USD/EUR`. Return prices in the quote currency. Response: ```json { "currency": "USD", "values": [ {"price": "119.50", "asOf": "2026-08-13T20:00:00Z"}, {"price": "123.45", "asOf": "2026-08-14T20:00:00Z"} ] } ``` Return at most 100,000 points. The tracker allows 60 seconds for quotes and FX, 120 seconds for history, and at most 20 MiB of JSON per invocation. ## Verification - Compare a synthetic or user-approved symbol against the provider's own UI. - Verify the returned currency before refreshing the full portfolio. - Confirm `previousClose` refers to the prior trading session. - Check both `5m` and `1d` history for chronological timestamps and split adjustment semantics. - Surface unsupported symbols, stale data, rate limits, and licensing delays; never silently substitute another currency or stale price. ## Alpha Vantage recipe Alpha Vantage can be implemented as a command provider when a user already has the needed plan and entitlements: - `quote`: call `GLOBAL_QUOTE` and map the current price, previous close, instrument currency, and a timezone-qualified observation time. - `fx`: call `CURRENCY_EXCHANGE_RATE`; return quote currency per one base unit. - `history ... 1d`: call `TIME_SERIES_DAILY_ADJUSTED` and return adjusted close. - `history ... 5m`: call `TIME_SERIES_INTRADAY` with `interval=5min`, `adjusted=true`, and the user's required entitlement. Keep the API key in a separate `0600` file and never put it in the adapter path, arguments, stdout, or repository. The current free plan is not a good match for a five-minute widget: it is limited to 25 requests per day and intraday history is premium. Confirm the user's current plan and Alpha Vantage terms before enabling it.