**Issue 1: TP2 Runner Position Bug** ✅ FIXED
- TP2 was calculated as 80% of ORIGINAL position instead of REMAINING
- With TP1=75%, TP2=80%: Was closing 75%+80%=155% (capped at 100%)
- Now correctly: TP1 closes 75%, TP2 closes 80% of remaining 25% = 20%
- Result: 5% runner now remains for trailing stop as intended!
**Issue 2: Race Condition - Orphaned SL Orders** ✅ FIXED
- Orders were placed AFTER Position Manager started monitoring
- If TP hit fast, PM detected 'external closure' before orders finished
- Orders completed after position gone → orphaned SL orders on Drift
- Now: Exit orders placed BEFORE starting monitoring
- PM can now properly cancel remaining orders when position closes
**Issue 3: 5min vs 15min Timeframe** ⚠️ NEEDS VERIFICATION
- n8n workflow correctly filters for timeframe === '15'
- Extracts timeframe with regex: /\.P\s+(\d+)/
- User needs to verify TradingView alert includes '.P 15' in message
- Format should be: 'SOL buy .P 15' not just 'SOL buy'
**Technical Changes:**
- lib/drift/orders.ts: Fixed TP2 calculation to use remaining size
- Added logging: Shows TP1, TP2, remaining, and runner amounts
- app/api/trading/execute/route.ts: Reordered to place orders before monitoring
- Prevents race condition where orders complete after position closed
**Testing:**
- Next trade will show proper runner position (5% remains)
- No more orphaned SL orders after wins
- Logs will show: 'Runner (if any): $X.XX'
**Documentation:**
- Created CRITICAL_ISSUES_FOUND.md explaining all 3 issues
- Created FIXES_APPLIED.md with testing instructions
**Root Cause:** Position Manager didn't detect when on-chain TP/SL orders closed positions externally, causing endless error loops and stale position data.
**Issues Fixed:**
1. Position Manager now checks if on-chain position still exists before attempting to close
2. Detects external closures (by on-chain orders) and updates database accordingly
3. Determines likely exit reason based on price vs TP/SL levels
4. Automatically cancels leftover orders when position detected as closed
5. Analytics now properly shows stopped-out trades
**Technical Changes:**
- Added position existence check at start of checkTradeConditions()
- Calls DriftService.getPosition() to verify on-chain state
- Updates database with exitPrice, exitReason, realizedPnL when external closure detected
- Removes trade from monitoring after external closure
- Handles size mismatches for partial closes (TP1 hit externally)
**Database Fix:**
- Manually closed orphaned trade (stopped out 9 hours ago but still marked 'open')
- Calculated and set realizedPnL = -$12.00 for stopped-out SHORT position
- Analytics now shows 3 total trades instead of missing the SL exit
**Testing:**
- Bot starts cleanly with no error loops
- Position monitoring active with 0 trades (as expected)
- Analytics correctly shows stopped-out trade in statistics
- Changed /api/trading/positions to use getInitializedPositionManager()
- Changed /api/trading/test to use getInitializedPositionManager()
- Changed /api/trading/test-db to use getInitializedPositionManager()
- These endpoints were accessing Position Manager before DB restore completed
- Now properly wait for async initialization before accessing trade data
- Fixes /status Telegram command showing empty despite active positions
- Added /close Telegram command for full position closure
- Updated /reduce to accept 10-100% (was 10-90%)
- Implemented auto-flip logic: automatically closes opposite position when signal reverses
- Fixed risk check to allow opposite direction trades (signal flips)
- Enhanced Position Manager to cancel orders when removing trades
- Added startup initialization for Position Manager (restores trades on restart)
- Fixed analytics to show stopped-out trades (manual DB update for orphaned trade)
- Updated reduce endpoint to route 100% closes through closePosition for proper cleanup
- All position closures now guarantee TP/SL order cancellation on Drift
- New endpoint: /api/trading/reduce-position to take partial profits
- Closes specified percentage at market price
- Recalculates and places new TP/SL orders for remaining size
- Entry price stays the same, only size is reduced
- Telegram command: /reduce [percent] (default 50%, range 10-90%)
- Shows realized P&L from the closed portion
- Example: /reduce 25 closes 25% and updates orders for remaining 75%
- New endpoint: /api/trading/scale-position to add to existing positions
- Calculates new average entry price after adding more size
- Cancels old TP/SL orders and places new ones at updated levels
- Telegram command: /scale [percent] (default 50%)
- Example: /scale 100 doubles your position
- Automatically adjusts Position Manager tracking with new values
- Cleaned up stale duplicate trade from database
- New endpoint: /api/trading/remove-position for manually removing stale positions
- Removed duplicate position from tracking (second SOL-PERP position)
- System now correctly shows 1 active position matching Drift
- Validation and analytics will now show accurate position count
- Updated .env with correct TELEGRAM_BOT_TOKEN and N8N_WEBHOOK_URL
- Added env_file directive to docker-compose.telegram-bot.yml
- Telegram bot now starts successfully with /validate command working
- New API endpoint: /api/trading/validate-positions
- Validates TP1, TP2, SL, leverage, and position size against current settings
- Fixed position size calculation: config stores collateral, positions store total value
- Added /validate command to Telegram bot for remote checking
- Returns detailed report of any mismatches with expected vs actual values
- Updated risk check API to verify no existing positions on same symbol
- Use getInitializedPositionManager() to wait for trade restoration
- Updated .dockerignore to exclude test files and archive/
- Moved test-*.ts files to archive directory
- Prevents multiple positions from being opened on same symbol even if signals are valid
- Extract timeframe from TradingView message format: 'SOLUSDT.P 15'
- Added 'timeframe-filter' IF node after Parse Signal
- Only allows trades on 15-minute chart signals
- Blocks 5-minute and other timeframe signals
- Regex pattern: \.P\s+(\d+) matches '.P 15' format
This prevents bot from trading on wrong timeframe alerts.
- CLEANUP_PLAN.md: Detailed plan for organizing workspace structure
- SAFETY_ANALYSIS.md: Analysis proving no runtime dependencies will break
- RECOVERY_PLAN.md: Step-by-step recovery procedures if anything goes wrong
All analysis complete - ready to execute cleanup safely.
Files document current state and recovery methods.
- Implemented /status command handler in telegram_command_bot.py
- Shows real-time P&L, entry/current prices, TP/SL levels, position info
- Added TRADING_BOT_URL and API_SECRET_KEY environment variables
- Updated docker-compose.telegram-bot.yml with new env vars
- Bot connects to trading-bot-v4:3000 API via internal Docker network
- Added comprehensive documentation and testing guides
- Command displays formatted position info with emojis (profit/loss indicators)
- Shows 'No open positions' message when no trades active
- Implemented trailing stop logic in Position Manager for remaining position after TP2
- Added new ActiveTrade fields: tp2Hit, trailingStopActive, peakPrice
- New config settings: useTrailingStop, trailingStopPercent, trailingStopActivation
- Added trailing stop UI section in settings page with explanations
- Fixed env file parsing regex to support numbers in variable names (A-Z0-9_)
- Settings now persist correctly across container restarts
- Added back arrow navigation on settings page
- Updated all API endpoints and test files with new fields
- Trailing stop activates when runner reaches configured profit level
- SL trails below peak price by configurable percentage
- Add Position Manager state persistence to survive restarts
- Auto-restore open trades from database on startup
- Save state after TP1, SL adjustments, profit locks
- Persist to configSnapshot JSON field
- Add automatic order cancellation
- Cancel all TP/SL orders when position fully closed
- New cancelAllOrders() function in drift/orders.ts
- Prevents orphaned orders after manual closes
- Improve stop loss management
- Move SL to +0.35% after TP1 (was +0.15%)
- Gives more breathing room for retracements
- Still locks in half of TP1 profit
- Add database sync when Position Manager closes trades
- Auto-update Trade record with exit data
- Save P&L, exit reason, hold time
- Fix analytics showing stale data
- Add trade state management functions
- updateTradeState() for Position Manager persistence
- getOpenTrades() for startup restoration
- getInitializedPositionManager() for async init
- Create n8n database analytics workflows
- Daily report workflow (automated at midnight)
- Pattern analysis (hourly/daily performance)
- Stop loss effectiveness analysis
- Database analytics query workflow
- Complete setup guide (N8N_DATABASE_SETUP.md)
- Created landing page at / with navigation to analytics and settings
- Built analytics dashboard at /analytics showing:
- Current positions (net vs individual)
- Trading statistics (win rate, P&L, profit factor)
- Time period selector (7/30/90/365 days)
- Position netting explanation
- Beautiful gradient UI matching settings page style
- Real-time data from database via API endpoints
- Auto-excludes test trades from statistics
- Shows net positions matching Drift UI behavior
- Fixed Prisma client not being available in Docker container
- Added isTestTrade flag to exclude test trades from analytics
- Created analytics views for net positions (matches Drift UI netting)
- Added API endpoints: /api/analytics/positions and /api/analytics/stats
- Added test trade endpoint: /api/trading/test-db
- Updated Dockerfile to properly copy Prisma client from builder stage
- Database now successfully stores all trades with full details
- Supports position netting calculations to match Drift perpetuals behavior
- 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
- Split test trade button into separate LONG and SHORT buttons
- Update testTrade function to accept direction parameter
- Add confirmation dialog showing the specific direction
- Green button for LONG, red button for SHORT
- Success message includes executed direction
- Add PostgreSQL database with Prisma ORM
- Trade model: tracks entry/exit, P&L, order signatures, config snapshots
- PriceUpdate model: tracks price movements for drawdown analysis
- SystemEvent model: logs errors and system events
- DailyStats model: aggregated performance metrics
- Implement dual stop loss system (enabled by default)
- Soft stop (TRIGGER_LIMIT) at -1.5% to avoid wicks
- Hard stop (TRIGGER_MARKET) at -2.5% to guarantee exit
- Configurable via USE_DUAL_STOPS, SOFT_STOP_PERCENT, HARD_STOP_PERCENT
- Backward compatible with single stop modes
- Add database service layer (lib/database/trades.ts)
- createTrade(): save new trades with all details
- updateTradeExit(): close trades with P&L calculations
- addPriceUpdate(): track price movements during trade
- getTradeStats(): calculate win rate, profit factor, avg win/loss
- logSystemEvent(): log errors and system events
- Update execute endpoint to use dual stops and save to database
- Calculate dual stop prices when enabled
- Pass dual stop parameters to placeExitOrders
- Save complete trade record to database after execution
- Add test trade button to settings page
- New /api/trading/test endpoint for executing test trades
- Displays detailed results including dual stop prices
- Confirmation dialog before execution
- Shows entry price, position size, stops, and TX signature
- Generate Prisma client in Docker build
- Update DATABASE_URL for container networking
- Changed SL from TRIGGER_LIMIT to TRIGGER_MARKET
- Guarantees SL execution even during volatile moves/gaps
- Added optional TRIGGER_LIMIT mode for very liquid markets
- TP orders remain as LIMIT for price precision
- Follows best practice: stop-market for SL, limit for TP
- Changed from LIMIT to TRIGGER_LIMIT for proper stop loss display
- SL now shows correctly on Drift UI with trigger line
- Added 0.5% buffer on limit price below trigger for safety
- Widened default SL to -2% for safer testing
- Tested and verified all 3 exit orders (TP1, TP2, SL) working
- Add placeExitOrders() to create reduce-only LIMIT orders for TP1, TP2, and SL
- Orders now visible in Drift UI
- Tested with real tiny position (0 base x 5x = 0)
- All 3 exit orders placed successfully on-chain
- Position manager continues monitoring as backup
- Added test script and results documentation
- Added TAKE_PROFIT_1_SIZE_PERCENT env var
- Added TAKE_PROFIT_2_SIZE_PERCENT env var
- These were missing causing container to use defaults
- Requires 'docker compose up -d --force-recreate' not just restart
**New Features:**
- Added TAKE_PROFIT_1_SIZE_PERCENT (default: 50%)
- Added TAKE_PROFIT_2_SIZE_PERCENT (default: 50%)
- Users can now control WHAT % to close at each TP level
- Risk calculator now shows actual TP sizes dynamically
**Bug Fixes:**
- Fixed settings save failure by mounting .env file to container
- Added .env volume mount in docker-compose.yml
- Fixed permission issues (.env must be chmod 666)
**UI Changes:**
- Split TP controls into Price % and Size %
- TP1 Price: When to exit first partial
- TP1 Size: What % of position to close (1-100%)
- TP2 Price: When to exit second partial
- TP2 Size: What % of remaining to close (1-100%)
- Risk calculator displays dynamic percentages
**Example:**
- TP1 at +1% price, close 60% of position
- TP2 at +2% price, close 40% of remaining (24% of original)
- Total exit: 84% of position at TP levels
- Added restart button to settings page
- Created /api/restart endpoint (file-flag based)
- Implemented watch-restart.sh daemon
- Added systemd service for restart watcher
- Updated README with restart setup instructions
- Container automatically restarts when settings changed
Settings flow:
1. User edits settings in web UI
2. Click 'Save Settings' to persist to .env
3. Click 'Restart Bot' to apply changes
4. Watcher detects flag and restarts container
5. New settings loaded automatically
- Added Docker deployment section with architecture details
- Documented web interface (/settings) features
- Added API endpoint examples for all operations
- Updated Phase 3 status to COMPLETE
- Added settings management API documentation
- Included Docker commands and container details
- Updated file structure to reflect current layout
Features:
- Autonomous trading system with Drift Protocol on Solana
- Real-time position monitoring with Pyth price feeds
- Dynamic stop-loss and take-profit management
- n8n workflow integration for TradingView signals
- Beautiful web UI for settings management
- REST API for trade execution and monitoring
- Next.js 15 with standalone output mode
- TypeScript with strict typing
- Docker containerization with multi-stage builds
- PostgreSQL database for trade history
- Singleton pattern for Drift client connection pooling
- BN.js for BigNumber handling (Drift SDK requirement)
- Configurable stop-loss and take-profit levels
- Breakeven trigger and profit locking
- Daily loss limits and trade cooldowns
- Slippage tolerance controls
- DRY_RUN mode for safe testing
- Real-time risk calculator
- Interactive sliders for all parameters
- Live preview of trade outcomes
- Position sizing and leverage controls
- Beautiful gradient design with Tailwind CSS
- POST /api/trading/execute - Execute trades
- POST /api/trading/close - Close positions
- GET /api/trading/positions - Monitor active trades
- GET /api/trading/check-risk - Validate trade signals
- GET /api/settings - View configuration
- POST /api/settings - Update configuration
- Fixed Borsh serialization errors (simplified order params)
- Resolved RPC rate limiting with singleton pattern
- Fixed BigInt vs BN type mismatches
- Corrected order execution flow
- Improved position state management
- Complete setup guides
- Docker deployment instructions
- n8n workflow configuration
- API reference documentation
- Risk management guidelines
- Runs on port 3001 (external), 3000 (internal)
- Uses Helius RPC for optimal performance
- Production-ready with error handling
- Health monitoring and logging