Saltar al contenido principal

Trading y Exchange

Este documento explica los flujos de trading e intercambio de criptomonedas en SwapBits.


Arquitectura del Sistema de Trading


1. Swap Interno (Cripto a Cripto)

Vista General

Cálculo de Cotización

interface SwapQuote {
fromCoin: string; // ETH
toCoin: string; // BTC
fromAmount: number; // 1.0 ETH
toAmount: number; // 0.05234 BTC
rate: number; // 0.05234 BTC/ETH
marketRate: number; // 0.05250 BTC/ETH (sin fee)
fee: number; // 0.003 (0.3%)
feeAmount: number; // 0.00003 ETH
totalCost: number; // 1.00003 ETH
expiresAt: Date; // 30 segundos
quoteId: string; // Para validar
}

// Pseudocódigo de cálculo
async function calculateQuote(from: string, to: string, amount: number): SwapQuote {
// 1. Obtener precios actuales en USD
const fromPriceUSD = await this.priceService.getPrice(from);
const toPriceUSD = await this.priceService.getPrice(to);

// 2. Calcular rate de mercado
const marketRate = fromPriceUSD / toPriceUSD;

// 3. Aplicar fee (0.3% por defecto)
const swapFee = 0.003; // 0.3%
const rate = marketRate * (1 - swapFee);

// 4. Calcular monto a recibir
const toAmount = amount * rate;
const feeAmount = amount * swapFee;

// 5. Crear quote con expiración
return {
fromCoin: from,
toCoin: to,
fromAmount: amount,
toAmount,
rate,
marketRate,
fee: swapFee,
feeAmount,
totalCost: amount + feeAmount,
expiresAt: new Date(Date.now() + 30000), // 30 segundos
quoteId: generateQuoteId()
};
}

Estados de Swap

enum SwapStatus {
PENDING = 'pending', // Orden creada
AWAITING_DEPOSIT = 'awaiting_deposit', // Esperando ETH del usuario
DEPOSIT_CONFIRMED = 'deposit_confirmed', // ETH recibido
PROCESSING = 'processing', // Enviando BTC
COMPLETED = 'completed', // Swap completado
FAILED = 'failed', // Error en el proceso
REFUNDED = 'refunded' // Fondos devueltos
}

Swap Guardado en MongoDB

{
_id: ObjectId("..."),
userId: ObjectId("user_123"),
quoteId: "quote_abc123",
fromCoin: "ETH",
toCoin: "BTC",
fromAmount: 1.0,
toAmount: 0.05234,
rate: 0.05234,
fee: 0.003,
feeAmount: 0.00003,
status: "completed",

// Transacciones
depositTxHash: "0x123abc...",
depositConfirmations: 12,
withdrawalTxHash: "0xdef456...",
withdrawalConfirmations: 6,

// Timestamps
createdAt: ISODate("2025-10-20T14:00:00Z"),
depositConfirmedAt: ISODate("2025-10-20T14:03:00Z"),
completedAt: ISODate("2025-10-20T14:15:00Z"),

// Auditoría
fromWalletId: ObjectId("wallet_eth"),
toWalletId: ObjectId("wallet_btc"),
ip: "192.168.1.1"
}

2. Trading con Bybit

Integración con Bybit Exchange

Tipos de Órdenes Soportadas

interface BybitOrder {
// Market Order (compra/venta inmediata al mejor precio)
market: {
type: 'market';
side: 'buy' | 'sell';
symbol: string; // ETHUSDT
quantity: number; // 0.5 ETH
};

// Limit Order (compra/venta a precio específico)
limit: {
type: 'limit';
side: 'buy' | 'sell';
symbol: string;
quantity: number;
price: number; // 2000 USDT
timeInForce: 'GTC' | 'IOC' | 'FOK';
};

// Stop Loss Order (venta automática si precio baja)
stopLoss: {
type: 'stop_loss';
symbol: string;
quantity: number;
stopPrice: number; // 1800 USDT
limitPrice?: number; // Opcional
};

// Take Profit Order (venta automática si precio sube)
takeProfit: {
type: 'take_profit';
symbol: string;
quantity: number;
stopPrice: number; // 2200 USDT
limitPrice?: number;
};
}

