Files
trading_bot_v4/docs/history/DUPLICATE_POSITION_FIX.md
2025-10-27 19:08:52 +01:00

4.6 KiB

Duplicate Position Prevention - Fix Documentation

Date: 2025-01-27 Issue: Multiple positions opened on same symbol from different timeframe signals Status: RESOLVED

Problem Description

User received TradingView alerts on both 15-minute AND 30-minute charts for SOLUSDT. The bot:

  1. Correctly extracted timeframe from both alerts (15 and 30)
  2. Correctly filtered out the 30-minute signal (as intended)
  3. BUT allowed the 15-minute signal even though a position already existed
  4. Result: Two LONG positions on SOL-PERP opened 15 minutes apart

Root Cause: Risk check API (/api/trading/check-risk) had TODO comment for checking existing positions but was always returning allowed: true.

Solution Implemented

1. Updated Risk Check API

File: app/api/trading/check-risk/route.ts

Changes:

  • Import getInitializedPositionManager() instead of getPositionManager()
  • Wait for Position Manager initialization (restores trades from database)
  • Check if any active trade exists on the requested symbol
  • Block trade if duplicate found
// Check for existing positions on the same symbol
const positionManager = await getInitializedPositionManager()
const existingTrades = Array.from(positionManager.getActiveTrades().values())
const duplicatePosition = existingTrades.find(trade => trade.symbol === body.symbol)

if (duplicatePosition) {
  return NextResponse.json({
    allowed: false,
    reason: 'Duplicate position',
    details: `Already have ${duplicatePosition.direction} position on ${body.symbol} (entry: $${duplicatePosition.entryPrice})`,
  })
}

2. Fixed Timing Issue

Problem: getPositionManager() creates instance immediately but trades are restored asynchronously in background.

Solution: Use getInitializedPositionManager() which waits for the initialization promise to complete before returning.

3. Updated .dockerignore

Problem: Test files in tests/ and archive/ directories were being included in Docker build, causing TypeScript compilation errors.

Solution: Added to .dockerignore:

tests/
archive/
*.test.ts
*.spec.ts

Testing Results

Test 1: Duplicate Position (BLOCKED )

curl -X POST /api/trading/check-risk \
  -d '{"symbol":"SOL-PERP","direction":"long"}'

Response:
{
  "allowed": false,
  "reason": "Duplicate position",
  "details": "Already have long position on SOL-PERP (entry: $202.835871)"
}

Logs:

🔍 Risk check for: { symbol: 'SOL-PERP', direction: 'long' }
🚫 Risk check BLOCKED: Duplicate position exists {
  symbol: 'SOL-PERP',
  existingDirection: 'long',
  requestedDirection: 'long',
  existingEntry: 202.835871
}

Test 2: Different Symbol (ALLOWED )

curl -X POST /api/trading/check-risk \
  -d '{"symbol":"BTC-PERP","direction":"long"}'

Response:
{
  "allowed": true,
  "details": "All risk checks passed"
}

System Behavior Now

n8n Workflow Flow:

  1. TradingView sends alert → n8n webhook
  2. Extract timeframe from message (\.P\s+(\d+) regex)
  3. 15min Chart Only? IF node: Check timeframe == "15"
  4. If passed → Call /api/trading/check-risk
  5. NEW: Check if position exists on symbol
  6. If no duplicate → Execute trade via /api/trading/execute

Risk Check Matrix:

Scenario Timeframe Filter Risk Check Result
15min signal, no position PASS PASS Trade executes
15min signal, position exists PASS 🚫 BLOCK Trade blocked
30min signal, no position 🚫 BLOCK N/A Trade blocked
30min signal, position exists 🚫 BLOCK N/A Trade blocked

Future Enhancements

The risk check API still has TODO items:

  • Check daily drawdown limit
  • Check trades per hour limit
  • Check cooldown period after loss
  • Check Drift account health before trade
  • Allow opposite direction trades (hedging)?

Files Modified

  1. app/api/trading/check-risk/route.ts - Added duplicate position check
  2. .dockerignore - Excluded test files from Docker build
  3. Moved test-*.ts files from / to archive/

Git Commits

  • 8f90339 - "Add duplicate position prevention to risk check"
  • 17b0806 - "Add 15-minute chart filter to n8n workflow" (previous)

Deployment

docker compose build trading-bot
docker compose up -d --force-recreate trading-bot

Bot automatically restores existing positions from database on startup via Position Manager persistence.


Status: System now prevents duplicate positions on same symbol. Multiple 15-minute signals will be blocked by risk check even if timeframe filter passes.