mgbam commited on
Commit
2aa11ed
Β·
verified Β·
1 Parent(s): 95c4c23

Update app/price_fetcher.py

Browse files
Files changed (1) hide show
  1. app/price_fetcher.py +32 -23
app/price_fetcher.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
- A high-frequency, multi-exchange price fetcher.
3
- It concurrently fetches prices from multiple sources for arbitrage detection.
4
  """
5
  import asyncio
6
  import logging
@@ -10,42 +10,51 @@ import httpx
10
  logger = logging.getLogger(__name__)
11
 
12
  class PriceFetcher:
13
- SOURCES = {
14
- "binance": "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT",
15
- "coinbase": "https://api.coinbase.com/v2/prices/BTC-USD/spot",
16
- "kraken": "https://api.kraken.com/0/public/Ticker?pair=XBTUSDT",
17
- }
 
18
 
19
  def __init__(self, client: httpx.AsyncClient):
20
  self.client = client
21
- self._prices: Dict[str, Optional[float]] = {name: None for name in self.SOURCES}
22
  self._lock = asyncio.Lock()
23
 
24
- async def _fetch_from_source(self, name: str, url: str) -> Optional[float]:
25
  try:
26
- resp = await self.client.get(url, timeout=5)
27
  resp.raise_for_status()
28
  data = resp.json()
29
- if name == "binance":
30
- return float(data['price'])
31
- elif name == "coinbase":
32
- return float(data['data']['amount'])
33
- elif name == "kraken":
34
- # Kraken has a more complex structure
35
- return float(data['result']['XXBTZUSD']['c'][0])
 
36
  return None
 
 
 
 
 
 
37
  except Exception as e:
38
- logger.error(f"❌ Failed to fetch from {name}: {e}")
39
  return None
40
 
41
  async def update_prices_async(self):
42
- tasks = [self._fetch_from_source(name, url) for name, url in self.SOURCES.items()]
43
- results = await asyncio.gather(*tasks)
 
 
44
 
45
  async with self._lock:
46
- for name, price in zip(self.SOURCES.keys(), results):
47
- if price:
48
- self._prices[name] = price
49
 
50
  logger.info(f"βœ… Prices updated: {self._prices}")
51
 
 
1
  """
2
+ A high-availability price fetcher using a decentralized oracle (Pyth)
3
+ and a reliable data aggregator to bypass geoblocking.
4
  """
5
  import asyncio
6
  import logging
 
10
  logger = logging.getLogger(__name__)
11
 
12
  class PriceFetcher:
13
+ # Pyth provides real-time, on-chain prices. We will use their public API.
14
+ # We will fetch BTC/USD.
15
+ PYTH_URL = "https://hermes.pyth.network/v2/updates/price/latest?ids[]=e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415B43"
16
+
17
+ # A reliable aggregator that is not typically geoblocked.
18
+ AGGREGATOR_URL = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd"
19
 
20
  def __init__(self, client: httpx.AsyncClient):
21
  self.client = client
22
+ self._prices: Dict[str, Optional[float]] = {"on_chain_pyth": None, "off_chain_agg": None}
23
  self._lock = asyncio.Lock()
24
 
25
+ async def _fetch_pyth(self) -> Optional[float]:
26
  try:
27
+ resp = await self.client.get(self.PYTH_URL, timeout=5)
28
  resp.raise_for_status()
29
  data = resp.json()
30
+ # The price is in the 'parsed' part of the response
31
+ price_data = data['parsed'][0]['price']
32
+ # Price is given with an exponent, e.g., price=119123, expo=-2 -> 1191.23
33
+ # But for BTC/USD, the expo is -8, and price is in sats. We need to adjust.
34
+ price = int(price_data['price']) / (10 ** abs(int(price_data['expo'])))
35
+ return price
36
+ except Exception as e:
37
+ logger.error(f"❌ Failed to fetch from Pyth: {e}")
38
  return None
39
+
40
+ async def _fetch_aggregator(self) -> Optional[float]:
41
+ try:
42
+ resp = await self.client.get(self.AGGREGATOR_URL, timeout=5)
43
+ resp.raise_for_status()
44
+ return float(resp.json()['bitcoin']['usd'])
45
  except Exception as e:
46
+ logger.error(f"❌ Failed to fetch from Aggregator: {e}")
47
  return None
48
 
49
  async def update_prices_async(self):
50
+ pyth_task = self._fetch_pyth()
51
+ agg_task = self._fetch_aggregator()
52
+
53
+ pyth_price, agg_price = await asyncio.gather(pyth_task, agg_task)
54
 
55
  async with self._lock:
56
+ self._prices["on_chain_pyth"] = pyth_price
57
+ self._prices["off_chain_agg"] = agg_price
 
58
 
59
  logger.info(f"βœ… Prices updated: {self._prices}")
60