Skip to content

feat: implement CoinPaprika quote source (.CP suffix) - #380

Open
donbagger wants to merge 1 commit into
achannarasappa:masterfrom
donbagger:feat/coinpaprika-quote-source
Open

feat: implement CoinPaprika quote source (.CP suffix)#380
donbagger wants to merge 1 commit into
achannarasappa:masterfrom
donbagger:feat/coinpaprika-quote-source

Conversation

@donbagger

Copy link
Copy Markdown

What this adds

internal/common/common.go has carried QuoteSourceCoingecko and QuoteSourceCoinCap in the QuoteSource enum for a while, but neither was ever implemented, and the README notes .CC and .CG were dropped in v5.0.0. CoinCap also can't come back in its old form: while working on this I checked and api.coincap.io no longer resolves in DNS, and the v3 replacement at rest.coincap.io returns 401 without an API key.

This PR implements a working aggregated crypto source instead: CoinPaprika, behind a new .CP symbol suffix. The free API needs no key, covers 12,000+ cryptocurrencies, and fills the gap for assets that aren't listed on Coinbase (KAS, and so on).

How it works

  • BTC.CP in a watchlist resolves to the highest ranked active coin on CoinPaprika whose symbol matches exactly (btc-bitcoin) via GET /v1/search/. Multiple coins share symbols on CoinPaprika, which is why rank is the tiebreaker.
  • The symbol to coin id mapping goes into the reference data cache for 7 days, same pattern as the Coinbase underlying product mapping and the Yahoo currency map.
  • Quotes come from GET /v1/tickers/{id} (price, percent_change_24h, market_cap, volume_24h from quotes.USD). Unknown ids 404 and are skipped rather than failing the whole watchlist, matching how the other sources treat unknown symbols.
  • Polling only, no streaming. The package mirrors the Yahoo monitor-price structure (monitor plus poller) with a Coinbase style unary client. The free API refreshes ticker data every few minutes and edge caches responses for about 30 seconds, so the CoinPaprika poll interval is floored at 30 seconds regardless of the global interval. A 5 second stock watchlist won't hammer CoinPaprika for no benefit.
  • Quotes are denominated in USD and wired into the existing currency rate flow, so currency: EUR conversion works the same as it does for Coinbase.

Config example:

interval: 5
watchlist:
  - NET          # Yahoo Finance, unchanged
  - ETH.CB       # Coinbase, unchanged
  - BTC.CP       # CoinPaprika
  - KAS.CP       # works for assets not listed on Coinbase
lots:
  - symbol: "BTC.CP"
    quantity: 0.5
    unit_cost: 30000

Enum note

I appended QuoteSourceCoinPaprika at the end of the enum so existing iota values don't shift, and left QuoteSourceCoingecko and QuoteSourceCoinCap untouched. Happy to mark those two as deprecated in a follow-up if you want, I just didn't want to bundle that decision in here.

Testing

  • go build ./..., go tool golangci-lint run (0 issues) and go tool ginkgo -skip="GetQuotes Response" -cover ./... all pass locally on Go 1.26.4, 24 suites green. New packages: unary 100%, poller 100%, monitor 91.2% statement coverage. Tests use ginkgo, gomega and ghttp like the neighboring monitors, with fixtures copied from live API responses.
  • Live checks against the real API: ticker print and ticker print summary with .CP lots return correct prices and position math, and a monitor-level run with the 30 second poller received a live poll update (an ETH price change) end to end. Search resolution verified live for BTC, ETH and KAS, including the case sensitivity gotcha: /v1/tickers/BTC-BITCOIN 404s, ids must be lowercase, which the client normalizes.
  • What I couldn't exercise: an interactive TUI session in a real terminal (Yahoo is consent-walled from where I am, and my pty capture setup didn't cooperate). The TUI uses the identical NewMonitor wiring that print uses, so the untested surface is small, but flagging it honestly.
  • govulncheck reports one Go stdlib finding that is also present on a clean master checkout, so it's pre-existing and not introduced by this change.

Disclosure: I do DevRel for CoinPaprika. Everything here uses the public free API, no key or account involved.

The QuoteSource enum has declared crypto sources that were never wired up and the
CoinCap hosted API has since shut down. This adds a working aggregated crypto source:
symbols suffixed with .CP resolve to the highest ranked matching coin on CoinPaprika
and are polled via the free API with no key required. Mirrors the Yahoo poll-only
monitor structure and the Coinbase unary client conventions.
@donbagger

Copy link
Copy Markdown
Author

Checking in on this. No CI has run on the PR at all, which I assume is the first-time-contributor approval gate, so there are no test results for you to look at yet.

The change is additive: a new internal/monitor/coinpaprika package behind a .CP suffix, with the Yahoo and Coinbase paths untouched, plus unit tests for the monitor, poller and unary client. If you would rather not carry another quote source in the tree, say so and I will close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant