ceb-sdk
v1.1.4
Published
Official TypeScript/Node.js SDK for CEB (Crypto Exchange Bot) - Unified API for multi-exchange trading, market data, and arbitrage
Maintainers
Readme
CEB SDK
Official TypeScript/Node.js SDK for CEB (Crypto Exchange Bot) - A unified API platform for multi-exchange trading, market data, and arbitrage.
Features
- ✅ Market Data - Real-time prices, order books, and trades from multiple exchanges
- ✅ Multi-Exchange Support - Binance, KuCoin, Gate.io, MEXC
- ✅ Live Trading - Place and manage orders across exchanges
- ✅ Portfolio Management - Aggregate holdings and analytics
- ✅ Arbitrage Detection - Identify profitable opportunities
- ✅ WebSocket Streaming - Real-time market data updates
- ✅ TypeScript Support - Full type definitions included
- ✅ Easy Integration - Simple, intuitive API
Installation
npm install ceb-sdk
# or
yarn add ceb-sdk
# or
pnpm add ceb-sdkQuick Start
import CEBSDK from "ceb-sdk";
// Initialize SDK
const ceb = new CEBSDK({
apiKey: "ceb_your_api_key_here",
baseUrl: "https://api.ceb.io/api/v1", // Optional
});
// Get ticker price
const ticker = await ceb.getTicker("BTC-USDT", "binance");
console.log(`BTC Price: $${ticker.price}`);
// Compare prices across exchanges
const comparison = await ceb.comparePrices("BTC-USDT");
if (comparison.arbitrageOpportunity.exists) {
console.log("Arbitrage opportunity found!");
}Configuration
interface CEBConfig {
apiKey: string; // Required: Your CEB API key
baseUrl?: string; // Optional: API base URL (defaults to http://localhost:5000/api/v1)
timeout?: number; // Optional: Request timeout in ms (default: 30000)
}Using Custom Base URL
You can configure the SDK to use a different base URL (e.g., for production or different environments):
// Local development (default)
const ceb = new CEBSDK({
apiKey: "ceb_your_api_key",
});
// Production
const ceb = new CEBSDK({
apiKey: "ceb_your_api_key",
baseUrl: "https://api.ceb.io/api/v1",
});
// Staging
const ceb = new CEBSDK({
apiKey: "ceb_your_api_key",
baseUrl: "https://staging.ceb.io/api/v1",
timeout: 60000, // Custom timeout
});
// Get the current base URL
console.log(ceb.getBaseUrl()); // "https://api.ceb.io/api/v1"
// Get the WebSocket URL
console.log(ceb.getWebSocketUrl()); // "wss://api.ceb.io/ws"Authentication
CEB uses API Key authentication for all operations. Your API key is tied to your user account and provides access to:
- Market data (ticker prices, order books, trades)
- Trading operations (place orders, manage positions)
- Portfolio management (balances, analytics)
- Account management (credentials, subscriptions)
Getting an API Key
- Register an account on the CEB platform
- Generate an API key from your dashboard:
# Register an account
curl -X POST https://api.ceb.io/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"secure123","firstName":"John","lastName":"Doe"}'
# Login to get JWT token (for dashboard access)
curl -X POST https://api.ceb.io/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"secure123"}'
# Generate API key (dashboard uses JWT, but SDK uses API key only)
curl -X POST https://api.ceb.io/api/v1/keys/generate \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{"name":"My Trading Bot","rateLimit":1000}'
# Response
{
"message": "API key generated successfully. Store this key securely - you won't see it again!",
"data": {
"key": "ceb_abc123...",
"keyId": 1,
"name": "My Trading Bot",
"rateLimit": 1000
}
}- Use your API key with the SDK:
const ceb = new CEBSDK({ apiKey: "ceb_abc123..." });
// Now you can access all features with just the API key!Important:
- Keep your API key secure - treat it like a password
- API keys are long-lived and don't expire (unlike JWT tokens)
- You can regenerate API keys anytime from your dashboard
- API keys have rate limits to prevent abuse
API Methods
Market Data
Get Ticker Price
// From all exchanges
const tickers = await ceb.getTicker("BTC-USDT");
// From specific exchange
const ticker = await ceb.getTicker("BTC-USDT", "binance");Get Order Book
const orderBook = await ceb.getOrderBook("BTC-USDT", "binance", 20);
console.log("Bids:", orderBook.bids);
console.log("Asks:", orderBook.asks);Get Recent Trades
const trades = await ceb.getRecentTrades("BTC-USDT", "binance", 50);Compare Prices
const comparison = await ceb.comparePrices("BTC-USDT");
console.log("Best Bid:", comparison.bestBid);
console.log("Best Ask:", comparison.bestAsk);
console.log("Arbitrage:", comparison.arbitrageOpportunity);Get Symbols
const symbols = await ceb.getSymbols("binance");List Exchanges
const exchanges = await ceb.getExchanges();Trading
Add Exchange Credentials
// Add your exchange API credentials
const credential = await ceb.addCredential({
exchangeName: "binance",
label: "My Binance Account",
apiKey: "your_binance_api_key",
apiSecret: "your_binance_api_secret",
});
// The returned credential object contains an ID that you'll use for trading
console.log(credential.id); // e.g., 1, 2, 3...Place Order
// Use the credentialId from the credential you added above
const order = await ceb.placeOrder({
credentialId: credential.id, // Use the ID from addCredential()
exchangeName: "binance",
symbol: "BTC-USDT",
side: "buy",
type: "limit",
quantity: "0.001",
price: "50000.00",
timeInForce: "GTC",
});
// Order response contains:
console.log(order.id); // Internal order ID
console.log(order.exchangeOrderId); // Exchange's order ID
console.log(order.status); // "pending" | "open" | "filled" | "cancelled" | "failed"
console.log(order.quantity); // Requested quantity: "0.001"
console.log(order.filledQuantity); // Actually filled: "0.001" (0 if not filled yet)
console.log(order.price); // Order price (if limit order)
console.log(order.fee); // Trading fee (if filled)
console.log(order.feeCurrency); // Fee currency (e.g., "BNB", "USDT")
console.log(order.createdAt); // Order creation timestamp
console.log(order.updatedAt); // Last update timestamp⚠️ CRITICAL: Verifying Order Fulfillment
When dealing with real money, you must verify that your order is actually filled:
// ❌ DON'T assume the order is filled immediately
const order = await ceb.placeOrder({ /* ... */ });
// Order might be "open" or "pending", not "filled"!
// ✅ DO: Check order status after placing
if (order.status === "filled") {
console.log("✅ Order filled!");
console.log(`Bought ${order.filledQuantity} at ${order.price}`);
console.log(`Fee: ${order.fee} ${order.feeCurrency}`);
} else if (order.status === "open" || order.status === "pending") {
console.log("⏳ Order placed but not filled yet. Status:", order.status);
// For limit orders, you need to wait for price to be met
// Sync the order status periodically to check if it's filled
const updated = await ceb.syncOrder(order.id);
if (updated.status === "filled") {
console.log("✅ Order filled!");
}
} else if (order.status === "failed" || order.status === "cancelled") {
console.log("❌ Order was not executed. Status:", order.status);
}
// ✅ DO: Use market orders for immediate execution (when you need certainty)
const marketOrder = await ceb.placeOrder({
credentialId: credential.id,
exchangeName: "binance",
symbol: "BTC-USDT",
side: "buy",
type: "market", // Market orders execute immediately at current price
quantity: "0.001",
});
// Market orders typically have status "filled" immediatelyOrder Status Lifecycle:
pending- Order submitted but not yet confirmed by exchangeopen- Order is active on exchange, waiting to be filled (common for limit orders)filled- Order completely executed ✅ YOUR COINS ARE BOUGHTpartial- Order partially filled (some coins bought, but not all)cancelled- Order was cancelled before fillingfailed- Order rejected by exchange (insufficient balance, invalid parameters, etc.)
Get Orders
const orders = await ceb.getOrders({ status: "open", limit: 20 });Cancel Order
const cancelled = await ceb.cancelOrder(orderId);Sync Order Status
Essential for verifying order fulfillment! This fetches the latest order status from the exchange.
// Sync order status with the exchange to get real-time updates
const updated = await ceb.syncOrder(order.id);
console.log(updated.status); // Current status from exchange
console.log(updated.filledQuantity); // How much has been filled
console.log(updated.fee); // Trading fee (if order filled)
// Use this for limit orders that may take time to fill
const checkOrderFilled = async (orderId: number, maxAttempts = 10) => {
for (let i = 0; i < maxAttempts; i++) {
const order = await ceb.syncOrder(orderId);
if (order.status === "filled") {
console.log("✅ Order filled successfully!");
console.log(`Bought ${order.filledQuantity} at actual price`);
return order;
} else if (order.status === "failed" || order.status === "cancelled") {
console.log("❌ Order not executed:", order.status);
return order;
}
console.log(`⏳ Order still ${order.status}, checking again in 5s...`);
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
}
console.log("⚠️ Order not filled within timeout period");
return await ceb.syncOrder(orderId);
};
// Usage
const filledOrder = await checkOrderFilled(order.id);💰 Best Practices for Production Trading
When dealing with real money, always follow these guidelines:
1. Always Verify Order Status
// ✅ GOOD: Verify before proceeding
const order = await ceb.placeOrder({ /* ... */ });
if (order.status !== "filled") {
// Handle unfilled order appropriately
await checkOrderFilled(order.id);
}
// ❌ BAD: Assuming order is filled
const order = await ceb.placeOrder({ /* ... */ });
// Proceeding without checking status2. Use Market Orders for Immediate Execution
// When you need certainty that coins are bought immediately
const order = await ceb.placeOrder({
type: "market", // Executes at current market price
// ...
});3. Implement Proper Error Handling
try {
const order = await ceb.placeOrder({ /* ... */ });
if (order.status === "filled") {
// ✅ Success - update your database
await yourDB.recordPurchase({
amount: order.filledQuantity,
price: order.price,
fee: order.fee,
orderId: order.id,
});
} else {
// ⚠️ Order not filled - handle appropriately
console.error("Order not filled:", order.status);
}
} catch (error) {
// ❌ Order failed completely
console.error("Order placement failed:", error);
// Notify user, log error, etc.
}4. Monitor Your Balances (⚠️ SPOT Wallet Only)
// ⚠️ CRITICAL: System only uses SPOT wallet for trading
// Funds in Funding/Earning wallets are NOT accessible for trading
// Before placing order, verify you have sufficient balance in SPOT wallet
const balances = await ceb.getCredentialBalances(credential.id);
const usdtBalance = balances.find(b => b.asset === "USDT");
if (!usdtBalance || parseFloat(usdtBalance.free) < requiredAmount) {
throw new Error(`Insufficient balance in SPOT wallet. Available: ${usdtBalance?.free || "0"}, Required: ${requiredAmount}`);
}
// ⚠️ If funds are in Funding/Earning wallet, transfer to Spot wallet first
// (Use exchange's native API - not implemented in CEB SDK yet)
// After order is filled, sync balances to confirm
await ceb.syncBalances();
const updatedBalances = await ceb.getCredentialBalances(credential.id);5. Keep Transaction Records
const order = await ceb.placeOrder({ /* ... */ });
// Store in your database immediately
await yourDB.transactions.create({
orderId: order.id,
exchangeOrderId: order.exchangeOrderId,
status: order.status,
amount: order.quantity,
filledAmount: order.filledQuantity,
price: order.price,
fee: order.fee,
timestamp: order.createdAt,
// ... other fields
});
// Update when order fills
if (order.status !== "filled") {
const filled = await checkOrderFilled(order.id);
await yourDB.transactions.update({
orderId: filled.id,
status: filled.status,
filledAmount: filled.filledQuantity,
actualFee: filled.fee,
});
}6. Test with Small Amounts First
// Start with minimal amounts to test your integration
const testOrder = await ceb.placeOrder({
quantity: "0.00001", // Very small amount for testing
// ...
});Balances
Get All Balances
const balances = await ceb.getBalances();Get Credential Balances
// Get balances for a specific credential (use credential.id from addCredential)
const balances = await ceb.getCredentialBalances(credential.id);Sync Balances
const updated = await ceb.syncBalances();💰 CRITICAL: Wallet Types & Automatic Fund Management
Many exchanges (like Binance, KuCoin) have multiple wallet types:
- Spot Wallet - For trading (buying/selling coins)
- Funding Wallet - For deposits/withdrawals
- Earning Wallet - For savings products, staking rewards
- Futures Wallet - For derivatives trading
- Margin Wallet - For margin trading
✅ AUTOMATIC TRANSFER: System now auto-transfers funds to Spot wallet!
For Binance, the CEB system now automatically consolidates funds from Funding and Earn wallets to Spot wallet when placing orders. If your Spot wallet has insufficient balance, the system will:
- Check your Funding wallet for available funds
- Transfer needed amount to Spot wallet
- Check your Earn wallet if still insufficient
- Transfer remaining needed amount to Spot wallet
- Then place your order
// The system automatically handles wallet transfers!
const order = await ceb.placeOrder({
credentialId: credential.id,
exchangeName: "binance",
symbol: "BTC-USDT",
side: "buy",
type: "market",
quantity: "0.001",
});
// ✅ Works even if USDT is in Funding/Earning wallet
// System automatically transfers to Spot before placing orderHow It Works:
// Behind the scenes, CEB does this automatically:
// 1. Checks Spot wallet balance
// 2. If insufficient, checks Funding wallet
// 3. Transfers from Funding → Spot (if available)
// 4. If still insufficient, checks Earn wallet
// 5. Transfers from Earn → Spot (if available)
// 6. Places the order with consolidated funds
// You see this in logs:
// 🔄 Checking wallets for USDT (need: 100)...
// ⚠️ Spot wallet short by 50 USDT
// 💸 Transferring 50 USDT from Funding to Spot...
// ✅ Transferred 50 USDT from Funding wallet
// ✅ Order placed successfully⚠️ Requirements:
- API Key Permission: Your Binance API key MUST have "Universal Transfer" permission enabled
- Exchange Support: Currently only works for Binance (other exchanges coming soon)
- Wallet Balance: You must have sufficient total balance across Spot, Funding, and Earn wallets
Checking All Wallet Balances:
// Check balances across ALL wallet types
const allBalances = await ceb.getAllWalletBalances(credential.id, "USDT");
allBalances.forEach(balance => {
console.log(`${balance.walletType}: ${balance.free} ${balance.asset}`);
});
// Example output:
// SPOT: 10.50 USDT
// FUNDING: 50.00 USDT
// EARN: 100.00 USDT
// Total available: 160.50 USDTManual Transfer (if needed):
You can also manually transfer funds between wallets:
const result = await ceb.transferBetweenWallets({
credentialId: credential.id,
exchangeName: "binance",
asset: "USDT",
amount: "50.00",
fromWallet: "FUNDING",
toWallet: "SPOT",
});
console.log(result.status); // "success" or "failed"
console.log(result.transactionId); // Transaction ID from exchangeBest Practices:
- Enable Universal Transfer permission on your Binance API key
- Check total balance across all wallets to ensure sufficient funds
- Monitor transfer logs for auto-consolidation activity
- Keep some funds in Spot for faster order execution (avoids transfer delay)
⚠️ CRITICAL: LD-Prefixed Assets (LDUSDT, LDBTC, etc.)
Binance Earn creates "LD" versions of assets that CANNOT be used for trading:
LDUSDT= USDT locked in Binance Earn (Flexible Savings, Staking, etc.)LDBTC= BTC locked in Binance Earn- Similar for
LDETH,LDBNB, etc.
Problem:
// ❌ This will FAIL if you only have LDUSDT
await ceb.placeOrder({
credentialId,
exchangeName: "binance",
symbol: "BTC-USDT",
side: "buy",
quantity: "0.001"
});
// Error: "Insufficient balance. You have 100 LDUSDT (locked in Binance Earn)"Solutions:
Option 1: Redeem via Binance Website/App (Recommended)
- Go to Binance Earn
- Redeem your Flexible Savings/Staking
- Wait for redemption (usually instant for Flexible)
- LDUSDT → USDT (now usable for trading)
Option 2: Check LD Assets Before Trading (Easy Way!)
// ✅ NEW: Use the built-in helper method
const check = await ceb.checkLockedAssets(credentialId, "USDT");
console.log(check.message);
// Output: "USDT: 10.50 available for trading. 119.85 LDUSDT locked in Binance Earn (redeem to use for trading)"
if (check.hasLockedAssets) {
// Show user-friendly warning
alert(`You have ${check.lockedAmount} LDUSDT locked in Binance Earn.
Redeem it via Binance app to use ${check.lockedAmount} USDT for trading.
Currently tradable: ${check.tradableAmount} USDT`);
}
// Or manual way:
const balances = await ceb.getCredentialBalances(credentialId);
const ldUsdt = balances.find(b => b.asset === "LDUSDT");
const usdt = balances.find(b => b.asset === "USDT");
if (ldUsdt && parseFloat(ldUsdt.free) > 0) {
alert(`You have ${ldUsdt.free} USDT locked in Binance Earn.`);
}- Option 3: Prevent LD Assets in Earn Products
- Don't subscribe assets to Binance Earn if you need them for frequent trading
- Keep trading funds in Spot or Funding wallets only
Why CEB Cannot Auto-Redeem:
- Redeeming from Binance Earn requires separate API endpoints
- Some products have lock-up periods (not instant redemption)
- Users may not want automatic redemption of earning products
- Better UX: Let users decide when to redeem
Detection: The system will automatically detect LD assets and show helpful error messages:
❌ Insufficient balance. Need 100 USDT, have 10 in Spot.
Note: You have 90 LDUSDT (locked in Binance Earn).
Redeem it to USDT via Binance website/app to use for trading.// Best practice: Check total balance before trading
const allBalances = await ceb.getAllWalletBalances(credential.id, "USDT");
const totalUSDT = allBalances.reduce((sum, b) =>
sum + parseFloat(b.free), 0
);
if (totalUSDT < requiredAmount) {
throw new Error(`Insufficient balance across all wallets. Have ${totalUSDT}, need ${requiredAmount}`);
}🔴 Production Warning:
When dealing with real money:
- ✅ Ensure "Universal Transfer" permission is enabled on your API key
- ✅ Test with small amounts first to verify auto-transfer works
- ✅ Monitor logs for transfer activity
- ✅ Keep emergency funds in Spot wallet for critical orders
- ⚠️ Auto-transfer may add 1-2 seconds to order placement time
Portfolio
Get Portfolio Overview
const portfolio = await ceb.getPortfolio();
console.log(`Total Value: $${portfolio.totalValue}`);
console.log("Assets:", portfolio.assets);
console.log("Exchanges:", portfolio.exchanges);Arbitrage
Scan for Opportunities
const opportunities = await ceb.scanArbitrage(1); // Min 1% profit
opportunities.forEach((opp) => {
console.log(`${opp.symbol}: ${opp.profitPercent}% profit`);
console.log(`Buy from ${opp.buyExchange} at ${opp.buyPrice}`);
console.log(`Sell to ${opp.sellExchange} at ${opp.sellPrice}`);
});Get Arbitrage for Symbol
const opportunity = await ceb.getArbitrageForSymbol("BTC-USDT");
if (opportunity) {
console.log(`Profit: ${opportunity.profitPercent}%`);
}Analytics
Get Usage Overview
const usage = await ceb.getUsageOverview();
console.log(`Total Requests: ${usage.totalRequests}`);
console.log(`Success Rate: ${usage.successRate}%`);Get Daily Usage
const daily = await ceb.getDailyUsage();Get Top Endpoints
const endpoints = await ceb.getTopEndpoints();Get Trading Analytics
const analytics = await ceb.getTradingAnalytics();
console.log(`Total Orders: ${analytics.totalOrders}`);
console.log(`Total Volume: $${analytics.totalVolume}`);
console.log(`Success Rate: ${analytics.successRate}%`);Billing
Get Subscription
const subscription = await ceb.getSubscription();
console.log(`Tier: ${subscription.tierId}`);
console.log("Usage:", subscription.currentUsage);
console.log("Limits:", subscription.usageLimit);Get Subscription Tiers
const tiers = await ceb.getSubscriptionTiers();Upgrade Subscription
const upgrade = await ceb.upgradeSubscription("pro");
console.log("Payment URL:", upgrade.paymentUrl);WebSocket Streaming
Basic Connection
// Create WebSocket connection
const ws = ceb.createWebSocket();
ws.on("open", () => {
console.log("Connected!");
// Subscribe to ticker
CEBSDK.subscribe(ws, "ticker", "binance", "BTC-USDT");
});
ws.on("message", (data: Buffer) => {
const message = JSON.parse(data.toString());
console.log(message);
});
ws.on("error", (error) => {
console.error("WebSocket error:", error);
});
ws.on("close", () => {
console.log("Disconnected");
});Subscribe to Channels
// Subscribe to ticker from specific exchange
CEBSDK.subscribe(ws, "ticker", "binance", "BTC-USDT");
// Subscribe to ticker from all exchanges
CEBSDK.subscribe(ws, "ticker", "all", "BTC-USDT");
// Subscribe to order book
CEBSDK.subscribe(ws, "orderbook", "kucoin", "ETH-USDT");
// Subscribe to trades
CEBSDK.subscribe(ws, "trades", "binance", "BTC-USDT");Unsubscribe
CEBSDK.unsubscribe(ws, "ticker", "binance", "BTC-USDT");Helper Functions
Format Price
const formatted = CEBSDK.formatPrice("50123.456789", 2);
// Output: "50123.46"Format Percentage
const formatted = CEBSDK.formatPercent("5.67890");
// Output: "5.68%"Check Order Status
if (CEBSDK.isOrderCompleted(order)) {
console.log("Order filled!");
}
if (CEBSDK.isOrderActive(order)) {
console.log("Order is pending or open");
}
const fillPercent = CEBSDK.getOrderFillPercent(order);
console.log(`Order ${fillPercent}% filled`);Check Arbitrage Profitability
if (CEBSDK.isProfitableArbitrage(opportunity, 2)) {
console.log("Profit is above 2%!");
}Error Handling
try {
const ticker = await ceb.getTicker("BTC-USDT", "binance");
} catch (error) {
console.error("Error:", error.message);
// Error messages are descriptive:
// - "Invalid API key"
// - "Exchange not available"
// - "Symbol not found"
// - etc.
}TypeScript Support
Full TypeScript definitions are included:
import CEBSDK, {
TickerData,
OrderBookData,
TradeData,
Order,
Balance,
Portfolio,
ArbitrageOpportunity,
TradingAnalytics,
} from "ceb-sdk";Examples
See the /examples directory for complete examples:
basic-usage.ts- Market data and trading exampleswebsocket-example.ts- Real-time data streaming
Rate Limits
CEB enforces rate limits based on your subscription tier:
- Free: 100 requests/minute
- Starter: 500 requests/minute
- Pro: 1000 requests/minute
- Enterprise: Custom limits
Exceeding your rate limit returns a 429 Too Many Requests error.
Supported Exchanges
| Exchange | Status | Trading | WebSocket | |----------|--------|---------|-----------| | Binance | ✅ Active | ✅ Yes | ✅ Yes | | KuCoin | ✅ Active | ✅ Yes | ✅ Yes | | Gate.io | ✅ Active | ✅ Yes | ✅ Yes | | MEXC | ✅ Active | ✅ Yes | ✅ Yes |
Best Practices
1. Store Credentials Securely
// Use environment variables
const ceb = new CEBSDK({
apiKey: process.env.CEB_API_KEY!,
});2. Handle Errors Gracefully
try {
const ticker = await ceb.getTicker("BTC-USDT");
} catch (error) {
console.error("Failed to fetch ticker:", error.message);
// Implement retry logic or fallback
}3. Use WebSocket for Real-Time Data
For continuous price monitoring, use WebSocket instead of polling the REST API.
4. Cache Market Data
Implement caching to reduce API calls and improve performance.
5. Monitor Rate Limits
Track your API usage and upgrade your subscription when needed.
Support
- Documentation: https://docs.ceb.io
- API Reference: https://api.ceb.io/docs
- GitHub: https://github.com/wealthexc/ceb-sdk
- Issues: https://github.com/wealthexc/ceb-sdk/issues
License
MIT License - See LICENSE file for details
Changelog
v1.0.0 (2025-10-31)
- Initial release
- Full API coverage
- Multi-exchange support (Binance, KuCoin, Gate.io, MEXC)
- WebSocket streaming
- Trading and portfolio management
- Arbitrage detection
- TypeScript support
- Helper functions
Built for developers who need unified access to multiple cryptocurrency exchanges 🚀
