FMP client migration: dividend/value Batch B (#495)
The following standalone skills now vendor generated scripts/fmp_client.py
from scripts/fmp_client/registry.py, the shared core and dividend_stable
extension:
value-dividend-screenerdividend-growth-pullback-screenerkanchi-dividend-sop
Their main scripts keep thin FMPClient subclasses for domain methods and
return conventions. FMP HTTP/authentication, error redaction, timeouts, rate
limiting, JSON retry and 429 handling run in the generated client. FINVIZ
transport remains separate. The existing fourteen generated clients retain
byte-identical output in this migration, including the economic-calendar client
used by PR #572.
Preserved behavior
CLI --api-key / FMP_API_KEY precedence, successful report formats, financial
calculations, filters, ranking and Kanchi review blockers are unchanged.
Supported statement/profile/quote/ratio/dividend calls target /stable through
query parameters. Legacy internal endpoint names still work, for example
income-statement/AAA maps to /stable/income-statement?symbol=AAA without
putting the symbol in the URL path.
The dividend-history wrapper, returnOnEquity → roe, and
netDividendsPaid → dividendsPaid aliases preserve the readers’ shapes, scale
and signs. Kanchi still restores lastDividend → lastDiv and requests one
quote/profile per symbol. Historical-price lists stay most-recent-first and
are truncated to the requested count. Value returns [] on history failure;
pullback returns None. Other statement/dividend None/[]/{} conventions remain
in their domain adapters.
Kanchi retains its sleep_seconds and timeout constructor arguments and its
api_calls view. The delay is now the shared minimum interval between requests,
not a sleep after successful responses. api_calls reads the shared counter,
including retried HTTP responses. The configurable timeout branch is enabled
only for these three new generator targets; existing targets still emit their
original fixed-timeout transport.
Intentional transport changes
- The migrated domain paths use stable endpoints only. A 402/403, empty history, or unsupported endpoint does not attempt retired v3 URLs. Unknown internal endpoint names fail without HTTP. Historical query windows use the shared America/New_York calendar date rather than the machine’s local date.
- All three inherit the shared single 429 retry (60-second wait) and fail closed after the second 429. Kanchi previously waited two seconds for its retry.
- Malformed HTTP-200 JSON is retried once, then returns the shared failure value.
- Provider/transport errors mask raw and URL-encoded API-key echoes. Shared transport exceptions remain visible even when a low-level caller asks for quiet HTTP diagnostics. This is not a promise that the separate FINVIZ client has the same logging policy.
The generated client drift gate covers seventeen targets. CI and pre-commit
package checks include these three archives. Tests run each skill in isolation
because standalone bundles intentionally share module names such as
fmp_client. The new fake-transport integration test also imports each bundle
in its own Python process and does not need a live API key.
This PR completes the proposed Batch B, not the remaining #495 batches.