luziadev
Official Python SDK for the Luzia cryptocurrency pricing API.
Installation
pip install luziadev# oruv add luziadev
For WebSocket streaming support, install with the optional dependency:
pip install luziadev[websocket]# oruv add luziadev[websocket]
Quick Start
import asynciofrom luziadev import Luziaasync def main():async with Luzia("lz_your_api_key") as client:# List all supported exchangesexchanges = await client.exchanges.list()print(exchanges)# [Exchange(id='binance', name='Binance', status='operational', ...)]# Get a single tickerticker = await client.tickers.get("binance", "BTC/USDT")print(f"BTC/USDT: ${ticker.last}")# Get multiple tickersresult = await client.tickers.list_filtered(exchange="binance",symbols=["BTC/USDT", "ETH/USDT"],)for t in result.tickers:print(f"{t.symbol}: ${t.last}")# Get markets with filtersmarkets = await client.markets.list("binance", quote="USDT")# Get historical OHLCV candlesohlcv = await client.history.get("binance", "BTC/USDT",interval="1h",limit=24,)print(f"Last close: ${ohlcv.candles[-1].close}")asyncio.run(main())
Client Lifecycle
The SDK uses httpx for async HTTP requests. Use the async context manager to ensure connections are properly closed.
# Option 1: Async context manager (recommended)async with Luzia("lz_your_api_key") as client:ticker = await client.tickers.get("binance", "BTC/USDT")# Option 2: Manual lifecycleclient = Luzia("lz_your_api_key")try:ticker = await client.tickers.get("binance", "BTC/USDT")finally:await client.close()
Configuration
Customize the SDK behavior with these configuration options.
from luziadev import Luzia, RetryOptionsclient = Luzia(# Required: Your API keyapi_key="lz_xxxxx",# Optional: Custom base URL (default: https://api.luzia.dev)base_url="http://localhost:3000",# Optional: Request timeout in seconds (default: 30)timeout=10,# Optional: Retry configurationretry=RetryOptions(max_retries=3, # Number of retry attempts (default: 3)initial_delay_ms=1000, # Initial delay before first retry (default: 1000)max_delay_ms=30000, # Maximum delay between retries (default: 30000)backoff_multiplier=2.0, # Multiplier for exponential backoff (default: 2)jitter=True, # Add random jitter to delays (default: True)),)
API Reference
Exchanges
# List all supported exchangesexchanges = await client.exchanges.list()
Tickers
# Get a single tickerticker = await client.tickers.get("binance", "BTC/USDT")# List all tickers for an exchangeresult = await client.tickers.list("binance", limit=50, offset=0)print(f"Found {result.total} tickers")# Get specific tickers across exchangesresult = await client.tickers.list_filtered(exchange="binance", # Optional: filter by exchangesymbols=["BTC/USDT", "ETH/USDT"], # Optional: filter by symbolslimit=100,offset=0,)
Markets
# List markets for an exchangeresult = await client.markets.list("binance",base="BTC", # Optional: filter by base currencyquote="USDT", # Optional: filter by quote currencyactive=True, # Optional: filter by active statuslimit=100,offset=0,)
History (OHLCV Candles)
Fetch historical OHLCV candlestick data for any supported centralized-exchange pair. Useful for charting, backtesting, and performance analysis. DEX markets (Raydium, Orca, Uniswap, Curve) including tokenized stocks and RWAs are not yet covered by this endpoint.
# Get 24h of hourly candles (default)result = await client.history.get("binance", "BTC/USDT")# Specify interval and limitresult = await client.history.get("binance", "ETH/USDT",interval="15m", # "1m" | "5m" | "15m" | "1h" | "1d"limit=96, # Number of candles (max: 500))# Specify a custom time rangeimport timeresult = await client.history.get("binance", "BTC/USDT",interval="1d",start=int((time.time() - 30 * 24 * 3600) * 1000), # 30 days agoend=int(time.time() * 1000),)# Each candle contains OHLCV datafor candle in result.candles:print({"timestamp": candle.timestamp, # Candle open time (RFC 3339)"open": candle.open,"high": candle.high,"low": candle.low,"close": candle.close,"volume": candle.volume, # Base currency volume"quote_volume": candle.quote_volume,"trades": candle.trades, # Number of trades})
| Interval | Description |
|---|---|
| 1m | 1 minute candles |
| 5m | 5 minute candles |
| 15m | 15 minute candles |
| 1h | 1 hour candles |
| 1d | 1 day candles |
| Tier | Max Lookback |
|---|---|
| Free | 30 days |
| Pro | 90 days |
WebSocket Streaming
Stream real-time ticker updates over WebSocket. Requires the websocket extra and a Pro or Enterprise tier API key.
import asynciofrom luziadev import Luziaasync def main():client = Luzia("lz_your_api_key")ws = client.create_websocket()ws.on("connected", lambda data: print(f"Connected! Max subs: {data['limits']['maxSubscriptions']}"))ws.on("ticker", lambda data: print(f"{data['data']['symbol']}: ${data['data']['last']}"))ws.on("error", lambda data: print(f"Error: {data['message']}"))ws.on("reconnecting", lambda data: print(f"Reconnecting (attempt {data['attempt']})..."))await ws.connect()ws.subscribe(["ticker:binance:BTC-USDT", "ticker:binance:ETH-USDT"])# Keep runningtry:await asyncio.sleep(3600)finally:ws.disconnect()await client.close()asyncio.run(main())
WebSocket Configuration
ws = client.create_websocket(auto_reconnect=True, # Auto-reconnect on disconnect (default: True)max_reconnect_attempts=10, # Max reconnect attempts (default: 10)reconnect_delay_ms=1000, # Initial reconnect delay (default: 1000)max_reconnect_delay_ms=30000, # Max reconnect delay (default: 30000)heartbeat_interval_ms=30000, # Heartbeat ping interval (default: 30000))
| Event | Description |
|---|---|
| connected | Connected to the WebSocket server |
| ticker | Received a ticker price update |
| subscribed | Successfully subscribed to a channel |
| unsubscribed | Successfully unsubscribed from a channel |
| error | An error occurred |
| reconnecting | Attempting to reconnect |
| disconnected | Disconnected from the server |
Error Handling
The SDK uses a single LuziaError class with a code property to distinguish error types. Use Python's match statement for clean error handling.
from luziadev import Luzia, LuziaErrorasync with Luzia("lz_your_api_key") as client:try:ticker = await client.tickers.get("invalid", "BTC/USDT")except LuziaError as e:match e.code:case "auth":print("Invalid API key")case "rate_limit":print(f"Rate limited. Retry after {e.retry_after}s")case "not_found":print("Resource not found")case "validation":print(f"Invalid request parameters: {e.details}")case "server":print("Server error (exchange may be temporarily unavailable)")case "network":print(f"Network error: {e}")case "timeout":print(f"Request timed out after {e.timeout_ms}ms")
Checking Error Types
from luziadev import is_luzia_error, is_retryable_errorif is_luzia_error(error):print(f"Luzia error: {error}")if is_retryable_error(error):print("This error can be retried")
| Code | Description |
|---|---|
| auth | Invalid or missing API key |
| rate_limit | Rate limit exceeded |
| not_found | Resource not found (exchange, market, or ticker) |
| validation | Invalid request parameters |
| server | Server error (exchange may be temporarily unavailable) |
| network | Network connectivity issue |
| timeout | Request timed out |
Rate Limit Information
Access rate limit information from the most recent request.
ticker = await client.tickers.get("binance", "BTC/USDT")info = client.rate_limit_infoif info:print(f"Requests remaining: {info.remaining}/{info.limit}")print(f"Resets at: {info.reset}")# Free tier also has daily limitsif info.daily_limit:print(f"Daily remaining: {info.daily_remaining}/{info.daily_limit}")
Automatic Retries
The SDK automatically retries requests on certain errors when retry options are configured.
Retryable Errors
- Rate limit errors (429) - respects
Retry-Afterheader - Timeout errors (408)
- Server errors (500, 502, 503, 504)
- Network errors
Non-Retryable Errors
- Bad request (400)
- Unauthorized (401)
- Forbidden (403)
- Not found (404)
Types
All types are exported from the main package and are fully type-annotated for IDE support.
from luziadev import (Exchange,Ticker,Market,MarketListResponse,OHLCVCandle,OHLCVResponse,TickerListResponse,RateLimitInfo,RetryOptions,RetryContext,LuziaError,ErrorCode,LuziaWebSocket,)
Ready to get started?
Create an account to get your API key and start using the SDK.