docs: Add Bug #92 - Exit order token sizing mismatch to Common Pitfalls

- Added comprehensive documentation for TP/SL size mismatch bug
- Root cause: usdToBase() recalculated tokens at each exit price
- Fix: Pass positionSizeTokens from position fill, use tokensToBase()
- Updated Quick Reference Table (now 74 pitfalls)
- Updated last modified date to January 6, 2026
This commit is contained in:
mindesbunister
2026-01-07 10:02:10 +01:00
parent 361f3ba183
commit bb2432f3bf

View File

@@ -1,7 +1,7 @@
# Common Pitfalls Reference Documentation
> **Last Updated:** December 4, 2025
> **Total Documented:** 72 Pitfalls
> **Last Updated:** January 6, 2026
> **Total Documented:** 74 Pitfalls
> **Primary Source:** `.github/copilot-instructions.md`
## Purpose
@@ -98,6 +98,8 @@ This document is the **comprehensive reference** for all documented pitfalls, bu
| 70 | 🔴 CRITICAL | Smart Entry | Dec 3, 2025 | Smart Validation Queue rejected by execute endpoint |
| 71 | 🔴 CRITICAL | Revenge System | Dec 3, 2025 | Revenge system missing external closure integration |
| 72 | 🔴 CRITICAL | Telegram | Dec 4, 2025 | Telegram webhook conflicts with polling bot |
| 91 | 🔴 CRITICAL | Orders | Jan 1, 2026 | Math.floor truncation in position close leaves fractional remnants |
| 92 | 🔴 CRITICAL | Orders | Jan 6, 2026 | Exit order token sizing mismatch - TP/SL different sizes than position |
| 89 | 🔴 CRITICAL | Drift Protocol | Dec 16, 2025 | Drift fractional position remnants after SL execution |
| 90 | 🔴 CRITICAL | Drift Protocol | Dec 31, 2025 | placePerpOrder vs placeAndTakePerpOrder - MARKET orders not filling |
| 91 | 🔴 CRITICAL | Drift Protocol | Jan 1, 2026 | Math.floor truncation leaves fractional position remnants |
@@ -1830,6 +1832,132 @@ if (percentToClose === 100) {
---
## 92. CRITICAL: Exit Order Token Sizing Mismatch - TP/SL Different Sizes Than Position (Jan 6, 2026)
**Symptom:** Position opened with 142.91 SOL but exit orders show different sizes:
- TP1: 140.87 SOL
- Position: 142.91 SOL
- SL: 147.03 SOL (WRONG!)
**User Report:** "that does not make sense. when i buy 1 sol and set tp and sl then i want to sell that 1 sol at these lvls. i dont care about the dollar value."
**Financial Impact:** Exit orders closing wrong amounts - potential for:
- Under-closing: Leaving unprotected remnants
- Over-closing: Attempting to close more than exists (order rejection)
- Asymmetric risk: SL closing more than TP
**Root Cause:**
* File: `lib/drift/orders.ts` function `placeExitOrders()`
* Code: `usdToBase()` calculated tokens as `USD / price` for each exit order
* Problem: Each exit order uses a DIFFERENT price (TP1 price, TP2 price, SL price)
* Result: Same USD amount / different prices = different token amounts
**Math Example (SOL at entry $140):**
```typescript
// Position: $20,000 notional = 142.91 SOL at $140
// TP1 at $142 (1.43% above entry):
// $12,000 (60%) / $142 = 84.51 SOL ❌ (should be 85.75 SOL = 60% of 142.91)
// SL at $136.19 (2.72% below entry):
// $20,000 (100%) / $136.19 = 146.85 SOL ❌ (should be 142.91 SOL)
```
**THE FIX (Jan 6, 2026):**
```typescript
// BEFORE: USD-based calculation (WRONG)
const usdToBase = (usd: number, price: number) => {
const base = usd / price // Different price = different tokens!
return Math.floor(base * 1e9)
}
const tp1Amount = usdToBase(tp1USD, options.tp1Price) // Wrong tokens
// AFTER: Token-based calculation (CORRECT)
const tokensToBase = (tokens: number) => {
return Math.floor(tokens * 1e9) // Direct conversion
}
// In PlaceExitOrdersOptions interface:
positionSizeTokens?: number // Pass actual token count from position fill
// Usage - calculate percentages from actual tokens:
const tp1Tokens = positionSizeTokens * (options.tp1SizePercent / 100)
const tp1Amount = tokensToBase(tp1Tokens) // Exact token count
```
**Files Changed:**
1. `lib/drift/orders.ts`:
- Added `positionSizeTokens?: number` to PlaceExitOrdersOptions interface
- Added `tokensToBase(tokens)` helper function
- All exit sections (TP1, TP2, SL, soft SL, hard SL) use token-based when available
- Fixed TypeScript error: Changed `if (tp2USD > 0)` to `if (tp2Tokens > 0)`
2. All callers updated to pass `positionSizeTokens`:
- `app/api/trading/execute/route.ts`: `openResult.fillSize`
- `lib/trading/smart-entry-timer.ts`: `openResult.fillSize`
- `lib/trading/sync-helper.ts`: `Math.abs(driftPos.size)`
- `lib/trading/position-manager.ts`: 7 calls updated with position fetching
- `lib/startup/init-position-manager.ts`: `Math.abs(position.size)`
- `lib/health/position-manager-health.ts`: Drift position fetch + token size
**Position Fetching Pattern (for methods without position object):**
```typescript
// For runner methods that need current position size
let positionSizeTokens: number | undefined
try {
const driftService = getDriftService()
const marketConfig = getMarketConfig(trade.symbol)
const position = await driftService.getPosition(marketConfig.driftMarketIndex)
if (position) {
positionSizeTokens = Math.abs(position.size)
}
} catch (error) {
console.error('Failed to fetch position for token sizing:', error)
}
await placeExitOrders({
// ... other options
positionSizeTokens: positionSizeTokens,
})
```
**Backward Compatible:** Falls back to USD calculation if `positionSizeTokens` not provided
**Expected Result After Fix:**
- Position: 142.91 SOL
- TP1 (60%): 85.75 SOL ✅
- TP2 (remaining 40%): 57.16 SOL ✅
- SL: 142.91 SOL ✅
**Verification:**
```bash
# Check logs for new token-based output
docker logs -f trading-bot-v4 | grep "Exit order sizes"
# Expected: "📊 Exit order sizes (TOKEN-BASED - CORRECT)"
```
**Prevention Rules:**
1. NEVER use USD / price to calculate token amounts for exit orders
2. ALWAYS pass actual token count from position fill to exit order placement
3. Exit orders should close PORTIONS of actual position, not recalculated amounts
4. For runner methods, fetch current position size from Drift before placing orders
**Red Flags Indicating This Bug:**
- TradingView chart shows TP/SL sizes different from position size
- Exit orders show values that don't match percentage calculations
- TP1 closes wrong amount, leaving unexpected runner size
- SL attempting to close more than position (order rejection)
**Git Commit:** 361f3ba "critical: Fix exit order token sizing - TP/SL now use exact position size"
**Deployment:** Jan 6, 2026 (container trading-bot-v4)
**Status:** ✅ FIXED AND DEPLOYED
**Lesson Learned:** When placing exit orders, the TOKEN COUNT matters, not the USD VALUE. Exit orders should close a percentage of the ACTUAL POSITION TOKENS, not a recalculated amount based on USD/price. The user said it best: "when i buy 1 sol and set tp and sl then i want to sell that 1 sol at these lvls."
---
## Appendix: Pattern Recognition
### Common Root Causes
@@ -1860,5 +1988,5 @@ if (percentToClose === 100) {
---
**Last Updated:** December 31, 2025
**Last Updated:** January 6, 2026
**Maintainer:** AI Agent team following "NOTHING gets lost" principle