Vinculación de Cuenta Bybit

API Keys Encriptadas

{
_id: ObjectId("..."),
userId: ObjectId("user_123"),
exchange: "bybit",
apiKey: "ABC123XYZ", // Público
apiSecretEncrypted: "U2FsdGVkX1...", // Encriptado AES-256
permissions: ["trade"], // NO withdrawal
isActive: true,
createdAt: ISODate("2025-10-20T10:00:00Z"),
lastUsedAt: ISODate("2025-10-20T14:30:00Z")
}

3. Órdenes Límite (Limit Orders)

Flujo de Orden Límite


4. Consulta de Precios en Tiempo Real

WebSocket de Precios

Formato de Precio

interface PriceUpdate {
symbol: string; // ETH
price: number; // 2000.50
change24h: number; // -50.25 (-2.45%)
changePercent: number; // -2.45
high24h: number; // 2100.00
low24h: number; // 1980.00
volume24h: number; // 123456.78 ETH
timestamp: number; // Unix timestamp
}

5. Historial de Trading

Consulta de Órdenes

Estadísticas de Trading

interface TradingStats {
totalOrders: number; // 150
filledOrders: number; // 120
cancelledOrders: number; // 20
pendingOrders: number; // 10

totalVolume: number; // $50,000 USD
totalFees: number; // $150 USD

profitLoss: {
realized: number; // $1,250 (órdenes cerradas)
unrealized: number; // $340 (posiciones abiertas)
total: number; // $1,590
};

winRate: number; // 65% (órdenes ganadoras)

favoriteAssets: Array<{
asset: string;
orderCount: number;
volume: number;
}>;
}

6. Validaciones de Trading

Pre-Trade Checks

async validateTradeOrder(order: TradeOrder, user: User) {

// 1. Usuario tiene cuenta Bybit vinculada
const bybitAccount = await this.getBybitAccount(user._id);
if (!bybitAccount) {
throw new ForbiddenException('Bybit account not linked');
}

// 2. API keys válidas
const keysValid = await this.testBybitKeys(bybitAccount);
if (!keysValid) {
throw new UnauthorizedException('Invalid Bybit credentials');
}

// 3. KYC aprobado para trading
if (user.kycStatus !== 'approved') {
throw new ForbiddenException('KYC required for trading');
}

// 4. Monto dentro de límites
if (order.quantity < MIN_ORDER_SIZE || order.quantity > MAX_ORDER_SIZE) {
throw new BadRequestException('Order size out of bounds');
}

// 5. Rate limiting
await this.rateLimit.check(`trade:${user._id}`, 20, 60000); // 20 órdenes/minuto

// 6. Verificar balance suficiente en Bybit
const balance = await this.getBybitBalance(user._id, order.baseCurrency);
if (balance < order.totalCost) {
throw new BadRequestException('Insufficient balance on Bybit');
}

// 7. Par de trading válido
const validPair = await this.isValidTradingPair(order.symbol);
if (!validPair) {
throw new BadRequestException('Invalid trading pair');
}

// 8. Anti-fraude
await this.fraudService.analyzeTradeOrder(user, order);
}

7. Fees y Comisiones

Estructura de Fees

interface FeeStructure {
// Swap interno
swapFee: {
standard: 0.003, // 0.3%
vip1: 0.0025, // 0.25% (> $10k volumen/mes)
vip2: 0.002, // 0.2% (> $50k volumen/mes)
vip3: 0.0015 // 0.15% (> $100k volumen/mes)
};

// Trading Bybit (fees de Bybit)
bybitTaker: 0.00055; // 0.055% (market orders)
bybitMaker: 0.0001; // 0.01% (limit orders)

// Mínimos
minSwapAmount: {
BTC: 0.0001,
ETH: 0.001,
USDT: 10
};
}

