Commit Graph

30 Commits

Author SHA1 Message Date
mindesbunister
0ed2e89c7e feat: implement per-symbol cooldown period
CRITICAL: Cooldown was global across ALL symbols, causing missed opportunities
Example: ETH trade at 10:00 blocked SOL trade at 10:04 (5min cooldown)

Changes:
- Added getLastTradeTimeForSymbol() function to query last trade per symbol
- Updated check-risk endpoint to use symbol-specific cooldown
- Each coin (SOL/ETH/BTC) now has independent cooldown timer
- Cooldown message shows symbol: 'Must wait X min before next SOL-PERP trade'

Result: Can trade ETH and SOL simultaneously without interference
Example: ETH LONG at 10:00, SOL SHORT at 10:01 = both allowed
2025-11-03 08:01:30 +01:00
mindesbunister
d4aeeb4f99 fix: add MAE/MFE fields to all ActiveTrade initializations
Updated execute, test, and test-db endpoints to include:
- maxFavorableExcursion: 0
- maxAdverseExcursion: 0
- maxFavorablePrice: entryPrice
- maxAdversePrice: entryPrice

Required for TypeScript compilation after adding MAE/MFE tracking
2025-11-02 23:04:02 +01:00
mindesbunister
32e88c3823 fix: improve signal quality scoring for volume breakouts
- Lower ATR threshold from 0.6% to 0.15% (allows low volatility breakouts)
- Increase volume bonus: +15 for very strong volume (1.5x+), was +10 for 1.2x+
- Add volume breakout logic: High volume (1.4x+) at 95%+ range gets +5 instead of -15 penalty
- Add volume compensation: +10 bonus when volume >1.8x and ATR <0.6%
- Example: SOL signal with 0.18% ATR, 1.74x volume at 95.6% range now scores 70/100 (PASS) instead of 25/100 (BLOCK)
- This signal moved +0.97% and would have hit TP1 (+1.5%) - proves quality scoring was too conservative
- Changes apply globally to all symbols (SOL, ETH, BTC) using same scoring algorithm
2025-11-02 09:10:03 +01:00
mindesbunister
056440bf8f feat: add quality score display and timezone fixes
- Add qualityScore to ExecuteTradeResponse interface and response object
- Update analytics page to always show Signal Quality card (N/A if unavailable)
- Fix n8n workflow to pass context metrics and qualityScore to execute endpoint
- Fix timezone in Telegram notifications (Europe/Berlin)
- Fix symbol normalization in /api/trading/close endpoint
- Update Drift ETH-PERP minimum order size (0.002 ETH not 0.01)
- Add transaction confirmation to closePosition() to prevent phantom closes
- Add 30-second grace period for new trades in Position Manager
- Fix execution order: database save before Position Manager.addTrade()
- Update copilot instructions with transaction confirmation pattern
2025-11-01 17:00:37 +01:00
mindesbunister
49a09ef04e Add 'Clear Manual Closes' button to analytics
- New button in analytics page to clear orphaned trades
- API endpoint /api/trading/clear-manual-closes
- Intelligently checks Drift positions before deleting
- Only removes trades with no matching position or mismatched entry price
- Safe operation: keeps trades on error (false positives better than deletions)
- User-friendly confirmation dialog
2025-11-01 02:41:26 +01:00
mindesbunister
a6005b6a5b Add configurable minimum quality score setting
- Added minQualityScore to TradingConfig (default: 60)
- Updated settings UI with slider control (0-100, step 5)
- Updated check-risk endpoint to use config value
- Made scoreSignalQuality function accept minScore parameter
- Updated API to read/write MIN_QUALITY_SCORE env variable
- Allows users to adjust quality threshold from settings page
2025-11-01 01:59:08 +01:00
mindesbunister
6f1c7bd5e3 fix: update test endpoint to use symbol-specific position sizing 2025-10-31 16:34:25 +01:00
mindesbunister
26f70c6426 feat: implement symbol-specific position sizing for multi-asset trading
- Extended MarketConfig with optional positionSize and leverage fields
- Configured ETH-PERP at  @ 1x leverage for minimal-risk data collection
- Created getPositionSizeForSymbol() helper function in config/trading.ts
- Integrated symbol-specific sizing into execute endpoint
- Added comprehensive guide in docs/guides/SYMBOL_SPECIFIC_SIZING.md

