Skip to content

Commit

Permalink
Merge pull request #636 from tellor-io/add-coinpaprika-source
Browse files Browse the repository at this point in the history
Add coinpaprika API source
  • Loading branch information
akremstudy authored Mar 22, 2023
2 parents 84bb299 + 13d3eb0 commit 75576ad
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 deletions.
6 changes: 5 additions & 1 deletion src/telliot_feeds/feeds/reth_btc_feed.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from telliot_feeds.datafeed import DataFeed
from telliot_feeds.queries.price.spot_price import SpotPrice
from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource
from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource
from telliot_feeds.sources.price_aggregator import PriceAggregator

reth_btc_median_feed = DataFeed(
Expand All @@ -9,6 +10,9 @@
asset="reth",
currency="btc",
algorithm="median",
sources=[CoinGeckoSpotPriceSource(asset="reth", currency="btc")],
sources=[
CoinGeckoSpotPriceSource(asset="reth", currency="btc"),
CoinpaprikaSpotPriceSource(asset="reth-rocket-pool-eth", currency="btc"),
],
),
)
6 changes: 5 additions & 1 deletion src/telliot_feeds/feeds/steth_btc_feed.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from telliot_feeds.datafeed import DataFeed
from telliot_feeds.queries.price.spot_price import SpotPrice
from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource
from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource
from telliot_feeds.sources.price_aggregator import PriceAggregator

steth_btc_median_feed = DataFeed(
Expand All @@ -9,6 +10,9 @@
asset="steth",
currency="btc",
algorithm="median",
sources=[CoinGeckoSpotPriceSource(asset="steth", currency="btc")],
sources=[
CoinGeckoSpotPriceSource(asset="steth", currency="btc"),
CoinpaprikaSpotPriceSource(asset="steth-lido-staked-ether", currency="btc"),
],
),
)
78 changes: 78 additions & 0 deletions src/telliot_feeds/sources/price/spot/coinpaprika.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from dataclasses import dataclass
from dataclasses import field
from typing import Any
from urllib.parse import urlencode

from telliot_feeds.dtypes.datapoint import datetime_now_utc
from telliot_feeds.dtypes.datapoint import OptionalDataPoint
from telliot_feeds.pricing.price_service import WebPriceService
from telliot_feeds.pricing.price_source import PriceSource
from telliot_feeds.utils.log import get_logger


logger = get_logger(__name__)


class CoinpaprikaSpotPriceService(WebPriceService):
"""Coinpaprika Price Service"""

def __init__(self, **kwargs: Any) -> None:
kwargs["name"] = "Coinpaprika Price Service"
kwargs["url"] = "https://api.coinpaprika.com"
super().__init__(**kwargs)

async def get_price(self, asset: str, currency: str) -> OptionalDataPoint[float]:
"""Implement PriceServiceInterface
This implementation gets the price from the Coinpaprika API."""

asset = asset.lower()
currency = currency.upper()

url_params = urlencode({"quotes": f"{currency}"})

request_url = f"/v1/tickers/{asset}?&{url_params}"

d = self.get_url(request_url)

if "error" in d:
logger.error(d)
return None, None
elif "response" in d:
response = d["response"]

quote = response.get("quotes")
if quote is None:
logger.error("No quotes in response")
return None, None
quote_currency = quote.get(currency)
if quote_currency is None:
logger.error(f"No prices in {currency} returned from Coinpaprika API")
return None, None

price = quote_currency.get("price")
if price is None:
logger.error("Error parsing Coinpaprika API response")
return None, None
return price, datetime_now_utc()

else:
raise Exception("Invalid response from get_url")


@dataclass
class CoinpaprikaSpotPriceSource(PriceSource):
asset: str = ""
currency: str = ""
service: CoinpaprikaSpotPriceService = field(default_factory=CoinpaprikaSpotPriceService, init=False)


if __name__ == "__main__":
import asyncio

async def main() -> None:
source = CoinpaprikaSpotPriceSource(asset="eth-ethereum", currency="btc")
v, _ = await source.fetch_new_datapoint()
print(v)

asyncio.run(main())
11 changes: 11 additions & 0 deletions tests/sources/test_spot_price_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from telliot_feeds.sources.price.spot.coinbase import CoinbaseSpotPriceService
from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceService
from telliot_feeds.sources.price.spot.coinmarketcap import CoinMarketCapSpotPriceService
from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceService
from telliot_feeds.sources.price.spot.gemini import GeminiSpotPriceService
from telliot_feeds.sources.price.spot.kraken import KrakenSpotPriceService
from telliot_feeds.sources.price.spot.nomics import NomicsSpotPriceService
Expand All @@ -38,6 +39,7 @@
"kraken": KrakenSpotPriceService(),
"coinmarketcap": CoinMarketCapSpotPriceService(),
"bitfinex": BitfinexSpotPriceService(),
"coinpaprika": CoinpaprikaSpotPriceService(),
}


Expand Down Expand Up @@ -293,3 +295,12 @@ async def test_failed_price_service_request():

assert v is None
assert t is None


@pytest.mark.asyncio
async def test_coinpaprika():
"""Test Coinpaprika price service"""
v, t = await get_price("steth-lido-staked-ether", "btc", service["coinpaprika"])
validate_price(v, t)
assert v is not None
assert t is not None

0 comments on commit 75576ad

Please sign in to comment.