Add support for a new spot price

This page outlines the steps to add support for reporting a new spot price to your Telliot reporter and optionally share that with the community via the Fetch open source Github repo.

Prerequisites

  • Python >= 3.9, < 3.10

  • Setup environment (see here)

Steps

  1. Add spot price to catalog. See src/telliot_feeds/queries/query_catalog.py. For example let's add a query called btctest-usd-spot for testing, adding BTCTEST/USD:

query_catalog.add_entry(
    tag="btctest-usd-spot",
    title="BTCTEST/USD spot price",
    q=SpotPrice(asset="btc", currency="usd"),
)
  1. Add data feed in src/telliot_feeds/feeds/. For example, for adding BTCTEST/USD, create file src/telliot_feeds/feeds/btctest_usd_feed.py:

from telliot_feeds.datafeed import DataFeed
from telliot_feeds.queries.price.spot_price import SpotPrice
from telliot_feeds.sources.price.spot.binance import BinanceSpotPriceSource
from telliot_feeds.sources.price.spot.coinbase import CoinbaseSpotPriceSource
from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource
from telliot_feeds.sources.price.spot.gemini import GeminiSpotPriceSource
from telliot_feeds.sources.price.spot.kraken import KrakenSpotPriceSource
from telliot_feeds.sources.price_aggregator import PriceAggregator

btctest_usd_median_feed = DataFeed(
    query=SpotPrice(asset="BTCTEST", currency="USD"),
    source=PriceAggregator(
        asset="btctest",
        currency="usd",
        algorithm="median",
        sources=[
            CoinGeckoSpotPriceSource(asset="btc", currency="usd"),
            BinanceSpotPriceSource(asset="btc", currency="usdt"),
            CoinbaseSpotPriceSource(asset="btc", currency="usd"),
            GeminiSpotPriceSource(asset="btc", currency="usd"),
            KrakenSpotPriceSource(asset="btc", currency="usd"),
        ],
    ),
)

In the above example, we use the PriceAggregator to aggregate the price from multiple sources (automatic API fetches, not sources that require manual entry). The algorithm can be median or mean. The sources can be any combination of those found in src/telliot_feeds/sources/price/spot/ directory or you can add your own, of course.

You're limited by what asset and currency pairs are supported by the underlying APIs (data providers). For example, if you want to add BTC/JPY, you might use the CoinGeckoSpotPriceSource and BinanceSpotPriceSource (which support BTC/JPY), but not the CoinbaseSpotPriceSource (which does not support BTC/JPY).

You will need to check the documentation of the underlying APIs for which pairs they support or how to parse their values correctly.

3. Add feed to CATALOG_FEEDS constant in src/telliot_feeds/feeds/__init__.py:

from telliot_feeds.feeds.btctest_usd_feed import btctest_usd_median_feed

CATALOG_FEEDS = {
    ...
    "btctest-usd-spot": btctest_usd_median_feed,
}
  1. Add currency/asset to supported lists in src/telliot_feeds/queries/price/spot_price.py. For example, for adding BTCTEST/USD:

CURRENCIES = ["usd", "jpy", "eth", "btc"]
SPOT_PRICE_PAIRS = [
    ...
    "BTCTEST/USD",
]
  1. Test your new feed in tests/feeds/. For example, once you've created a datafeed for an BTCTEST/USD spot price using an aggregate of a few price sourcees, create file tests/feeds/test_btctest_usd_feed.py:

import statistics

import pytest

from telliot_feeds.feeds.btctest_usd_feed import btctest_usd_median_feed


@pytest.mark.asyncio
async def test_btctest_usd_median_feed(caplog):
    """Retrieve median BTC/USD price."""
    v, _ = await btctest_usd_median_feed.source.fetch_new_datapoint()

    assert v is not None
    assert v > 0
    assert (
        "sources used in aggregate: 4" in caplog.text.lower() or "sources used in aggregate: 5" in caplog.text.lower()
    )
    print(f"BTC/USD Price: {v}")

    # Get list of data sources from sources dict
    source_prices = [source.latest[0] for source in btctest_usd_median_feed.source.sources if source.latest[0]]

    # Make sure error is less than decimal tolerance
    assert (v - statistics.median(source_prices)) < 10**-6
  1. Create a pull request to merge your changes into the main branch here.

Using pulseX as source

Add pulseX as a source

sources=[PulseXSubgraphSource(asset="btc", currency="usd"),

and import the function

from telliot_feeds.sources.price.spot.pulsex_subgraph import PulseXSubgraphSource

in the feed file, like this:

from telliot_feeds.datafeed import DataFeed
from telliot_feeds.queries.price.spot_price import SpotPrice
from telliot_feeds.sources.price.spot.binance import BinanceSpotPriceSource
from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource
from telliot_feeds.sources.price_aggregator import PriceAggregator
from telliot_feeds.sources.price.spot.pulsex_subgraph import PulseXSubgraphSource

btctest_usd_median_feed = DataFeed(
    query=SpotPrice(asset="BTCTEST", currency="USD"),
    source=PriceAggregator(
        asset="btctest",
        currency="usd",
        algorithm="median",
        sources=[
            CoinGeckoSpotPriceSource(asset="btc", currency="usd"),
            BinanceSpotPriceSource(asset="btc", currency="usdt"),
            PulseXSubgraphSource(asset="btc", currency="usd"),
        ],
    ),
)

In the example, we're using Coingecko, Binance and PulseX to get the price for BTC now.

After that, search the token address in pulseX and add support for it

"wbtc": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", #wbtc testnet

inside this file:

~telliot-feeds/src/telliot_feeds/sources/price/spot/pulsex_subgraph.py

like this:

logger = get_logger(__name__)
pulsex_subgraph_supporten_tokens = {
    "dai": "0x826e4e896cc2f5b371cd7bb0bd929db3e3db67c0",
    "daimain": "0xefD766cCb38EaF1dfd701853BFCe31359239F305", #dai mainnet
    "usdc": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
    "hex": "0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39",
    "btc": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", #wbtc testnet
    "wpls": "0x70499adEBB11Efd915E3b69E700c331778628707"
}

Last updated