Purpose: Enable ETH trading for faster signal quality data collection
         while preserving SOL's profit-generation sizing (0 @ 10x)

Next: Create ETH alert in TradingView and restart bot
2025-10-31 16:16:03 +01:00
mindesbunister
090b79a07f Store signal quality score in database for future analysis
- Add signalQualityScore field to Trade model (0-100)
- Calculate quality score in execute endpoint using same logic as check-risk
- Save score with every trade for correlation analysis
- Create database migration for new field
- Enables future analysis: score vs win rate, P&L, etc.

This allows data-driven decisions on dynamic position sizing
2025-10-31 11:12:07 +01:00
mindesbunister
37ce94d8f1 Restore context metrics in execute endpoint and clean up test files 2025-10-31 09:09:26 +01:00
mindesbunister
830468d524 Implement signal quality scoring system
- Updated execute endpoint to store context metrics in database
- Updated CreateTradeParams interface with 5 context metrics
- Updated Prisma schema with rsiAtEntry and pricePositionAtEntry
- Ran migration: add_rsi_and_price_position_metrics
- Complete flow: TradingView → n8n → check-risk (scores) → execute (stores)
2025-10-30 19:31:32 +01:00
mindesbunister
7c4adff4e4 Implement risk checks: cooldown, hourly limit, and daily drawdown
Implemented 3 critical risk checks in /api/trading/check-risk:

1. Daily Drawdown Check
   - Blocks trades if today's P&L < maxDailyDrawdown
   - Prevents catastrophic daily losses
   - Currently: -0 limit (configurable via MAX_DAILY_DRAWDOWN)

2. Hourly Trade Limit
   - Blocks trades if tradesInLastHour >= maxTradesPerHour
   - Prevents overtrading / algorithm malfunction
   - Currently: 20 trades/hour (configurable via MAX_TRADES_PER_HOUR)

3. Cooldown Period
   - Blocks trades if timeSinceLastTrade < minTimeBetweenTrades
   - Enforces breathing room between trades
   - Uses minutes (not seconds) thanks to previous commit
   - Currently: 0 min = disabled (configurable via MIN_TIME_BETWEEN_TRADES)

Added database helper functions:
- getLastTradeTime() - Returns timestamp of most recent trade
- getTradesInLastHour() - Counts trades in last 60 minutes
- getTodayPnL() - Sums realized P&L since midnight

All checks include detailed logging with values and thresholds.
Risk check called by n8n workflow before every trade execution.
2025-10-30 10:50:08 +01:00
mindesbunister
e068c5f2e6 Phase 2: Market context capture at entry
- Added getFundingRate() method to DriftService
- Capture expectedEntryPrice from oracle before order execution
- Capture fundingRateAtEntry from Drift Protocol
- Save market context fields to database (expectedEntryPrice, fundingRateAtEntry)
- Calculate entry slippage percentage in createTrade()
- Fixed template literal syntax errors in execute endpoint

Database fields populated:
- expectedEntryPrice: Oracle price before order
- entrySlippagePct: Calculated from entrySlippage
- fundingRateAtEntry: Current funding rate from Drift

Next: Phase 3 (analytics API) or test market context on next trade
2025-10-29 20:51:46 +01:00
mindesbunister
65e6a8efed Phase 1: Add MAE/MFE tracking and analytics schema
- Added 20+ analytics fields to Trade model (MAE/MFE, fill tracking, timing, market context, slippage)
- Implemented real-time MAE/MFE tracking in Position Manager (updates every 5s)
- Enhanced database schema with comprehensive trade analytics
- Updated all API endpoints to initialize MAE/MFE fields
- Modified updateTradeState() to persist MAE/MFE in configSnapshot

