Commit f0f3d96f authored by Your Name's avatar Your Name

Expand crypto price display to show BTC, ETH, USDT, USDC

- Updated UI to show prices for all 4 supported cryptocurrencies
- Each crypto has its own section with color-coded borders
- Shows prices from Coinbase, Binance, and Kraken for each
- Displays average price (applied) for each cryptocurrency
- New API endpoint: GET /api/admin/crypto/prices (returns all 4 cryptos)
- Legacy endpoint /api/admin/crypto/btc-prices still works (redirects)
- Handles stablecoin pricing correctly (USDT/USDC near 1.00)
- Auto-refreshes all prices every 60 seconds
- Single refresh button updates all cryptocurrencies
parent 79a2e226
...@@ -6249,9 +6249,9 @@ async def api_get_encryption_key_status(request: Request): ...@@ -6249,9 +6249,9 @@ async def api_get_encryption_key_status(request: Request):
logger.error(f"Error getting encryption key status: {e}") logger.error(f"Error getting encryption key status: {e}")
return JSONResponse({"error": str(e)}, status_code=500) return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/api/admin/crypto/btc-prices") @app.get("/api/admin/crypto/prices")
async def api_get_btc_prices(request: Request): async def api_get_crypto_prices(request: Request):
"""Get BTC prices from all enabled sources - API endpoint""" """Get crypto prices (BTC, ETH, USDT, USDC) from all enabled sources - API endpoint"""
auth_check = require_admin(request) auth_check = require_admin(request)
if auth_check: if auth_check:
return auth_check return auth_check
...@@ -6276,74 +6276,110 @@ async def api_get_btc_prices(request: Request): ...@@ -6276,74 +6276,110 @@ async def api_get_btc_prices(request: Request):
currency_settings = db.get_currency_settings() currency_settings = db.get_currency_settings()
currency_code = currency_settings.get('currency_code', 'USD') currency_code = currency_settings.get('currency_code', 'USD')
prices = {} result = {}
enabled_prices = []
# Fetch from Coinbase # Fetch prices for each cryptocurrency
if sources.get('coinbase', False): for crypto_symbol, crypto_name in [('BTC', 'btc'), ('ETH', 'eth'), ('USDT', 'usdt'), ('USDC', 'usdc')]:
try: prices = {}
async with httpx.AsyncClient(timeout=10.0) as client: enabled_prices = []
response = await client.get(f'https://api.coinbase.com/v2/prices/BTC-{currency_code}/spot')
if response.status_code == 200: # Fetch from Coinbase
data = response.json() if sources.get('coinbase', False):
price = float(data['data']['amount']) try:
prices['coinbase'] = price async with httpx.AsyncClient(timeout=10.0) as client:
enabled_prices.append(price) response = await client.get(f'https://api.coinbase.com/v2/prices/{crypto_symbol}-{currency_code}/spot')
except Exception as e: if response.status_code == 200:
logger.warning(f"Error fetching Coinbase BTC price: {e}") data = response.json()
price = float(data['data']['amount'])
prices['coinbase'] = price
enabled_prices.append(price)
except Exception as e:
logger.warning(f"Error fetching Coinbase {crypto_symbol} price: {e}")
prices['coinbase'] = None
else:
prices['coinbase'] = None prices['coinbase'] = None
else:
prices['coinbase'] = None # Fetch from Binance
if sources.get('binance', False):
# Fetch from Binance try:
if sources.get('binance', False): async with httpx.AsyncClient(timeout=10.0) as client:
try: # Binance uses USDT pairs for most, but handle stablecoins differently
async with httpx.AsyncClient(timeout=10.0) as client: if crypto_symbol in ['USDT', 'USDC']:
# Binance uses USDT pairs, convert if needed symbol = f'{crypto_symbol}USDT' if crypto_symbol == 'USDC' else 'USDCUSDT'
symbol = 'BTCUSDT' if currency_code == 'USD' else f'BTC{currency_code}' else:
response = await client.get(f'https://api.binance.com/api/v3/ticker/price?symbol={symbol}') symbol = f'{crypto_symbol}USDT' if currency_code == 'USD' else f'{crypto_symbol}{currency_code}'
if response.status_code == 200: response = await client.get(f'https://api.binance.com/api/v3/ticker/price?symbol={symbol}')
data = response.json() if response.status_code == 200:
price = float(data['price']) data = response.json()
prices['binance'] = price price = float(data['price'])
enabled_prices.append(price) prices['binance'] = price
except Exception as e:
logger.warning(f"Error fetching Binance BTC price: {e}")
prices['binance'] = None
else:
prices['binance'] = None
# Fetch from Kraken
if sources.get('kraken', False):
try:
async with httpx.AsyncClient(timeout=10.0) as client:
# Kraken uses XBT instead of BTC
pair = f'XXBTZ{currency_code}' if currency_code == 'USD' else f'XXBTZ{currency_code}'
response = await client.get(f'https://api.kraken.com/0/public/Ticker?pair={pair}')
if response.status_code == 200:
data = response.json()
if 'result' in data and data['result']:
# Get first result key
result_key = list(data['result'].keys())[0]
price = float(data['result'][result_key]['c'][0])
prices['kraken'] = price
enabled_prices.append(price) enabled_prices.append(price)
except Exception as e: except Exception as e:
logger.warning(f"Error fetching Kraken BTC price: {e}") logger.warning(f"Error fetching Binance {crypto_symbol} price: {e}")
prices['binance'] = None
else:
prices['binance'] = None
# Fetch from Kraken
if sources.get('kraken', False):
try:
async with httpx.AsyncClient(timeout=10.0) as client:
# Kraken uses different symbols
if crypto_symbol == 'BTC':
pair = f'XXBTZ{currency_code}'
elif crypto_symbol == 'ETH':
pair = f'XETHZ{currency_code}'
elif crypto_symbol == 'USDT':
pair = f'USDTZ{currency_code}'
elif crypto_symbol == 'USDC':
pair = f'USDCZ{currency_code}'
response = await client.get(f'https://api.kraken.com/0/public/Ticker?pair={pair}')
if response.status_code == 200:
data = response.json()
if 'result' in data and data['result']:
# Get first result key
result_key = list(data['result'].keys())[0]
price = float(data['result'][result_key]['c'][0])
prices['kraken'] = price
enabled_prices.append(price)
except Exception as e:
logger.warning(f"Error fetching Kraken {crypto_symbol} price: {e}")
prices['kraken'] = None
else:
prices['kraken'] = None prices['kraken'] = None
else:
prices['kraken'] = None # Calculate average
if enabled_prices:
# Calculate average prices['average'] = sum(enabled_prices) / len(enabled_prices)
if enabled_prices: else:
prices['average'] = sum(enabled_prices) / len(enabled_prices) prices['average'] = None
else:
prices['average'] = None result[crypto_name] = prices
return JSONResponse(prices) return JSONResponse(result)
except Exception as e: except Exception as e:
logger.error(f"Error getting BTC prices: {e}") logger.error(f"Error getting crypto prices: {e}")
return JSONResponse({"error": str(e)}, status_code=500) return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/api/admin/crypto/btc-prices")
async def api_get_btc_prices(request: Request):
"""Get BTC prices from all enabled sources - API endpoint (legacy, redirects to /prices)"""
auth_check = require_admin(request)
if auth_check:
return auth_check
try:
# Call the new endpoint and extract BTC data
full_response = await api_get_crypto_prices(request)
if isinstance(full_response, JSONResponse):
import json
data = json.loads(full_response.body.decode())
if 'btc' in data:
return JSONResponse(data['btc'])
return full_response
except Exception as e:
logger.error(f"Error getting BTC prices: {e}")
return JSONResponse({"error": str(e)}, status_code=500) return JSONResponse({"error": str(e)}, status_code=500)
@app.post("/api/admin/settings/encryption-key") @app.post("/api/admin/settings/encryption-key")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment