A sophisticated NestJS-based trading platform with Unified API Architecture supporting multiple perpetual futures exchanges including Aster DEX, Hyperliquid, Binance Futures, and OKX Perpetuals.
- ✅ Unified API: Single set of endpoints serving all exchanges
- ✅ Factory Pattern: Dynamic service resolution at runtime via Exchange Factory
- ✅ Interface-Driven: Clean separation between interfaces and implementations
- ✅ Type-Safe: Full TypeScript with strict mode enabled
- ✅ Modular Design: Each exchange is a self-contained module
- ✅ Plug & Play: Add new exchanges by implementing standard interfaces
- ✅ Aster DEX: Decentralized perpetual futures (with WebSocket support)
- ✅ Hyperliquid: On-chain perpetual futures (with WebSocket support)
- ✅ Binance Futures: Centralized perpetual futures
- ✅ OKX Perpetuals: Centralized perpetual futures
- ✅ Trading Operations: Market/limit orders, position management, leverage control
- ✅ Risk Management: Stop-loss, take-profit, margin management
- ✅ Balance & Portfolio: Real-time balance tracking, P&L calculation, portfolio value
- ✅ Market Data: Real-time prices, orderbook depth, historical candles, funding rates
- ✅ Symbol Normalization: Automatic symbol format conversion across exchanges
- ✅ REST API: Comprehensive Swagger documentation at
/api - ✅ WebSocket Support: Real-time market data and account updates
- ✅ Authentication: API Key guard for secure access
- ✅ Error Handling: Standardized error responses
- ✅ Clean Architecture: Modular, testable, maintainable codebase
# Install dependencies
pnpm installCreate a .env file in the root directory with your exchange API credentials:
# Application Settings
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug
# API Access Control (REQUIRED!)
# This key protects all endpoints
API_KEY_ACCESS=your_secure_api_key_here
# Aster DEX Configuration
ASTER_API_KEY=your_aster_api_key
ASTER_API_SECRET=your_aster_api_secret
ASTER_USER_ADDRESS=your_wallet_address
ASTER_SIGNER_ADDRESS=your_signer_address
ASTER_PRIVATE_KEY=your_private_key
ASTER_REST_URL=https://fapi.asterdex.com
ASTER_WS_URL=wss://fstream.asterdex.com
# Hyperliquid Configuration
HYPERLIQUID_REST_URL=https://api.hyperliquid.xyz
HYPERLIQUID_WS_URL=wss://api.hyperliquid.xyz/ws
HYPERLIQUID_WALLET_ADDRESS=your_wallet_address
HYPERLIQUID_PRIVATE_KEY=your_private_key
HYPERLIQUID_TESTNET=false
# Binance Futures Configuration (Optional)
BINANCE_API_KEY=your_binance_api_key
BINANCE_API_SECRET=your_binance_api_secret
BINANCE_REST_URL=https://fapi.binance.com
BINANCE_TESTNET=false
# OKX Perpetuals Configuration (Optional)
OKX_API_KEY=your_okx_api_key
OKX_API_SECRET=your_okx_api_secret
OKX_PASSPHRASE=your_okx_passphrase
OKX_REST_URL=https://www.okx.com
OKX_TESTNET=falseSecurity Note: The API_KEY_ACCESS is required in the X-API-Key header for all requests to protected endpoints.
# Development mode with hot reload
pnpm start:dev
# Production mode
pnpm build
pnpm start:prodThe application will be available at:
- API: http://localhost:3000
- Swagger Documentation: http://localhost:3000/api
All trading endpoints require API key authentication using the X-API-Key header.
Required Header:
X-API-Key: your_api_key_access_here- Open http://localhost:3000/api
- Click the "Authorize" button (lock icon) at the top
- Enter your
API_KEY_ACCESSfrom.envfile - Click "Authorize" and "Close"
- Now you can test all endpoints directly in the browser
curl -H "X-API-Key: your_api_key_access_here" \
http://localhost:3000/balance?exchange=asterAll endpoints follow a unified pattern: /{resource}?exchange={exchange_name}
GET /balance?exchange={exchange}- Get account balance and positionsGET /balance/portfolio?exchange={exchange}- Get portfolio summaryGET /balance/positions?exchange={exchange}- Get all open positionsGET /balance/position?exchange={exchange}&symbol={symbol}- Get specific position
Example:
# Get Aster balance
curl -H "X-API-Key: your_key" \
"http://localhost:3000/balance?exchange=aster"
# Get Hyperliquid positions
curl -H "X-API-Key: your_key" \
"http://localhost:3000/balance/positions?exchange=hyperliquid"GET /market/symbols?exchange={exchange}- Get all tradable symbolsGET /market/ticker?exchange={exchange}&symbol={symbol}- Get 24hr tickerGET /market/orderbook?exchange={exchange}&symbol={symbol}- Get order bookGET /market/trades?exchange={exchange}&symbol={symbol}- Get recent tradesGET /market/candles?exchange={exchange}&symbol={symbol}&interval={interval}- Get klines/candlesGET /market/funding?exchange={exchange}&symbol={symbol}- Get funding rate history
Example:
# Get BTC ticker from Binance
curl -H "X-API-Key: your_key" \
"http://localhost:3000/market/ticker?exchange=binance&symbol=BTC-USDT"
# Get ETH orderbook from Hyperliquid
curl -H "X-API-Key: your_key" \
"http://localhost:3000/market/orderbook?exchange=hyperliquid&symbol=ETH-USD"POST /trading/order/market- Place market orderPOST /trading/order/limit- Place limit orderPOST /trading/order/cancel- Cancel orderPOST /trading/order/cancel-all- Cancel all ordersGET /trading/orders?exchange={exchange}- Get open ordersPOST /trading/leverage- Set leveragePOST /trading/position/close- Close position
Market Order Example:
curl -X POST -H "X-API-Key: your_key" \
-H "Content-Type: application/json" \
"http://localhost:3000/trading/order/market" \
-d '{
"exchange": "aster",
"symbol": "BTC-USDT",
"side": "BUY",
"quantity": 0.001
}'Limit Order Example:
curl -X POST -H "X-API-Key: your_key" \
-H "Content-Type: application/json" \
"http://localhost:3000/trading/order/limit" \
-d '{
"exchange": "hyperliquid",
"symbol": "ETH-USD",
"side": "SELL",
"quantity": 0.1,
"price": 3500
}'Close Position Example:
curl -X POST -H "X-API-Key: your_key" \
-H "Content-Type: application/json" \
"http://localhost:3000/trading/position/close" \
-d '{
"exchange": "binance",
"symbol": "BTC-USDT"
}'src/
├── api/ # Unified API Layer
│ ├── controllers/ # REST API Controllers
│ │ ├── balance.controller.ts # Balance & portfolio endpoints
│ │ ├── market.controller.ts # Market data endpoints
│ │ └── trading.controller.ts # Trading endpoints
│ └── api.module.ts # API module configuration
│
├── common/ # Shared Utilities
│ ├── decorators/ # Custom decorators
│ │ ├── api-key.decorator.ts # API key extraction
│ │ └── public.decorator.ts # Public endpoint marker
│ ├── dto/ # Data Transfer Objects
│ │ ├── exchange.dto.ts # Exchange selection DTOs
│ │ └── trading.dto.ts # Trading operation DTOs
│ ├── factory/ # Factory Pattern
│ │ └── exchange.factory.ts # Dynamic service resolution
│ ├── guards/ # Authentication Guards
│ │ └── api-key.guard.ts # API key validation
│ ├── interfaces/ # Standard Interfaces
│ │ ├── balance.interface.ts # Balance operations
│ │ ├── market.interface.ts # Market data operations
│ │ └── trading.interface.ts # Trading operations
│ ├── middleware/ # HTTP Middleware
│ │ └── symbol-normalizer.middleware.ts # Symbol format conversion
│ ├── services/ # Common Services
│ │ └── symbol-normalizer.service.ts # Symbol normalization logic
│ └── types/ # Type Definitions
│ └── exchange.types.ts # Exchange enums and types
│
├── exchanges/ # Exchange Integrations
│ ├── aster/ # Aster DEX
│ │ ├── perpetual/
│ │ │ ├── services/
│ │ │ │ ├── perpetual-balance.service.ts
│ │ │ │ ├── perpetual-market.service.ts
│ │ │ │ └── perpetual-trading.service.ts
│ │ │ └── perpetual.module.ts
│ │ ├── shared/
│ │ │ ├── aster-api.service.ts # REST API client
│ │ │ └── aster-websocket.service.ts # WebSocket client
│ │ ├── types/ # Type definitions
│ │ └── aster.module.ts
│ │
│ ├── hyperliquid/ # Hyperliquid
│ │ ├── perp/
│ │ │ ├── services/
│ │ │ │ ├── balance.service.ts
│ │ │ │ ├── market-data.service.ts
│ │ │ │ ├── order-management.service.ts
│ │ │ │ └── order-placement.service.ts
│ │ │ └── perp.module.ts
│ │ ├── shared/
│ │ │ ├── hyperliquid-api.service.ts # REST API client
│ │ │ └── signing.service.ts # Signature generation
│ │ ├── types/
│ │ └── hyperliquid.module.ts
│ │
│ ├── binance/ # Binance Futures
│ │ ├── perpetual/
│ │ │ ├── services/
│ │ │ │ ├── perpetual-balance.service.ts
│ │ │ │ ├── perpetual-market.service.ts
│ │ │ │ └── perpetual-trading.service.ts
│ │ │ └── perpetual.module.ts
│ │ ├── shared/
│ │ │ └── binance-api.service.ts
│ │ ├── types/
│ │ └── binance.module.ts
│ │
│ ├── okx/ # OKX Perpetuals
│ │ ├── perpetual/
│ │ │ ├── services/
│ │ │ │ ├── perpetual-balance.service.ts
│ │ │ │ ├── perpetual-market.service.ts
│ │ │ │ └── perpetual-trading.service.ts
│ │ │ └── perpetual.module.ts
│ │ ├── shared/
│ │ │ └── okx-api.service.ts
│ │ ├── types/
│ │ └── okx.module.ts
│ │
│ └── exchanges.module.ts # Exchanges module aggregator
│
├── config/ # Configuration Files
│ ├── app.config.ts # App settings
│ ├── aster.config.ts # Aster configuration
│ ├── binance.config.ts # Binance configuration
│ ├── hyperliquid.config.ts # Hyperliquid configuration
│ ├── okx.config.ts # OKX configuration
│ └── trading.config.ts # Trading settings
│
├── app.module.ts # Root module
└── main.ts # Application entry point
Instead of separate endpoints per exchange, we use a unified pattern:
Traditional Approach (Bad):
- /aster/balance
- /hyperliquid/balance
- /binance/balance
- /okx/balance
→ 4 exchanges × 50 operations = 200 endpoints!
Unified Approach (Good):
- /balance?exchange=aster
- /balance?exchange=hyperliquid
- /balance?exchange=binance
- /balance?exchange=okx
→ 50 endpoints serving all exchanges
The ExchangeFactory dynamically resolves the correct service based on the exchange parameter:
// Client request
GET /balance?exchange=aster
// Factory resolves
ExchangeFactory → AsterPerpetualBalanceService → Execute
// Client request
GET /balance?exchange=hyperliquid
// Factory resolves
ExchangeFactory → HyperliquidBalanceService → ExecuteAll exchange implementations follow standard interfaces:
IBalanceService: Balance and portfolio operationsIMarketDataService: Market data operationsITradingService: Trading operations
This ensures:
- Consistency: All exchanges work the same way
- Testability: Easy to mock and test
- Maintainability: Changes in one place affect all exchanges
- Extensibility: New exchanges just implement interfaces
Each exchange uses different symbol formats:
- Aster:
BTCUSDT - Hyperliquid:
BTC - Binance:
BTCUSDT - OKX:
BTC-USDT-SWAP
The SymbolNormalizerMiddleware automatically converts symbols:
Client → "BTC-USDT" → Middleware → "BTCUSDT" (Aster)
Client → "BTC-USDT" → Middleware → "BTC" (Hyperliquid)
Client → "BTC-USDT" → Middleware → "BTC-USDT-SWAP" (OKX)
| Variable | Description | Required | Default |
|---|---|---|---|
API_KEY_ACCESS |
API key for endpoint authentication | Yes | - |
PORT |
Application port | No | 3000 |
NODE_ENV |
Environment mode | No | development |
LOG_LEVEL |
Logging level | No | debug |
Aster DEX:
| Variable | Description | Required |
|---|---|---|
ASTER_API_KEY |
Aster API key | Yes |
ASTER_API_SECRET |
Aster API secret | Yes |
ASTER_USER_ADDRESS |
Wallet address | Yes |
ASTER_SIGNER_ADDRESS |
Signer address | Yes |
ASTER_PRIVATE_KEY |
Private key | Yes |
ASTER_REST_URL |
REST API URL | No |
ASTER_WS_URL |
WebSocket URL | No |
Hyperliquid:
| Variable | Description | Required |
|---|---|---|
HYPERLIQUID_WALLET_ADDRESS |
Wallet address | Yes |
HYPERLIQUID_PRIVATE_KEY |
Private key | Yes |
HYPERLIQUID_REST_URL |
REST API URL | No |
HYPERLIQUID_WS_URL |
WebSocket URL | No |
HYPERLIQUID_TESTNET |
Use testnet | No |
Binance Futures:
| Variable | Description | Required |
|---|---|---|
BINANCE_API_KEY |
Binance API key | Yes |
BINANCE_API_SECRET |
Binance API secret | Yes |
BINANCE_REST_URL |
REST API URL | No |
BINANCE_TESTNET |
Use testnet | No |
OKX Perpetuals:
| Variable | Description | Required |
|---|---|---|
OKX_API_KEY |
OKX API key | Yes |
OKX_API_SECRET |
OKX API secret | Yes |
OKX_PASSPHRASE |
OKX passphrase | Yes |
OKX_REST_URL |
REST API URL | No |
OKX_TESTNET |
Use testnet | No |
# Development
pnpm start:dev # Start with hot reload
pnpm build # Build for production
pnpm start:prod # Start production build
# Testing
pnpm test # Run unit tests
pnpm test:watch # Run tests in watch mode
pnpm test:cov # Generate coverage report
pnpm test:e2e # Run end-to-end tests
# Code Quality
pnpm lint # Run ESLint
pnpm format # Format code with PrettierTo add support for a new exchange:
-
Create exchange module structure:
mkdir -p src/exchanges/newexchange/perpetual/services mkdir -p src/exchanges/newexchange/shared mkdir -p src/exchanges/newexchange/types
-
Implement standard interfaces:
Create services implementing:
IBalanceService(balance operations)IMarketDataService(market data)ITradingService(trading operations)
-
Create API service:
Implement REST API client in
shared/newexchange-api.service.ts -
Define types:
Add exchange-specific types in
types/index.ts -
Create configuration:
Add config in
src/config/newexchange.config.ts -
Register in factory:
Add exchange to
ExchangeFactoryresolution logic -
Update exchange enum:
Add to
ExchangeNameenum incommon/types/exchange.types.ts -
Test thoroughly:
Create unit tests for all services
- Environment Variables: Sensitive data stored securely in
.env - API Key Authentication: All endpoints protected with API key guard
- HMAC Signatures: Secure API authentication for supported exchanges
- Input Validation: Comprehensive validation using class-validator
- Rate Limiting: Built-in protection against API rate limits
- Error Sanitization: Sensitive information removed from logs
The application uses structured logging with contextual information:
- Error: System errors and critical failures
- Warn: Non-critical issues and warnings
- Info: General application information
- Debug: Detailed debugging information (set
LOG_LEVEL=debug)
Logs include request IDs, exchange names, and operation metadata for easy troubleshooting.
Connection Failed:
- Verify API credentials in
.envfile - Check network connectivity
- Ensure exchange API is accessible
Invalid Signature:
- Verify API secret is correct
- Check system time synchronization
- Ensure timestamp is within acceptable range
Rate Limited:
- Reduce request frequency
- Implement exponential backoff
- Check exchange rate limit documentation
Symbol Not Found:
- Verify symbol format for the specific exchange
- Check if symbol is supported by the exchange
- Use
/market/symbolsendpoint to list available symbols
Enable detailed logging:
LOG_LEVEL=debug pnpm start:devAll API responses follow a standardized format:
Success Response:
{
"success": true,
"data": {
// Response data here
},
"timestamp": "2024-01-01T00:00:00.000Z"
}Error Response:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Error description",
"details": {}
},
"timestamp": "2024-01-01T00:00:00.000Z"
}# Build image
docker build -t perps-vibe-ai .
# Run container
docker run -d \
--name perps-vibe-ai \
-p 3000:3000 \
--env-file .env \
perps-vibe-ai# Deploy to Google Cloud Run
./scripts/deploy-cloudrun.shFor detailed documentation, see the .docs folder:
- Architecture guides
- API authentication details
- Exchange-specific documentation
- Trading strategies
- WebSocket integration guides
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Implement your changes
- Add tests for new features
- Submit a pull request
MIT License - see LICENSE file for details.
Important: This is a trading platform that can place real orders and spend real money. Always:
- Test thoroughly in testnet/sandbox environments
- Start with small amounts
- Implement proper risk management
- Monitor positions actively
- Use at your own risk
The developers are not responsible for any financial losses incurred while using this platform.