- Updated lib/maintenance/data-cleanup.ts retention period: 28 days → 365 days - Storage requirements validated: 251 MB/year (negligible) - Rationale: 13× more historical data for better pattern analysis - Benefits: 260-390 blocked signals/year vs 20-30/month - Cleanup cutoff: Now Dec 2, 2024 (vs Nov 4, 2025 previously) - Deployment verified: Container restarted, cleanup scheduled for 3 AM daily
Trading Bot v4 🚀
Fully Autonomous Trading Bot with Dual-Layer Redundancy for TradingView → n8n → Drift Protocol (Solana)
📊 Live Status
Capital: $97.55 USDC | Target: $2,500 (Phase 1) | Leverage: 15x (SOL)
Win Rate: 60%+ target | Trades Executed: 161 | System: ✅ Operational
Development Status
| Phase | Status | Description |
|---|---|---|
| Phase 1-4 | ✅ COMPLETE | Core system: Execution, monitoring, UI, database |
| Phase 5 | 🔄 IN PROGRESS | Data collection & optimization (see below) |
🎯 Active Optimization Initiatives
Three parallel data-driven improvements targeting 35-40% P&L increase over 3 months:
1. Signal Quality Optimization (🔜 2-3 weeks)
Filter bad trades BEFORE entry by optimizing quality thresholds
Progress: [▓░░░░░░░░░] 0/20 blocked signals collected (0%)
Status: Phase 1 - Data Collection
Impact: +5% win rate expected (60% → 65%)
2. Position Scaling & Exit Strategy (🔜 3-4 weeks)
Optimize HOW MUCH to close at each target based on signal quality
Progress: [▓▓▓▓▓▓▓▓▓▓] 161/50 trades (322%) ✅ - Need v6 indicator data
Status: Phase 5 complete (TP2-as-runner), Phase 2-4 pending analysis
Impact: +15% average win size expected
3. ATR-Based Take Profit Levels (🔜 6-8 weeks)
Replace fixed % targets with volatility-adaptive ATR multipliers
Progress: [▓░░░░░░░░░] 1/50 trades with ATR (2%)
Status: Phase 1 - Data Collection
Impact: +10% total P&L expected (better hit rates in all conditions)
📈 Combined Expected Impact: 35-40% improvement → Phase 1 goal acceleration from 6-7 months to 4-5 months
📋 View Master Roadmap for detailed timeline and implementation plan
What It Does
- Receives signals from TradingView (5-minute OR 15-minute charts)
- Executes trades on Drift Protocol (Solana DEX) with dual stop-loss system
- Monitors positions every 2 seconds via Pyth Network WebSocket + HTTP fallback
- Closes positions automatically at TP1 (partial) / TP2 (80%) / SL (100%)
- Adjusts stops dynamically (breakeven at +0.5%, profit lock at +1.2%)
- Tracks everything in PostgreSQL (trades, prices, P&L, win rate)
- Provides web UI for configuration, monitoring, and analytics
100% autonomous. Dual-layer safety. No manual intervention required!
Architecture: Dual-Layer Redundancy
Key Design Principle: Every trade has TWO independent exit mechanisms:
-
On-Chain Orders (Drift Protocol) - Primary layer
- TP1/TP2 as LIMIT orders
- Soft SL as TRIGGER_LIMIT (-1.5%, avoids wicks)
- Hard SL as TRIGGER_MARKET (-2.5%, guarantees exit)
-
Software Monitoring (Position Manager) - Backup layer
- Checks prices every 2 seconds
- Closes via MARKET orders if on-chain orders fail
- Dynamic SL adjustments
- Emergency stop functionality
Why? If Drift orders don't fill (low liquidity, network issues), Position Manager acts as backup. Both write to the same PostgreSQL database for complete trade history.
📈 The Money Line v8 Indicator
How It Works (Simple Explanation)
The Money Line is a dynamic support/resistance indicator that adapts to market volatility. Think of it as a "safety zone" - price above = bullish, price below = bearish.
The Core Concept:
- Green line = Bulls in control, momentum up → Go LONG
- Red line = Bears in control, momentum down → Go SHORT
- Line flip = Power shift detected → Enter trade
What Creates the Line
1. ATR (Average True Range)
- Measures how much the market moves on average
- Volatile markets → wider bands, calm markets → tighter bands
- Think: "How much wiggle room does price need?"
2. The Multiplier
- ATR × Multiplier = Distance from price to line
- v8 uses 3.8x for 5min charts (stickier than previous versions)
- Higher multiplier = line changes color less often
3. HalfTrend Algorithm
- Calculates upper band (resistance) and lower band (support)
- Price crosses above upper band → line turns GREEN (bullish)
- Price crosses below lower band → line turns RED (bearish)
- Line "sticks" to its color until price STRONGLY breaks the opposite band
v8 Improvements (Anti-Whipsaw Protection)
Flip Threshold (0.6%)
- Price must move 0.6% beyond the line before it changes color
- Filters tiny bounces that don't mean anything
- Example: Line at $100 → price must hit $100.60 to flip bullish
Entry Buffer (0.2 ATR)
- Confirms the breakout is real, not just a wick
- Waits for price to close beyond line + buffer zone
- Prevents fake signals from sudden spikes
Stickier Bands
- Increased multipliers make the line "lazier" to flip
- Follows major trends, ignores minor corrections
In Simple Terms
"It's like a traffic light for trading:
- Green = Go long (buy)
- Red = Go short (sell)
- The line doesn't change until there's a REAL trend shift, filtering out fake moves.
It adapts to volatility automatically - in crazy markets it needs bigger moves to flip, in calm markets it's more sensitive. This keeps you trading WITH the flow, not against it."
Technical Name: Modified HalfTrend Supertrend with ATR-based adaptive bands and flip threshold confirmation
Street Name: The Money Line 💰
Indicator Versions
- v6: Filtered mode with ADX/volume/RSI confirmations (conservative)
- v7: Pure line flips (too noisy, deprecated)
- v8: Sticky trend with flip threshold + momentum confirmation (current)
All versions available in workflows/trading/ directory.
Quick Start (Docker)
1. Prerequisites
- Docker & Docker Compose installed
- Solana wallet with Drift Protocol account
- Helius RPC API key (mainnet)
- TradingView alerts → n8n webhook setup
2. Deploy with Docker Compose
# Clone and setup
cd /home/icke/traderv4
# Configure .env file (copy from .env.example)
nano .env
# Build and start all services
docker compose up -d
# View logs
docker compose logs -f trading-bot
# Stop
docker compose down
3. Access Web Interface
- Settings UI:
http://YOUR_HOST:3001/settings - Analytics:
http://YOUR_HOST:3001/analytics - API Endpoints:
http://YOUR_HOST:3001/api/
4. Configure Settings
Open http://YOUR_HOST:3001/settings in your browser to:
- Adjust position size ($10-$10,000) and leverage (1x-20x)
- Set stop-loss (-1.5% soft, -2.5% hard) and take-profit levels
- Configure dynamic stop-loss (breakeven +0.5%, profit lock +1.2%)
- Set daily loss limits and max trades per hour
- Toggle DRY_RUN mode for paper trading
After saving, click "Restart Bot" to apply changes.
5. Setup n8n Workflow
Import workflows/trading/Money_Machine.json into your n8n instance:
- Configure TradingView webhook URL
- Set timeframe filters (5min and/or 15min)
- Add API authentication header
- Test with manual execution
Alternative: Manual Setup
1. Install Dependencies
npm install
2. Configure Environment
# Copy and edit .env
cp .env.example .env
# Required variables:
DRIFT_WALLET_PRIVATE_KEY=[your_wallet_array]
SOLANA_RPC_URL=https://mainnet.helius-rpc.com/?api-key=YOUR_KEY
API_SECRET_KEY=your_random_secret_key
DRY_RUN=false
3. Run
# Development
npm run dev
# Production
npm run build
npm start
Core Features
Dual Stop-Loss System
- Soft Stop (TRIGGER_LIMIT): -1.5% from entry, avoids wick-outs
- Hard Stop (TRIGGER_MARKET): -2.5% from entry, guarantees exit
- Both placed on-chain as reduce-only orders
- Position Manager monitors as backup (closes via MARKET if needed)
Dynamic Stop-Loss Adjustments
- Breakeven: Moves SL to +0.01% when price hits +0.5%
- Profit Lock: Locks in profit when price hits +1.2%
- Reduces risk while letting winners run
Take-Profit Strategy
- TP1 (default +0.7%): Closes 50% of position, moves SL to breakeven
- TP2 (default +1.5%): Closes 80% of remaining position
- Runner: 20% remains open if takeProfit2SizePercent < 100%
Position Manager (Singleton)
- Monitors all positions every 2 seconds
- Singleton pattern: Use
getPositionManager()- never instantiate directly - Tracks price updates in database
- Closes positions when targets hit
- Cancels orphaned orders automatically
- Acts as backup if on-chain orders don't fill
Database Integration (PostgreSQL + Prisma)
Models:
Trade: Complete trade history with entry/exit dataPriceUpdate: Price movements every 2 seconds during monitoringSystemEvent: Errors, restarts, important eventsDailyStats: Win rate, profit factor, avg win/loss
Analytics:
- Real-time P&L tracking
- Win rate and profit factor
- Best/worst trades
- Drawdown monitoring
Configuration System (Three-Layer Merge)
- Defaults (
config/trading.ts- DEFAULT_TRADING_CONFIG) - Environment (
.envfile viagetConfigFromEnv()) - Runtime (API overrides via
getMergedConfig(overrides))
Always use getMergedConfig() in business logic - never read env vars directly.
Safety Features
- Reduce-only orders: All TP/SL orders can only close, not open positions
- Account health checks: Validates margin before every trade
- Risk validation:
/api/trading/check-riskendpoint - Daily loss limits: Stops trading after max loss reached
- Cooldown periods: Prevents over-trading
- DRY_RUN mode: Paper trading for testing
How It Works: Complete Trade Flow
1. Signal Reception (TradingView → n8n)
TradingView Alert: "LONG SOLUSDT .P 15"
↓
n8n Webhook receives signal
↓
Parse Signal node extracts:
- Symbol: SOLUSDT → SOL-PERP (normalized)
- Direction: long
- Timeframe: 15 (from .P 15)
↓
Timeframe Filter: Allow 5 or 15 minutes only
↓
Check Risk: Validate position limits, daily loss, etc.
2. Trade Execution (n8n → Next.js API → Drift)
POST /api/trading/execute
↓
getMergedConfig() - Get current settings
↓
initializeDriftService() - Connect to Drift SDK
↓
Check account health (margin requirements)
↓
openPosition() - Execute MARKET order
↓
Calculate dual stop prices (soft -1.5%, hard -2.5%)
↓
placeExitOrders() - Place on-chain TP/SL orders
├─ TP1: LIMIT reduce-only at +0.7%
├─ TP2: LIMIT reduce-only at +1.5%
├─ Soft SL: TRIGGER_LIMIT reduce-only at -1.5%
└─ Hard SL: TRIGGER_MARKET reduce-only at -2.5%
↓
createTrade() - Save to PostgreSQL database
↓
positionManager.addTrade() - Start monitoring loop
3. Position Monitoring (Every 2 Seconds)
Position Manager Loop:
↓
getPythPriceMonitor().getLatestPrice()
↓
Calculate current P&L and percentage gain/loss
↓
Check TP1 hit? → closePosition(75%) + move SL to breakeven
↓
Check TP2 hit? → closePosition(80% of remaining)
↓
Check SL hit? → closePosition(100%)
↓
Check dynamic adjustments:
├─ Price > +0.5%? → Move SL to breakeven (+0.01%)
└─ Price > +1.2%? → Lock profit (move SL to +X%)
↓
addPriceUpdate() - Save price to database
↓
Repeat every 2 seconds until position closed
4. Position Exit (Automatic)
Exit Triggered (TP/SL hit):
↓
If closed by on-chain order:
├─ Position Manager detects position.size === 0
├─ Determines exit reason (TP1/TP2/SL from price)
├─ updateTradeExit() - Save exit data to database
└─ removeTrade() - Stop monitoring + cancel orphaned orders
↓
If closed by Position Manager:
├─ closePosition() - Execute MARKET order
├─ cancelAllOrders() - Cancel remaining on-chain orders
├─ updateTradeExit() - Save exit data to database
└─ removeTrade() - Stop monitoring
5. Order Cleanup (Automatic)
When position closes (100%):
↓
cancelAllOrders(symbol) - Query all open orders
↓
Filter by marketIndex and status === 0 (Open)
↓
driftClient.cancelOrders() - Cancel on Drift
↓
Logs: "Cancelled X orders" or "Cancelled X orphaned orders"
Result: Clean exit with no orphaned orders, complete trade history in database, ready for next signal.
Web Interface
Settings Page (/settings)
Beautiful web interface for managing all trading parameters:
Position Sizing:
- Adjust position size ($10-$10,000 USD)
- Set leverage (1x-20x)
Risk Management:
- Stop-loss percentage (soft -1.5%, hard -2.5%)
- Take-profit 1 & 2 levels
- Emergency stop level
Dynamic Stop-Loss:
- Breakeven trigger (+0.5%)
- Profit lock trigger and amount (+1.2%)
Safety Limits:
- Max daily loss
- Max trades per hour
- Cooldown between trades
Execution:
- Slippage tolerance
- DRY_RUN toggle for testing
Live Risk Calculator:
- Shows max loss in USD
- TP1 and TP2 gains
- Risk/Reward ratio
Analytics Page (/analytics)
Real-time trading performance dashboard:
- Current open positions with live P&L
- Trade history with detailed entry/exit data
- Win rate and profit factor
- Total P&L (daily, weekly, monthly)
- Best and worst trades
- Drawdown tracking
API Endpoints
All endpoints require Authorization: Bearer YOUR_API_SECRET_KEY (except /api/trading/test)
Trade Execution:
# Execute a trade (production - from n8n)
POST /api/trading/execute
{
"symbol": "SOL-PERP",
"direction": "long",
"timeframe": "15",
"signalStrength": "strong"
}
# Test trade (no auth required - from settings UI)
POST /api/trading/test
{
"symbol": "SOL-PERP",
"direction": "long",
"timeframe": "15"
}
# Close a position (partial or full)
POST /api/trading/close
{
"symbol": "SOL-PERP",
"percentToClose": 100 // or 50, 75, etc.
}
# Get active positions
GET /api/trading/positions
# Returns: { positions: [...], monitoring: [...] }
# Validate trade (risk check)
POST /api/trading/check-risk
{
"symbol": "SOL-PERP",
"direction": "long"
}
Settings Management:
# Get current settings
GET /api/settings
# Update settings (writes to .env file)
POST /api/settings
{
"MAX_POSITION_SIZE_USD": 100,
"LEVERAGE": 10,
"STOP_LOSS_PERCENT": -1.5,
"SOFT_STOP_LOSS_PERCENT": -1.5,
"HARD_STOP_LOSS_PERCENT": -2.5,
"TAKE_PROFIT_1_PERCENT": 0.7,
"TAKE_PROFIT_2_PERCENT": 1.5,
"TAKE_PROFIT_2_SIZE_PERCENT": 80,
"BREAKEVEN_TRIGGER_PERCENT": 0.5,
"PROFIT_LOCK_TRIGGER_PERCENT": 1.2,
"DRY_RUN": false
}
# Restart bot container (apply settings)
POST /api/restart
# Creates /tmp/trading-bot-restart.flag
# watch-restart.sh detects flag and runs: docker restart trading-bot-v4
Analytics:
# Get trade statistics
GET /api/analytics/stats
# Returns: { winRate, profitFactor, totalTrades, totalPnL, ... }
# Get recent trades
GET /api/analytics/positions
# Returns: { openPositions: [...], recentTrades: [...] }
Symbol Normalization:
- TradingView sends:
SOLUSDT,BTCUSDT,ETHUSDT - Bot converts to:
SOL-PERP,BTC-PERP,ETH-PERP - Always use Drift format in API calls
Docker Deployment
Architecture
- Multi-stage build: deps → builder → runner (Node 20 Alpine)
- Next.js standalone output for production (~400MB image)
- PostgreSQL 16-alpine for trade history
- Isolated network (172.28.0.0/16)
- Health monitoring and logging
Container Details
-
trading-bot-v4: Main application
- Port: 3001 (external) → 3000 (internal)
- Restart: unless-stopped
- Volumes: .env file mounted
-
trading-bot-postgres: Database
- Port: 5432 (internal only)
- Persistent volume: trading-bot-postgres-data
- Auto-backup recommended
Critical Build Steps
- Install deps:
npm install --production - Copy source and generate Prisma client:
npx prisma generate - Build Next.js:
npm run build(standalone mode) - Runner stage: Copy standalone + static + node_modules + Prisma client
Why Prisma generate before build? The Trade type from Prisma must exist before Next.js compiles TypeScript.
Commands
# Build and deploy
docker compose build trading-bot
docker compose up -d
# View logs (real-time)
docker compose logs -f trading-bot
# View logs (last 100 lines)
docker compose logs --tail=100 trading-bot
# Restart after config changes
docker compose restart trading-bot
# Rebuild and restart (force recreate)
docker compose up -d --force-recreate trading-bot
# Stop everything
docker compose down
# Stop and remove volumes (WARNING: deletes database)
docker compose down -v
Database Operations
# Connect to database
docker exec -it trading-bot-postgres psql -U postgres -d trading_bot_v4
# Run migrations from host
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/trading_bot_v4" npx prisma migrate dev
# Generate Prisma client
npx prisma generate
# View tables
docker exec trading-bot-postgres psql -U postgres -d trading_bot_v4 -c "\dt"
DATABASE_URL caveat: Use trading-bot-postgres (container name) in .env for runtime, but localhost:5432 for Prisma CLI migrations from host.
Restart Watcher (Required for Web UI Restart Button)
The restart watcher monitors for restart requests from the web UI:
# Start watcher manually
cd /home/icke/traderv4
nohup ./watch-restart.sh > logs/restart-watcher.log 2>&1 &
# OR install as systemd service (recommended)
sudo cp trading-bot-restart-watcher.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable trading-bot-restart-watcher
sudo systemctl start trading-bot-restart-watcher
# Check watcher status
sudo systemctl status trading-bot-restart-watcher
The watcher enables the "Restart Bot" button in the web UI to automatically restart the container when settings are changed.
Environment Variables
All settings configured via .env file:
Required:
DRIFT_WALLET_PRIVATE_KEY: Solana wallet (JSON array or base58 string)SOLANA_RPC_URL: Helius RPC endpoint (mainnet recommended)API_SECRET_KEY: Random secret for API authenticationDATABASE_URL: PostgreSQL connection string
Trading Parameters:
MAX_POSITION_SIZE_USD: Position size in USDLEVERAGE: Leverage multiplier (1-20x)STOP_LOSS_PERCENT: Soft stop percentage (e.g., -1.5)HARD_STOP_LOSS_PERCENT: Hard stop percentage (e.g., -2.5)TAKE_PROFIT_1_PERCENT: TP1 target (e.g., 0.7)TAKE_PROFIT_2_PERCENT: TP2 target (e.g., 1.5)TAKE_PROFIT_2_SIZE_PERCENT: How much to close at TP2 (e.g., 80)
Dynamic Stop-Loss:
BREAKEVEN_TRIGGER_PERCENT: Move to breakeven at (e.g., 0.5)PROFIT_LOCK_TRIGGER_PERCENT: Lock profit at (e.g., 1.2)PROFIT_LOCK_AMOUNT_PERCENT: Profit to lock (e.g., 0.5)
Safety:
MAX_DAILY_LOSS: Max loss per day in USDMAX_TRADES_PER_HOUR: Rate limitingTRADE_COOLDOWN_MINUTES: Cooldown between tradesDRY_RUN: Enable paper trading (true/false)USE_DUAL_STOPS: Enable dual stop system (true/false)
Changes to .env require container restart to take effect.
Singleton Services (Critical Pattern)
Never create multiple instances - always use getter functions:
// Drift Client
const driftService = await initializeDriftService() // NOT: new DriftService()
const driftService = getDriftService() // After init
// Position Manager
const positionManager = getPositionManager() // NOT: new PositionManager()
// Database
const prisma = getPrismaClient() // NOT: new PrismaClient()
Creating multiple instances causes connection issues and state inconsistencies.
File Structure
traderv4/
├── README.md ← You are here
├── docker-compose.yml ← Docker orchestration
├── Dockerfile ← Multi-stage build
├── .env ← Configuration (create from .env.example)
├── package.json ← Dependencies (Next.js 15, Drift SDK, Prisma)
├── next.config.js ← Next.js config (standalone output)
├── tsconfig.json ← TypeScript config
│
├── app/ ← Next.js 15 App Router
│ ├── layout.tsx ← Root layout with Tailwind
│ ├── page.tsx ← Home page
│ ├── globals.css ← Global styles
│ ├── settings/
│ │ └── page.tsx ← Settings UI
│ ├── analytics/
│ │ └── page.tsx ← Analytics dashboard
│ └── api/
│ ├── settings/
│ │ └── route.ts ← GET/POST settings, writes to .env
│ ├── restart/
│ │ └── route.ts ← Creates restart flag file
│ ├── analytics/
│ │ ├── stats/route.ts ← Trade statistics
│ │ └── positions/route.ts ← Open/recent positions
│ └── trading/
│ ├── execute/route.ts ← Main execution (production)
│ ├── test/route.ts ← Test execution (UI)
│ ├── close/route.ts ← Close positions
│ ├── positions/route.ts ← Query positions
│ ├── check-risk/route.ts ← Risk validation
│ └── remove-position/route.ts ← Remove from monitoring
│
├── lib/ ← Business logic
│ ├── drift/
│ │ ├── client.ts ← Drift SDK wrapper (singleton)
│ │ └── orders.ts ← Order execution & cancellation
│ ├── pyth/
│ │ └── price-monitor.ts ← WebSocket + HTTP fallback
│ ├── trading/
│ │ └── position-manager.ts ← Monitoring loop (singleton)
│ ├── database/
│ │ ├── trades.ts ← Trade CRUD operations
│ │ └── views.ts ← Analytics queries
│ └── notifications/
│ └── telegram.ts ← Telegram alerts (optional)
│
├── config/
│ └── trading.ts ← Market configs & defaults
│
├── prisma/
│ ├── schema.prisma ← Database models
│ └── migrations/ ← Migration history
│ ├── 20251026200052_init/
│ └── 20251027080947_add_test_trade_flag/
│
├── workflows/ ← n8n workflow JSON files
│ ├── trading/
│ │ └── Money_Machine.json ← Main trading workflow
│ ├── analytics/
│ │ ├── n8n-daily-report.json
│ │ ├── n8n-database-analytics.json
│ │ └── n8n-stop-loss-analysis.json
│ └── telegram/
│ └── telegram-webhook-FINAL.json
│
├── scripts/ ← Utility scripts
│ ├── docker-build.sh
│ ├── docker-start.sh
│ ├── docker-stop.sh
│ ├── docker-logs.sh
│ ├── watch-restart.sh ← Restart watcher daemon
│ ├── send_trade.sh ← Test trade execution
│ └── test-exit-orders.sh ← Test exit order placement
│
├── tests/ ← Test files
│ ├── test-drift-v4.ts
│ ├── test-full-flow.ts
│ ├── test-position-manager.ts
│ └── test-price-monitor.ts
│
├── docs/ ← Documentation
│ ├── SETUP.md ← Detailed setup guide
│ ├── DOCKER.md ← Docker deployment
│ ├── TESTING.md ← Testing guide
│ ├── TELEGRAM_BOT_README.md ← Telegram setup
│ ├── N8N_WORKFLOW_SETUP.md ← n8n configuration
│ ├── PHASE_2_COMPLETE.md ← Phase 2 features
│ └── QUICKREF_PHASE2.md ← Quick reference
│
└── logs/ ← Log files (created at runtime)
Documentation
| Document | Purpose |
|---|---|
README.md |
This overview |
docs/setup/SETUP.md |
Detailed setup instructions |
docs/setup/DOCKER.md |
Docker deployment guide |
docs/setup/TELEGRAM_BOT_README.md |
Telegram bot setup |
docs/guides/TESTING.md |
Comprehensive testing guide |
docs/history/PHASE_2_COMPLETE.md |
Phase 2 feature overview |
workflows/trading/ |
n8n workflow files |
../N8N_SETUP_GUIDE.md- n8n configuration
Trade Example (Real-World Flow)
Entry Signal from TradingView
Alert Message: "LONG SOLUSDT .P 15"
↓
n8n receives webhook
↓
Parse: symbol=SOL-PERP, direction=long, timeframe=15
↓
Timeframe check: 15 minutes ✅ (allowed)
↓
Risk check: Daily loss OK, no existing position ✅
↓
Execute trade via API
Position Opened
Symbol: SOL-PERP
Direction: LONG
Entry: $200.00
Position Size: $100 (10x leverage = $1,000 notional)
On-Chain Orders Placed:
├─ TP1: LIMIT at $201.40 (+0.7%) - Close 50%
├─ TP2: LIMIT at $203.00 (+1.5%) - Close 80% of remaining
├─ Soft SL: TRIGGER_LIMIT at $197.00 (-1.5%)
└─ Hard SL: TRIGGER_MARKET at $195.00 (-2.5%)
Position Manager: ✅ Monitoring started (every 2s)
Database: ✅ Trade #601 saved
TP1 Hit (First Target)
Price reaches $201.40
↓
On-chain TP1 order fills → 50% closed
↓
Position Manager detects partial close:
├─ Profit: +$7.00 (+7% account)
├─ Remaining: 50% ($500 notional)
├─ Move SL to breakeven: $200.02 (+0.01%)
└─ Trade is now RISK-FREE ✅
↓
Database updated: exitReason=TP1_PARTIAL
Price Continues Higher
Price reaches $202.44 (+1.22%)
↓
Position Manager dynamic adjustment:
├─ Trigger: +1.2% profit lock activated
├─ Move SL to: $201.00 (+0.5% profit locked)
└─ Letting winner run with locked profit ✅
TP2 Hit (Second Target)
Price reaches $203.00
↓
On-chain TP2 order fills → 80% of remaining closed (40% of original)
↓
Position Manager detects:
├─ Profit from TP2: +$6.00
├─ Remaining: 10% runner ($100 notional)
└─ Runner continues with locked profit SL
↓
Database updated: exitReason=TP2_PARTIAL
Final Exit (Runner)
Option 1: Runner hits new high → Manual/trailing stop
Option 2: Price pulls back → Locked profit SL hits at $201.00
Option 3: Emergency stop or manual close
Total P&L:
├─ TP1: +$7.00 (50% at +0.7%)
├─ TP2: +$6.00 (40% at +1.5%)
└─ Runner: +$3.00 (10% at +3.0%, closed at pullback)
═══════════════════
Total: +$16.00 (+16% account growth)
Database: ✅ Trade #601 complete
If Stop-Loss Hit Instead
Price drops to $197.00
↓
Soft SL (TRIGGER_LIMIT) activates:
├─ Triggers at $197.00
├─ Limit order at $196.95 (avoid wick)
└─ If fills → Position closed ✅
↓
If soft SL doesn't fill (low liquidity):
├─ Price drops to $195.00
├─ Hard SL (TRIGGER_MARKET) activates
└─ Market order guarantees exit ✅
↓
Position Manager backup:
├─ Detects position still open at -2.5%
└─ Closes via MARKET order if needed
↓
Loss: -$25.00 (-2.5% account)
Database: ✅ exitReason=STOP_LOSS
Key Points:
- Dual stop system ensures exit even in volatile markets
- Position Manager acts as backup to on-chain orders
- Dynamic SL makes trades risk-free after +0.5%
- Profit lock captures gains before reversals
- Complete audit trail in database
Common Issues & Solutions
"Drift service not initialized"
Cause: Drift client not connected before trade execution
Solution: Ensure initializeDriftService() called before operations
"Position not found in monitoring"
Cause: Race condition - orders placed after Position Manager started Solution: ✅ FIXED - Orders now placed before monitoring starts
"Orphaned orders after exit"
Cause: Old bug - Position Manager detected closure before orders existed Solution: ✅ FIXED - Order placement sequencing corrected Cleanup: Cancel manually on Drift UI or wait for next trade's auto-cleanup
"TP2 closes entire position instead of 80%"
Cause: Old bug - TP2 calculated from original position instead of remaining Solution: ✅ FIXED - TP2 now calculates from remaining after TP1
"Database save failed but trade executed"
Cause: PostgreSQL connection issue or schema mismatch Solution: Trade still executes successfully, check database logs and fix connection
"Prisma Client not generated" (Docker build)
Cause: npx prisma generate not run before npm run build
Solution: Ensure Dockerfile runs Prisma generate in builder stage
"Wrong DATABASE_URL" (localhost vs container)
Container runtime: Use trading-bot-postgres:5432 in .env
Prisma CLI (host): Use localhost:5432 for migrations
Solution: Maintain two DATABASE_URL values for different contexts
Container won't restart after settings change
Cause: Restart watcher not running Solution:
sudo systemctl status trading-bot-restart-watcher
sudo systemctl start trading-bot-restart-watcher
Safety Guidelines
- Start Small: Use $10-50 positions for first 20 trades
- Test Thoroughly:
- Run with DRY_RUN=true first
- Execute test trades from settings UI
- Verify all exits work correctly
- Monitor Closely: Watch first 10 auto-exits in real-time
- Verify Database: Check that all trades are being saved correctly
- Check Drift UI: Confirm positions and orders match expectations
- Scale Gradually: Increase position size 2x per week maximum
- Daily Review: Check analytics page every day
- Backup Database: Export PostgreSQL data weekly
Risk Warning: Cryptocurrency trading involves substantial risk. This bot executes trades automatically. Start small and never risk more than you can afford to lose.
Testing Commands
# 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
# Test trade from UI
# Go to http://localhost:3001/settings
# Click "Test LONG" or "Test SHORT"
# Test trade from terminal
./send_trade.sh LONG SOL-PERP 15
# Check current positions
curl -s -X GET http://localhost:3001/api/trading/positions \
-H "Authorization: Bearer YOUR_API_SECRET_KEY" | jq
# Test exit order placement
./test-exit-orders.sh
# Database operations
npx prisma generate
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/trading_bot_v4" npx prisma migrate dev
docker exec trading-bot-postgres psql -U postgres -d trading_bot_v4 -c "SELECT * FROM \"Trade\" ORDER BY \"createdAt\" DESC LIMIT 5;"
# Check logs
docker compose logs --tail=100 trading-bot
docker compose logs -f trading-bot | grep "Position Manager"
Documentation
| Document | Purpose |
|---|---|
README.md |
Complete system overview (this file) |
docs/SETUP.md |
Detailed setup instructions |
docs/DOCKER.md |
Docker deployment guide |
docs/TESTING.md |
Comprehensive testing guide |
docs/TELEGRAM_BOT_README.md |
Telegram bot setup |
docs/N8N_WORKFLOW_SETUP.md |
n8n workflow configuration |
docs/PHASE_2_COMPLETE.md |
Phase 2 features and architecture |
docs/QUICKREF_PHASE2.md |
Quick reference guide |
.github/copilot-instructions.md |
AI agent instructions (architecture) |
Resources
- Drift Protocol: https://drift.trade
- Drift Docs: https://docs.drift.trade
- Drift SDK: https://github.com/drift-labs/protocol-v2
- Pyth Network: https://pyth.network
- Solana RPC: https://helius.dev (recommended)
- Next.js: https://nextjs.org
- Prisma ORM: https://prisma.io
Development Notes
Key Patterns to Follow
- Singleton Services: Always use getter functions, never instantiate directly
- Configuration: Always use
getMergedConfig(), never read env vars directly - Database Errors: Wrap in try/catch, don't fail trades on DB errors
- Price Calculations: Direction matters - long vs short use opposite math
- Reduce-Only Orders: All TP/SL orders MUST have
reduceOnly: true - Symbol Normalization: Always use
normalizeTradingViewSymbol()
Adding New Features
- New Config: Update DEFAULT_TRADING_CONFIG + getConfigFromEnv() + .env
- New Database Fields: Update schema.prisma → migrate → regenerate → rebuild Docker
- New API Endpoint: Follow auth pattern, use getMergedConfig(), init services
- Order Logic Changes: Test with DRY_RUN=true first, use small positions
Recent Bug Fixes (Oct 2024)
- ✅ TP2 runner calculation: Now uses remaining position after TP1
- ✅ Race condition: Exit orders now placed BEFORE monitoring starts
- ✅ Order cancellation: removeTrade() properly cancels orphaned orders
- ✅ Dynamic SL: Breakeven at +0.5%, profit lock at +1.2%
Ready to trade autonomously? Start with docs/SETUP.md and test with DRY_RUN=true! 🚀
Dual-layer safety. Complete audit trail. Built for reliability.