Error Handling¶
Exception hierarchy and error handling patterns.
Exception Hierarchy¶
QldataError (base)
├── ConnectionError
│ ├── WebSocketError
│ └── TimeoutError
├── RateLimitError
├── ValidationError
│ ├── SymbolNotFoundError
│ └── InvalidParameterError
├── ConfigurationError
└── DataError
├── EmptyDataError
└── CorruptedDataError
Common Exceptions¶
QldataError¶
Base exception for all qldata errors.
from qldata.errors import QldataError
try:
df = qd.data("INVALID", source="binance").last(1).get()
except QldataError as e:
print(f"qldata error: {e}")
ConnectionError¶
Network and connection issues.
from qldata.errors import ConnectionError
try:
df = qd.data("BTCUSDT", source="binance").last(1).get()
except ConnectionError as e:
print(f"Network error: {e}")
# Retry or use fallback
RateLimitError¶
API rate limit exceeded.
from qldata.errors import RateLimitError
import time
try:
df = qd.data("BTCUSDT", source="binance").last(1).get()
except RateLimitError as e:
print(f"Rate limited. Retry after: {e.retry_after}s")
time.sleep(e.retry_after)
# Retry
ValidationError¶
Data validation failed.
from qldata.errors import ValidationError
try:
df = qd.data("BTCUSDT", source="binance").last(1).get()
except ValidationError as e:
print(f"Validation failed: {e}")
# Check data quality
SymbolNotFoundError¶
Symbol doesn't exist on exchange.
from qldata.errors import SymbolNotFoundError
try:
info = qd.get_symbol_info("INVALIDPAIR", source="binance")
except SymbolNotFoundError as e:
print(f"Symbol not found: {e.symbol}")
Error Handling Patterns¶
Basic Try-Except¶
from qldata.errors import QldataError
try:
df = qd.data("BTCUSDT", source="binance").last(30).get()
except QldataError as e:
print(f"Error: {e}")
df = fallback_data()
Specific Exceptions¶
from qldata.errors import (
ConnectionError,
RateLimitError,
ValidationError,
QldataError
)
try:
df = qd.data("BTCUSDT", source="binance").last(30).get()
except RateLimitError as e:
time.sleep(e.retry_after)
df = qd.data("BTCUSDT", source="binance").last(30).get()
except ConnectionError as e:
logger.error(f"Network error: {e}")
df = load_cached_data()
except ValidationError as e:
logger.warning(f"Validation issue: {e}")
df = qd.data("BTCUSDT", source="binance").last(30).get(validate=False)
except QldataError as e:
logger.error(f"Unexpected error: {e}")
raise
Retry with Backoff¶
from tenacity import retry, stop_after_attempt, wait_exponential
from qldata.errors import ConnectionError, RateLimitError
@retry(
retry=retry_if_exception_type((ConnectionError, RateLimitError)),
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=1, max=10)
)
def fetch_data(symbol, days):
return qd.data(symbol, source="binance").last(days).get()
Fallback Chain¶
def get_data_with_fallback(symbol, days):
"""Try multiple sources with fallback."""
sources = [
("binance", "spot"),
("bybit", "spot"),
]
for source, category in sources:
try:
return qd.data(symbol, source=source, category=category) \
.last(days).resolution("1h").get()
except QldataError as e:
logger.warning(f"Failed {source}: {e}")
continue
raise QldataError(f"All sources failed for {symbol}")
Streaming Error Handling¶
import qldata as qd
def on_error(error):
"""Handle streaming errors."""
if isinstance(error, ConnectionError):
logger.warning("Connection lost, will auto-reconnect")
elif isinstance(error, RateLimitError):
logger.error(f"Rate limited: {error}")
else:
logger.error(f"Streaming error: {error}")
stream = qd.stream(["BTCUSDT"], source="binance") \
.resolution("tick") \
.on_data(process) \
.on_error(on_error) \
.get(start=True)
Logging Errors¶
import logging
from qldata.errors import QldataError
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s"
)
logger = logging.getLogger("trading")
try:
df = qd.data("BTCUSDT", source="binance").last(30).get()
except QldataError as e:
logger.exception("Data fetch failed")
raise
Best Practices¶
1. Catch Specific Exceptions¶
# ✓ Good - handle specific cases
try:
df = fetch_data()
except RateLimitError:
wait_and_retry()
except ConnectionError:
use_cached_data()
# ✗ Avoid - too broad
try:
df = fetch_data()
except Exception:
pass # Swallows all errors
2. Always Log Errors¶
3. Provide Fallbacks¶
4. Use Retry Logic¶
See Also¶
- Configuration - Retry settings
- Resilience - Auto-reconnect