Cálculo de VIP Level

async function calculateVIPLevel(userId: ObjectId): Promise<number> {
// Volumen de trading últimos 30 días
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);

const volume = await this.ordersRepo.aggregate([
{
$match: {
userId,
createdAt: { $gte: thirtyDaysAgo },
status: 'completed'
}
},
{
$group: {
_id: null,
totalVolume: { $sum: '$volumeUSD' }
}
}
]);

const totalVolume = volume[0]?.totalVolume || 0;

if (totalVolume >= 100000) return 3; // VIP 3
if (totalVolume >= 50000) return 2; // VIP 2
if (totalVolume >= 10000) return 1; // VIP 1
return 0; // Standard
}

8. Slippage Protection

Protección contra Slippage

Configuración de Slippage

interface SlippageConfig {
// Slippage máximo por orden
maxSlippage: {
marketOrder: 0.005, // 0.5%
largeOrder: 0.003, // 0.3% (> $10k)
vipOrder: 0.002 // 0.2% (usuarios VIP)
};

// Definir "large order"
largeOrderThreshold: 10000; // $10k USD
}

9. Monitoreo y Alertas

Alertas de Precio

Tipos de Alertas

interface PriceAlert {
_id: ObjectId;
userId: ObjectId;
asset: string; // ETH
condition: 'above' | 'below';
targetPrice: number; // 1900
currentPrice: number; // Precio al crear
isActive: boolean;
triggeredAt?: Date;
notificationSent: boolean;
createdAt: Date;
}

10. Métricas de Trading

Dashboard de Métricas

interface TradingMetrics {
// Métricas del sistema
totalTradingVolume24h: number; // $500,000
totalSwapsCompleted24h: number; // 150
averageSwapTime: number; // 45 segundos
totalFeesCollected24h: number; // $1,500

// Métricas de usuario
activeTraders24h: number; // 200 usuarios
newBybitAccounts24h: number; // 15
averageOrderSize: number; // $350

// Performance
failedSwapRate: number; // 2%
averageSlippage: number; // 0.12%
bybitAPIUptime: number; // 99.8%

// Top pairs
topTradingPairs: Array<{
pair: string;
volume24h: number;
trades: number;
}>;
}

Rate Limiting para Trading

OperaciónLímiteVentanaRazón
Get quote30 requests1 minutoPrevenir spam de cotizaciones
Create swap5 swaps5 minutosPrevenir abuso
Place order (Bybit)20 orders1 minutoLímite de Bybit API
Cancel order30 cancels1 minutoLímite de Bybit API
Get pricesSin límite-Cache en Redis

Troubleshooting

ProblemaCausaSolución
Quote expiróUsuario tardó > 30sSolicitar nueva cotización
Swap pendiente 10+ minBlockchain congestionadoAumentar gas fee
Orden Bybit no ejecutaPrecio no alcanzadoAjustar precio límite
API keys inválidasKeys revocadas en BybitRe-vincular cuenta
Slippage muy altoBaja liquidezReducir tamaño de orden
Balance descuadradoSincronización pendienteForzar sync con Bybit

Best Practices

Para Desarrolladores:

  1. Siempre validar quotes antes de ejecutar swaps
  2. Implementar timeouts en llamadas a Bybit API (5 segundos)
  3. Loggear todas las órdenes para auditoría
  4. Monitorear rate limits de Bybit proactivamente
  5. Encriptar API secrets de Bybit con AES-256
  6. Nunca guardar private keys en logs o responses
  7. Implementar circuit breaker si Bybit API falla 3+ veces

Para Testing:

  • Usar Bybit Testnet para desarrollo
  • Validar slippage protection con órdenes grandes
  • Testear reconnection de WebSocket de precios
  • Simular fallos de API de Bybit