Database changes:
- maxFavorableExcursion/maxAdverseExcursion track best/worst profit %
- maxFavorablePrice/maxAdversePrice track exact price levels
- Fill tracking: tp1Filled, tp2Filled, softSlFilled, hardSlFilled
- Timing metrics: timeToTp1, timeToTp2, timeToSl
- Market context: atrAtEntry, adxAtEntry, volumeAtEntry, fundingRateAtEntry, basisAtEntry
- Slippage tracking: expectedEntryPrice, entrySlippagePct, expectedExitPrice, exitSlippagePct

Position Manager changes:
- Track MAE/MFE on every price check (2s interval)
- Throttled database updates (5s interval) via updateTradeMetrics()
- Persist MAE/MFE in trade state snapshots for recovery

Next: Phase 2 (market context capture) or Phase 3 (analytics API)
2025-10-29 20:34:03 +01:00
mindesbunister
797e80b56a CRITICAL FIX: TP/SL orders using wrong size calculation
**ROOT CAUSE:** placeExitOrders() calculated position size using TP/SL prices instead of entry price

**Problem:**
- TP1 order size: 85 / TP1_price (00.746) = 2.914 SOL
- Actual position: 80 / entry_price (99.946) = 3.901 SOL
- TP1 should close: 3.901 * 75% = 2.926 SOL
- But it only closed: 2.914 SOL = 74.7%  WRONG!

**Result:** TP1 closed ~25% instead of 75%, no runner left

**Fix:**
- Changed usdToBase() to use entryPrice for ALL size calculations
- Added entryPrice param to PlaceExitOrdersOptions interface
- Updated all API routes to pass entryPrice

**Testing:** Next trade will have correctly sized TP/SL orders
2025-10-29 17:34:10 +01:00
mindesbunister
e8a9b68fa7 Fix: Critical bugs - TP2 runner calculation + race condition + order cleanup
**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
2025-10-28 10:12:04 +01:00
mindesbunister
a72ddd8f0e Fix: Position Manager initialization race condition in API endpoints
- 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
2025-10-27 23:38:24 +01:00
mindesbunister
9bf83260c4 Add /close command and auto-flip logic with order cleanup
- 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
2025-10-27 23:27:48 +01:00
mindesbunister
a07bf9f4b2 Add position reduction feature via Telegram
- 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%
2025-10-27 20:34:47 +01:00
mindesbunister
1acb5e7210 Add position scaling feature via Telegram
- 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
2025-10-27 20:24:06 +01:00
mindesbunister
6a04d3469f Add remove-position endpoint and clean up stale position
- 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
2025-10-27 19:58:57 +01:00
mindesbunister
dde25ad2c1 Add position validation endpoint and Telegram /validate command
- 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
2025-10-27 19:20:36 +01:00
mindesbunister
8f90339d8d Add duplicate position prevention to risk check
- 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
2025-10-27 19:08:07 +01:00
mindesbunister
4ae9c38ad8 Add trailing stop feature for runner position + fix settings persistence
- 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
2025-10-27 12:11:10 +01:00
mindesbunister
d3c04ea9c9 feat: Position Manager persistence + order cleanup + improved stop loss
- 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)
2025-10-27 10:39:05 +01:00
mindesbunister
8e5c592cac Fix database persistence and add analytics
- 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
2025-10-27 09:35:01 +01:00
mindesbunister
b82ceb49a4 feat: add position size and leverage to Telegram confirmation message 2025-10-27 01:06:51 +01:00
mindesbunister
d64f6d84c4 feat: implement dual stop system and database tracking
- 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
2025-10-26 21:29:27 +01:00
mindesbunister
4cc294baef feat: Add on-chain TP/SL order placement
- 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
2025-10-26 13:30:07 +01:00
mindesbunister
2405bff68a feat: Complete Trading Bot v4 with Drift Protocol integration
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
2025-10-24 14:24:36 +02:00