- Added telegram_command_bot.py with slash commands (/buySOL, /sellBTC, etc) - Docker compose setup with DNS configuration - Sends trades as plain text to n8n webhook (same format as TradingView) - Improved Telegram success message formatting - Only responds to authorized chat ID (579304651) - Commands: /buySOL, /sellSOL, /buyBTC, /sellBTC, /buyETH, /sellETH
263 lines
9.5 KiB
Markdown
263 lines
9.5 KiB
Markdown
# AI Agent Instructions for Trading Bot v4
|
|
|
|
## Architecture Overview
|
|
|
|
**Type:** Autonomous cryptocurrency trading bot with Next.js 15 frontend + Solana/Drift Protocol backend
|
|
|
|
**Data Flow:** TradingView → n8n webhook → Next.js API → Drift Protocol (Solana DEX) → Real-time monitoring → Auto-exit
|
|
|
|
**Key Design Principle:** Dual-layer redundancy - every trade has both on-chain orders (Drift) AND software monitoring (Position Manager) as backup.
|
|
|
|
## Critical Components
|
|
|
|
### 1. Position Manager (`lib/trading/position-manager.ts`)
|
|
**Purpose:** Software-based monitoring loop that checks prices every 2 seconds and closes positions via market orders
|
|
|
|
**Singleton pattern:** Always use `getPositionManager()` - never instantiate directly
|
|
```typescript
|
|
const positionManager = getPositionManager()
|
|
await positionManager.addTrade(activeTrade)
|
|
```
|
|
|
|
**Key behaviors:**
|
|
- Tracks `ActiveTrade` objects in a Map
|
|
- Dynamic SL adjustments: Moves to breakeven at +0.5%, locks profit at +1.2%
|
|
- Closes positions via `closePosition()` market orders when targets hit
|
|
- Acts as backup if on-chain orders don't fill
|
|
|
|
### 2. Drift Client (`lib/drift/client.ts`)
|
|
**Purpose:** Solana/Drift Protocol SDK wrapper for order execution
|
|
|
|
**Singleton pattern:** Use `initializeDriftService()` and `getDriftService()` - maintains single connection
|
|
```typescript
|
|
const driftService = await initializeDriftService()
|
|
const health = await driftService.getAccountHealth()
|
|
```
|
|
|
|
**Wallet handling:** Supports both JSON array `[91,24,...]` and base58 string formats from Phantom wallet
|
|
|
|
### 3. Order Placement (`lib/drift/orders.ts`)
|
|
**Critical function:** `placeExitOrders()` - places TP/SL orders on-chain
|
|
|
|
**Dual Stop System** (USE_DUAL_STOPS=true):
|
|
```typescript
|
|
// Soft stop: TRIGGER_LIMIT at -1.5% (avoids wicks)
|
|
// Hard stop: TRIGGER_MARKET at -2.5% (guarantees exit)
|
|
```
|
|
|
|
**Order types:**
|
|
- Entry: MARKET (immediate execution)
|
|
- TP1/TP2: LIMIT reduce-only orders
|
|
- Soft SL: TRIGGER_LIMIT reduce-only
|
|
- Hard SL: TRIGGER_MARKET reduce-only
|
|
|
|
### 4. Database (`lib/database/trades.ts` + `prisma/schema.prisma`)
|
|
**Purpose:** PostgreSQL via Prisma ORM for trade history and analytics
|
|
|
|
**Models:** Trade, PriceUpdate, SystemEvent, DailyStats
|
|
|
|
**Singleton pattern:** Use `getPrismaClient()` - never instantiate PrismaClient directly
|
|
|
|
**Key functions:**
|
|
- `createTrade()` - Save trade after execution (includes dual stop TX signatures)
|
|
- `updateTradeExit()` - Record exit with P&L
|
|
- `addPriceUpdate()` - Track price movements (called by Position Manager)
|
|
- `getTradeStats()` - Win rate, profit factor, avg win/loss
|
|
|
|
## Configuration System
|
|
|
|
**Three-layer merge:**
|
|
1. `DEFAULT_TRADING_CONFIG` (config/trading.ts)
|
|
2. Environment variables (.env) via `getConfigFromEnv()`
|
|
3. Runtime overrides via `getMergedConfig(overrides)`
|
|
|
|
**Always use:** `getMergedConfig()` to get final config - never read env vars directly in business logic
|
|
|
|
**Symbol normalization:** TradingView sends "SOLUSDT" → must convert to "SOL-PERP" for Drift
|
|
```typescript
|
|
const driftSymbol = normalizeTradingViewSymbol(body.symbol)
|
|
```
|
|
|
|
## API Endpoints Architecture
|
|
|
|
**Authentication:** All `/api/trading/*` endpoints (except `/test`) require `Authorization: Bearer API_SECRET_KEY`
|
|
|
|
**Pattern:** Each endpoint follows same flow:
|
|
1. Auth check
|
|
2. Get config via `getMergedConfig()`
|
|
3. Initialize Drift service
|
|
4. Check account health
|
|
5. Execute operation
|
|
6. Save to database
|
|
7. Add to Position Manager if applicable
|
|
|
|
**Key endpoints:**
|
|
- `/api/trading/execute` - Main entry point from n8n (production)
|
|
- `/api/trading/test` - Test trades from settings UI (no auth required)
|
|
- `/api/trading/close` - Manual position closing
|
|
- `/api/trading/positions` - Query open positions
|
|
- `/api/settings` - Get/update config (writes to .env file)
|
|
|
|
## Critical Workflows
|
|
|
|
### Execute Trade (Production)
|
|
```
|
|
n8n webhook → /api/trading/execute
|
|
↓ normalize symbol (SOLUSDT → SOL-PERP)
|
|
↓ getMergedConfig()
|
|
↓ openPosition() [MARKET order]
|
|
↓ calculate dual stop prices if enabled
|
|
↓ placeExitOrders() [on-chain TP/SL orders]
|
|
↓ createTrade() [save to database]
|
|
↓ positionManager.addTrade() [start monitoring]
|
|
```
|
|
|
|
### Position Monitoring Loop
|
|
```
|
|
Position Manager every 2s:
|
|
↓ getPythPriceMonitor().getLatestPrice()
|
|
↓ Calculate current P&L
|
|
↓ Check TP1 hit → closePosition(75%)
|
|
↓ Check TP2 hit → closePosition(100%)
|
|
↓ Check SL hit → closePosition(100%)
|
|
↓ Check dynamic adjustments (breakeven, profit lock)
|
|
↓ addPriceUpdate() [save to database]
|
|
```
|
|
|
|
### Settings Update
|
|
```
|
|
Web UI → /api/settings POST
|
|
↓ Validate new settings
|
|
↓ Write to .env file using string replacement
|
|
↓ Return success
|
|
↓ User clicks "Restart Bot" → /api/restart
|
|
↓ Creates /tmp/trading-bot-restart.flag
|
|
↓ watch-restart.sh detects flag
|
|
↓ Executes: docker restart trading-bot-v4
|
|
```
|
|
|
|
## Docker Context
|
|
|
|
**Multi-stage build:** deps → builder → runner (Node 20 Alpine)
|
|
|
|
**Critical Dockerfile steps:**
|
|
1. Install deps with `npm install --production`
|
|
2. Copy source and `npx prisma generate` (MUST happen before build)
|
|
3. `npm run build` (Next.js standalone output)
|
|
4. Runner stage copies standalone + static + node_modules + Prisma client
|
|
|
|
**Container networking:**
|
|
- External: `trading-bot-v4` on port 3001
|
|
- Internal: Next.js on port 3000
|
|
- Database: `trading-bot-postgres` on 172.28.0.0/16 network
|
|
|
|
**DATABASE_URL caveat:** Use `trading-bot-postgres` (container name) in .env for runtime, but `localhost:5432` for Prisma CLI migrations from host
|
|
|
|
## Project-Specific Patterns
|
|
|
|
### 1. Singleton Services
|
|
Never create multiple instances - always use getter functions:
|
|
```typescript
|
|
const driftService = await initializeDriftService() // NOT: new DriftService()
|
|
const positionManager = getPositionManager() // NOT: new PositionManager()
|
|
const prisma = getPrismaClient() // NOT: new PrismaClient()
|
|
```
|
|
|
|
### 2. Price Calculations
|
|
Direction matters for long vs short:
|
|
```typescript
|
|
function calculatePrice(entry: number, percent: number, direction: 'long' | 'short') {
|
|
if (direction === 'long') {
|
|
return entry * (1 + percent / 100) // Long: +1% = higher price
|
|
} else {
|
|
return entry * (1 - percent / 100) // Short: +1% = lower price
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Error Handling
|
|
Database failures should not fail trades - always wrap in try/catch:
|
|
```typescript
|
|
try {
|
|
await createTrade(params)
|
|
console.log('💾 Trade saved to database')
|
|
} catch (dbError) {
|
|
console.error('❌ Failed to save trade:', dbError)
|
|
// Don't fail the trade if database save fails
|
|
}
|
|
```
|
|
|
|
### 4. Reduce-Only Orders
|
|
All exit orders MUST be reduce-only (can only close, not open positions):
|
|
```typescript
|
|
const orderParams = {
|
|
reduceOnly: true, // CRITICAL for TP/SL orders
|
|
// ... other params
|
|
}
|
|
```
|
|
|
|
## Testing Commands
|
|
|
|
```bash
|
|
# Local development
|
|
npm run dev
|
|
|
|
# Build production
|
|
npm run build && npm start
|
|
|
|
# Docker build and restart
|
|
docker compose build trading-bot
|
|
docker compose up -d --force-recreate trading-bot
|
|
docker logs -f trading-bot-v4
|
|
|
|
# Database operations
|
|
npx prisma generate # Generate client
|
|
DATABASE_URL="postgresql://...@localhost:5432/..." npx prisma migrate dev
|
|
docker exec trading-bot-postgres psql -U postgres -d trading_bot_v4 -c "\dt"
|
|
|
|
# Test trade from UI
|
|
# Go to http://localhost:3001/settings
|
|
# Click "Test LONG" or "Test SHORT"
|
|
```
|
|
|
|
## Common Pitfalls
|
|
|
|
1. **Prisma not generated in Docker:** Must run `npx prisma generate` in Dockerfile BEFORE `npm run build`
|
|
|
|
2. **Wrong DATABASE_URL:** Container runtime needs `trading-bot-postgres`, Prisma CLI from host needs `localhost:5432`
|
|
|
|
3. **Symbol format mismatch:** Always normalize with `normalizeTradingViewSymbol()` before calling Drift
|
|
|
|
4. **Missing reduce-only flag:** Exit orders without `reduceOnly: true` can accidentally open new positions
|
|
|
|
5. **Singleton violations:** Creating multiple DriftClient or Position Manager instances causes connection/state issues
|
|
|
|
6. **Type errors with Prisma:** The Trade type from Prisma is only available AFTER `npx prisma generate` - use explicit types or `// @ts-ignore` carefully
|
|
|
|
## File Conventions
|
|
|
|
- **API routes:** `app/api/[feature]/[action]/route.ts` (Next.js 15 App Router)
|
|
- **Services:** `lib/[service]/[module].ts` (drift, pyth, trading, database)
|
|
- **Config:** Single source in `config/trading.ts` with env merging
|
|
- **Types:** Define interfaces in same file as implementation (not separate types directory)
|
|
- **Console logs:** Use emojis for visual scanning: 🎯 🚀 ✅ ❌ 💰 📊 🛡️
|
|
|
|
## When Making Changes
|
|
|
|
1. **Adding new config:** Update DEFAULT_TRADING_CONFIG + getConfigFromEnv() + .env file
|
|
2. **Adding database fields:** Update prisma/schema.prisma → migrate → regenerate client → rebuild Docker
|
|
3. **Changing order logic:** Test with DRY_RUN=true first, use small position sizes ($10)
|
|
4. **API endpoint changes:** Update both endpoint + corresponding n8n workflow JSON
|
|
5. **Docker changes:** Rebuild with `docker compose build trading-bot` then restart container
|
|
|
|
## Integration Points
|
|
|
|
- **n8n:** Expects exact response format from `/api/trading/execute` (see n8n-complete-workflow.json)
|
|
- **Drift Protocol:** Uses SDK v2.75.0 - check docs at docs.drift.trade for API changes
|
|
- **Pyth Network:** WebSocket + HTTP fallback for price feeds (handles reconnection)
|
|
- **PostgreSQL:** Version 16-alpine, must be running before bot starts
|
|
|
|
---
|
|
|
|
**Key Mental Model:** Think of this as two parallel systems (on-chain orders + software monitoring) working together. The Position Manager is the "backup brain" that constantly watches and acts if on-chain orders fail. Both write to the same database for complete trade history.
|