2025-12-22 15:42:59 +01:00
|
|
|
"""Bitfinex price fetcher for BTC/EUR pair."""
|
|
|
|
|
|
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
|
|
|
|
|
|
import httpx
|
|
|
|
|
|
|
|
|
|
BITFINEX_TICKER_URL = "https://api-pub.bitfinex.com/v2/ticker/tBTCEUR"
|
|
|
|
|
LAST_PRICE_INDEX = 6
|
|
|
|
|
|
2025-12-22 16:06:56 +01:00
|
|
|
# Constants for price history records
|
|
|
|
|
SOURCE_BITFINEX = "bitfinex"
|
|
|
|
|
PAIR_BTC_EUR = "BTC/EUR"
|
|
|
|
|
|
2025-12-22 15:42:59 +01:00
|
|
|
|
|
|
|
|
async def fetch_btc_eur_price() -> tuple[float, datetime]:
|
|
|
|
|
"""
|
|
|
|
|
Fetch the current BTC/EUR price from Bitfinex.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Tuple of (price, timestamp) where timestamp is the current UTC time.
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
httpx.HTTPStatusError: If the API returns a non-2xx status code.
|
|
|
|
|
httpx.RequestError: If a network error occurs.
|
|
|
|
|
ValueError: If the response format is unexpected.
|
|
|
|
|
"""
|
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
|
|
|
response = await client.get(BITFINEX_TICKER_URL)
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
|
|
|
|
# Bitfinex ticker response is an array:
|
|
|
|
|
# [BID, BID_SIZE, ASK, ASK_SIZE, DAILY_CHANGE, DAILY_CHANGE_RELATIVE,
|
|
|
|
|
# LAST_PRICE, VOLUME, HIGH, LOW]
|
|
|
|
|
if not isinstance(data, list) or len(data) <= LAST_PRICE_INDEX:
|
|
|
|
|
raise ValueError(f"Unexpected response format: {data}")
|
|
|
|
|
|
|
|
|
|
price = float(data[LAST_PRICE_INDEX])
|
|
|
|
|
timestamp = datetime.now(UTC)
|
|
|
|
|
|
|
|
|
|
return price, timestamp
|