A self-hosted trading automation backend. Connect your exchange accounts, configure bots, and automate futures trades via webhooks from TradingView or any HTTP client.
Think 3Commas or Pionex — but open-source and running on your own infrastructure.
- Receive trading signals via webhook (TradingView alerts, custom scripts, etc.)
- Execute futures orders on connected exchanges automatically
- Track trade lifecycle: from order placement through fill to position close
- Manage multiple exchange accounts per user, credentials encrypted with AWS KMS
Supported exchanges: Gate.io, OKX, Hyperliquid, Tokocrypto, Bitget, MEXC, BitMart
Signal (TradingView / HTTP)
│
▼
POST /webhook/signal { token, action: "BUY" | "SELL" | "CLOSE" }
│
▼
Validates token → loads autotrader config → decrypts exchange credentials
│
▼
Exchange Executor (places order via REST, writes trade to DB)
│
▼ (async, separate process)
Exchange Worker (listens to exchange WebSocket → updates trade status in DB)
Trades progress through these states: waiting_position → waiting_targets → closed
| Layer | Technology |
|---|---|
| Runtime | Bun |
| Framework | Hono |
| Database | PostgreSQL + Drizzle ORM |
| Cache / Pub-Sub | Redis (ioredis) |
| Credential encryption | AWS KMS (KEK-DEK model) |
| Auth | Firebase Authentication |
- Bun >= 1.0
- PostgreSQL
- Redis
- AWS account with a KMS key (for credential encryption)
- Firebase project (for user auth)
- API keys for whichever exchanges you want to connect
1. Install dependencies
bun install2. Configure environment
Create a .env file:
PORT=1122
DATABASE_URL=postgresql://user:password@localhost:5432/byscript
REDIS_URL=redis://localhost:6379
CORS_ORIGIN=http://localhost:5173
# AWS KMS
AWS_REGION=ap-southeast-1
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
KMS_KEY_ID=...
# Firebase
FIREBASE_PROJECT_ID=...
FIREBASE_CLIENT_EMAIL=...
FIREBASE_PRIVATE_KEY=...3. Run database migrations
bun run db:push4. Start the API server
bun run src/index.ts5. Start worker manager
bun run start:worker-managerWorkerManager runs all exchange adapters in one process, routes control commands, runs internal reconciliation, and serves worker health/metrics endpoints.
Server runs on http://localhost:1122 by default.
Send POST /webhook/signal:
{
"token": "your-autotrader-webhook-token",
"action": "BUY",
"order_type": "market",
"take_profit": {
"enabled": true,
"price": "68000",
"price_type": "mark"
},
"stop_loss": {
"enabled": true,
"price": "62000",
"price_type": "mark"
}
}| Field | Required | Values |
|---|---|---|
token |
Yes | Per-autotrader webhook token |
action |
Yes | BUY, SELL, CLOSE, CANCEL |
order_type |
No | market (default) or limit |
price |
If limit | Entry price |
take_profit.price_type |
If TP enabled | mark, last, index |
stop_loss.price_type |
If SL enabled | mark, last, index |
The API responds immediately with 200 OK. Execution happens asynchronously.
| Method | Path | Description |
|---|---|---|
POST |
/webhook/signal |
Receive and execute a trading signal |
GET |
/health |
Health check (DB + Redis latency) |
GET |
/autotraders |
List autotrader configurations |
POST |
/autotraders |
Create autotrader |
GET |
/user/trades |
Trade history |
GET |
/sse/trades |
Real-time trade updates (Server-Sent Events) |
POST |
/gate/register-user |
Register Gate.io account |
POST |
/okx/register-user |
Register OKX account |
POST |
/hyperliquid/register-user |
Register Hyperliquid account |
POST |
/tokocrypto/register-user |
Register Tokocrypto account |
All routes except /webhook/signal and /health require a Firebase JWT: Authorization: Bearer <token>
An autotrader defines one bot on one exchange for one trading pair.
| Field | Description |
|---|---|
symbol |
Trading pair in exchange format (BTC_USDT for Gate, BTC-USDT-SWAP for OKX) |
exchange_id |
Which connected exchange account to use |
initial_investment |
Contract size (number of contracts) |
leverage |
Leverage multiplier |
leverage_type |
ISOLATED or CROSS |
position_mode |
hedge or one-way |
webhook_token |
Token for authenticating incoming signals |
status |
active, inactive, or paused |
Exchange API keys are never stored in plaintext:
- A random DEK (data encryption key) is generated per exchange connection
- The DEK is encrypted with your AWS KMS master key and stored in the database
- API keys and secrets are encrypted with the DEK
- On each trade, the KMS key decrypts the DEK at runtime — plaintext keys exist only in memory for the duration of the request
Compromising the database alone is not sufficient to recover API keys.
Gate.io — fully tested end-to-end
- Symbol format:
BTC_USDT - TP/SL as separate trigger price orders
OKX — implemented, lifecycle testing in progress
- Symbol format:
BTC-USDT-SWAP - TP/SL inline in order payload via
attachAlgoOrds
Hyperliquid — implemented, lifecycle testing in progress
- Uses agent private key (not API key/secret)
- TP/SL as separate reduce-only limit orders
Tokocrypto — implemented, lifecycle testing in progress
- Binance Cloud infrastructure, follows Binance Futures API
- Requires three pre-order calls: position mode, leverage, margin mode
Bitget — implemented, lifecycle testing in progress
- Uses CCXT + API passphrase
- WebSocket-driven order/position updates
MEXC — implemented, lifecycle testing in progress
- Uses CCXT without passphrase
- WebSocket-driven order/position updates
BitMart — implemented, lifecycle testing in progress
- Uses CCXT + memo/uid passphrase
- WebSocket-driven order/position updates
Gate.io is the reference implementation with a fully tested trade lifecycle. The other exchanges have executors and workers implemented but are not yet fully tested end-to-end.
Actively working on:
- High-availability: Redis Streams for at-least-once delivery, dead letter queue for failed DB writes, periodic reconciliation
- Worker architecture consolidation: single
WorkerManagerprocess instead of 4 separate workers - Structured logging with pino
- Fork the repository
- Create a feature branch
- Submit a pull request
MIT