Error handling provides a comprehensive hierarchy of exception types for different failure scenarios, enabling precise error handling and recovery strategies in cryptocurrency trading applications.
CCXT provides a structured error hierarchy with specific exception types for different categories of failures.
// Base error classes
class BaseError extends Error {
constructor(message?: string);
}
class ExchangeError extends BaseError {
constructor(message?: string);
}
class OperationFailed extends BaseError {
constructor(message?: string);
}
// Authentication and authorization errors
class AuthenticationError extends ExchangeError {
constructor(message?: string);
}
class PermissionDenied extends ExchangeError {
constructor(message?: string);
}
class AccountNotEnabled extends ExchangeError {
constructor(message?: string);
}
class AccountSuspended extends ExchangeError {
constructor(message?: string);
}
// Request validation errors
class ArgumentsRequired extends ExchangeError {
constructor(message?: string);
}
class BadRequest extends ExchangeError {
constructor(message?: string);
}
class BadSymbol extends BadRequest {
constructor(message?: string);
}
class InvalidAddress extends ExchangeError {
constructor(message?: string);
}
class AddressPending extends ExchangeError {
constructor(message?: string);
}
// Order and trading errors
class InvalidOrder extends ExchangeError {
constructor(message?: string);
}
class OrderNotFound extends ExchangeError {
constructor(message?: string);
}
class OrderNotCached extends ExchangeError {
constructor(message?: string);
}
class OrderImmediatelyFillable extends ExchangeError {
constructor(message?: string);
}
class OrderNotFillable extends ExchangeError {
constructor(message?: string);
}
class DuplicateOrderId extends ExchangeError {
constructor(message?: string);
}
class ContractUnavailable extends ExchangeError {
constructor(message?: string);
}
// Operation status errors
class OperationRejected extends ExchangeError {
constructor(message?: string);
}
class NoChange extends ExchangeError {
constructor(message?: string);
}
class MarginModeAlreadySet extends ExchangeError {
constructor(message?: string);
}
class MarketClosed extends ExchangeError {
constructor(message?: string);
}
class ManualInteractionNeeded extends ExchangeError {
constructor(message?: string);
}
class RestrictedLocation extends ExchangeError {
constructor(message?: string);
}
// Financial errors
class InsufficientFunds extends ExchangeError {
constructor(message?: string);
}
// Network and connectivity errors
class NetworkError extends BaseError {
constructor(message?: string);
}
class DDoSProtection extends NetworkError {
constructor(message?: string);
}
class RateLimitExceeded extends NetworkError {
constructor(message?: string);
}
class ExchangeNotAvailable extends NetworkError {
constructor(message?: string);
}
class OnMaintenance extends NetworkError {
constructor(message?: string);
}
class InvalidNonce extends NetworkError {
constructor(message?: string);
}
class ChecksumError extends NetworkError {
constructor(message?: string);
}
class RequestTimeout extends NetworkError {
constructor(message?: string);
}
// Response handling errors
class BadResponse extends ExchangeError {
constructor(message?: string);
}
class NullResponse extends BadResponse {
constructor(message?: string);
}
// Other errors
class NotSupported extends ExchangeError {
constructor(message?: string);
}
class InvalidProxySettings extends ExchangeError {
constructor(message?: string);
}
class ExchangeClosedByUser extends ExchangeError {
constructor(message?: string);
}
class CancelPending extends ExchangeError {
constructor(message?: string);
}
class UnsubscribeError extends ExchangeError {
constructor(message?: string);
}Common patterns for handling different types of errors in trading applications.
Usage Examples:
// Basic error handling
try {
const balance = await exchange.fetchBalance();
console.log('Balance:', balance);
} catch (error) {
if (error instanceof ccxt.AuthenticationError) {
console.error('Authentication failed - check API credentials');
} else if (error instanceof ccxt.NetworkError) {
console.error('Network error - check connection');
} else if (error instanceof ccxt.ExchangeError) {
console.error('Exchange error:', error.message);
} else {
console.error('Unexpected error:', error.message);
}
}
// Comprehensive error handling for order creation
async function createOrderWithErrorHandling(symbol: string, side: string, amount: number, price?: number) {
try {
const order = await exchange.createOrder(symbol, 'limit', side, amount, price);
console.log(`Order created successfully: ${order.id}`);
return order;
} catch (error) {
if (error instanceof ccxt.InsufficientFunds) {
console.error('Insufficient funds to place order');
throw new Error('Not enough balance');
} else if (error instanceof ccxt.InvalidOrder) {
console.error('Invalid order parameters:', error.message);
throw new Error('Order validation failed');
} else if (error instanceof ccxt.BadSymbol) {
console.error(`Invalid trading symbol: ${symbol}`);
throw new Error('Invalid symbol');
} else if (error instanceof ccxt.MarketClosed) {
console.error(`Market ${symbol} is currently closed`);
throw new Error('Market closed');
} else if (error instanceof ccxt.RateLimitExceeded) {
console.error('Rate limit exceeded, waiting before retry...');
await new Promise(resolve => setTimeout(resolve, 1000));
throw new Error('Rate limited');
} else if (error instanceof ccxt.AuthenticationError) {
console.error('Authentication failed - check API credentials');
throw new Error('Authentication failed');
} else if (error instanceof ccxt.PermissionDenied) {
console.error('Permission denied - check API key permissions');
throw new Error('Permission denied');
} else if (error instanceof ccxt.NetworkError) {
console.error('Network error - check connection');
throw new Error('Network error');
} else {
console.error('Unexpected error:', error.message);
throw error;
}
}
}
// Error handling with retry logic
async function fetchWithRetry<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
retryDelay: number = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
// Don't retry for certain error types
if (error instanceof ccxt.AuthenticationError ||
error instanceof ccxt.PermissionDenied ||
error instanceof ccxt.BadSymbol ||
error instanceof ccxt.InvalidOrder) {
throw error;
}
// Retry for network errors and rate limits
if (error instanceof ccxt.NetworkError ||
error instanceof ccxt.RateLimitExceeded ||
error instanceof ccxt.ExchangeNotAvailable) {
console.log(`Attempt ${attempt} failed, retrying in ${retryDelay}ms...`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
retryDelay *= 2; // Exponential backoff
} else {
throw error;
}
}
}
throw lastError!;
}
// Usage with retry
const balanceWithRetry = await fetchWithRetry(
() => exchange.fetchBalance(),
3, // Max 3 retries
1000 // Initial 1 second delay
);
// Error handling for WebSocket operations
async function watchWithErrorHandling(symbol: string) {
while (true) {
try {
const ticker = await exchange.watchTicker(symbol);
console.log(`${symbol}: $${ticker.last}`);
} catch (error) {
if (error instanceof ccxt.NetworkError) {
console.error('WebSocket network error, reconnecting...');
await new Promise(resolve => setTimeout(resolve, 5000));
} else if (error instanceof ccxt.UnsubscribeError) {
console.error('Unsubscribe error, resubscribing...');
await new Promise(resolve => setTimeout(resolve, 1000));
} else if (error instanceof ccxt.ExchangeNotAvailable) {
console.error('Exchange unavailable, waiting...');
await new Promise(resolve => setTimeout(resolve, 10000));
} else {
console.error('Unexpected WebSocket error:', error.message);
break;
}
}
}
}
// Advanced error handling with logging and alerting
class ErrorHandler {
private errorCounts = new Map<string, number>();
private lastErrors = new Map<string, number>();
async handleError(error: Error, context: string): Promise<boolean> {
const errorType = error.constructor.name;
const currentTime = Date.now();
// Log error
console.error(`[${context}] ${errorType}: ${error.message}`);
// Track error frequency
const count = this.errorCounts.get(errorType) || 0;
this.errorCounts.set(errorType, count + 1);
this.lastErrors.set(errorType, currentTime);
// Check if we should retry
if (this.shouldRetry(error)) {
const delay = this.getRetryDelay(errorType, count);
console.log(`Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
return true; // Should retry
}
// Alert on critical errors
if (this.isCriticalError(error)) {
await this.sendAlert(error, context);
}
return false; // Should not retry
}
private shouldRetry(error: Error): boolean {
return error instanceof ccxt.NetworkError ||
error instanceof ccxt.RateLimitExceeded ||
error instanceof ccxt.ExchangeNotAvailable ||
error instanceof ccxt.RequestTimeout;
}
private getRetryDelay(errorType: string, attempts: number): number {
const baseDelay = 1000;
const maxDelay = 30000;
// Exponential backoff with jitter
const delay = Math.min(baseDelay * Math.pow(2, attempts), maxDelay);
const jitter = Math.random() * 0.1 * delay;
return Math.floor(delay + jitter);
}
private isCriticalError(error: Error): boolean {
return error instanceof ccxt.AuthenticationError ||
error instanceof ccxt.AccountSuspended ||
error instanceof ccxt.ExchangeClosedByUser;
}
private async sendAlert(error: Error, context: string): Promise<void> {
// Implement alerting logic (email, webhook, etc.)
console.error(`CRITICAL ERROR in ${context}: ${error.message}`);
}
getErrorSummary(): { [errorType: string]: number } {
return Object.fromEntries(this.errorCounts);
}
resetErrorCounts(): void {
this.errorCounts.clear();
this.lastErrors.clear();
}
}
// Usage
const errorHandler = new ErrorHandler();
async function safeOperation() {
let retryCount = 0;
const maxRetries = 3;
while (retryCount < maxRetries) {
try {
const result = await exchange.fetchTicker('BTC/USDT');
return result;
} catch (error) {
const shouldRetry = await errorHandler.handleError(error, 'fetchTicker');
if (shouldRetry && retryCount < maxRetries - 1) {
retryCount++;
continue;
} else {
throw error;
}
}
}
}
// Periodic error summary
setInterval(() => {
const summary = errorHandler.getErrorSummary();
if (Object.keys(summary).length > 0) {
console.log('Error summary:', summary);
}
}, 60000); // Every minute