diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..dca4e88 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +python 3.10.14 diff --git a/config/config.toml b/config/config.toml index 37abc15..45f15c6 100644 --- a/config/config.toml +++ b/config/config.toml @@ -1,6 +1,6 @@ [publisher] -# Set it to either 'coin_gecko' or 'pyth_replicator'. You need to provide +# Set it to 'coin_gecko', 'pyth_replicator' or 'hermes'. You need to provide # the configuration for the chosen engine as described below. provider_engine = 'pyth_replicator' @@ -21,6 +21,10 @@ endpoint = 'ws://127.0.0.1:8910' # symbol = 'Crypto.BTC/USD' # coin_gecko_id = 'bitcoin' +# [publisher.hermes] +# http_endpoint = 'https://hermes.pyth.network' +# ws_endpoint = 'wss://hermes.pyth.network' + [publisher.pyth_replicator] http_endpoint = 'https://pythnet.rpcpool.com' ws_endpoint = 'wss://pythnet.rpcpool.com' diff --git a/example_publisher/config.py b/example_publisher/config.py index 71d65a1..c487889 100644 --- a/example_publisher/config.py +++ b/example_publisher/config.py @@ -42,6 +42,10 @@ class PythReplicatorConfig: manual_agg_max_slot_diff: int = ts.option(default=25) account_update_interval_secs: int = ts.option(default=300) +@ts.settings +class HermesConfig: + http_endpoint: str + ws_endpoint: str @ts.settings class Config: @@ -52,3 +56,4 @@ class Config: product_update_interval_secs: int = ts.option(default=60) coin_gecko: Optional[CoinGeckoConfig] = ts.option(default=None) pyth_replicator: Optional[PythReplicatorConfig] = ts.option(default=None) + hermes: Optional[HermesConfig] = ts.option(default=None) diff --git a/example_publisher/providers/hermes.py b/example_publisher/providers/hermes.py new file mode 100644 index 0000000..ff9001e --- /dev/null +++ b/example_publisher/providers/hermes.py @@ -0,0 +1,57 @@ +import asyncio +from typing import List, Optional +from pythclient.hermes import HermesClient +# from pythclient.pythaccounts import PythPriceAccount, PythPriceStatus + + +from structlog import get_logger + +from example_publisher.provider import Price, Provider, Symbol + +from ..config import HermesConfig + +log = get_logger() + + +class Hermes(Provider): + def __init__(self, config: HermesConfig) -> None: + self._config = config + self._client = HermesClient([], config.http_endpoint, config.ws_endpoint) + asyncio.run(self._get_hermes_prices()) + + def upd_products(self, product_symbols: List[Symbol]) -> None: + # TODO Optimize: Remove if possible any symbols we don't want any more + self._client.add_feed_ids(product_symbols) + pass + + def latest_price(self, symbol: Symbol) -> Optional[Price]: + item = self._client.prices_dict[symbol] + return Price( + price=item.price.price, + conf=item.price.conf, + timestamp=item.price.publish_time + ) + + async def _get_hermes_prices(self): + # feed_ids = await self._client.get_price_feed_ids() + # feed_ids_rel = feed_ids[:2] + + # self._client.add_feed_ids(feed_ids_rel) + + # prices_latest = await self._client.get_all_prices(version=version_http) + + # print("Initial prices") + # for feed_id, price_feed in prices_latest.items(): + # print(f"Feed ID: {feed_id}, Price: {price_feed['price'].price}, Confidence: {price_feed['price'].conf}, Time: {price_feed['price'].publish_time}") + + print("Starting web socket...") + ws_call = self._client.ws_pyth_prices(version=1) + ws_task = asyncio.create_task(ws_call) + + while True: + await asyncio.sleep(5) + if ws_task.done(): + break + # print("Latest prices:") + # for feed_id, price_feed in self._client.prices_dict.items(): + # print(f"Feed ID: {feed_id}, Price: {price_feed['price'].price}, Confidence: {price_feed['price'].conf}, Time: {price_feed['price'].publish_time}")