Fix runner activation and order cancellation

- Change takeProfit2SizePercent from 100% to 80% to leave 5% runner
- Fix cancelAllOrders() to detect trigger orders using orderId > 0
- Trigger orders (TRIGGER_MARKET, TRIGGER_LIMIT) now properly canceled
- Trailing stop will now activate on 5% runner position
This commit is contained in:
mindesbunister
2025-10-29 15:38:47 +01:00
parent fe4d9bc954
commit 344a79a753
3 changed files with 170 additions and 7 deletions

View File

@@ -0,0 +1,162 @@
# Runner and Order Cancellation Fixes
## Date: 2025-01-29
## Issues Found and Fixed
### 1. **5% Runner (Trailing Stop) Not Working**
**Problem:**
- Config had `takeProfit2SizePercent: 100` which closed 100% of remaining position at TP2
- This left 0% for the runner, so trailing stop never activated
- Logs showed "Executing TP2 for SOL-PERP (80%)" but no "Runner activated" messages
**Root Cause:**
- After TP1 closes 75%, remaining position is 25%
- TP2 at 100% closes all of that 25%, leaving nothing for trailing stop
**Fix Applied:**
```typescript
// config/trading.ts line 98
takeProfit2SizePercent: 80, // Close 80% of remaining 25% at TP2 (leaves 5% as runner)
```
**How It Works Now:**
1. Entry: 100% position ($50)
2. TP1 hits: Closes 75% → Leaves 25% ($12.50)
3. TP2 hits: Closes 80% of remaining 25% (= 20% of original) → Leaves 5% ($2.50 runner)
4. Trailing stop activates when runner reaches +0.5% profit
5. Stop loss trails 0.3% below peak price
**Expected Behavior:**
- You should now see: `🏃 Runner activated: 5.0% remaining with trailing stop`
- Then: `📈 Trailing SL updated: $X.XX → $Y.YY (0.3% below peak $Z.ZZ)`
- Finally: `🔴 TRAILING STOP HIT: SOL-PERP at +X.XX%`
---
### 2. **Stop-Loss Orders Not Being Canceled After Position Closes**
**Problem:**
- When position closed (by software or on-chain orders), 2 SL orders remained open on Drift
- Drift UI showed orphaned TRIGGER_MARKET and TRIGGER_LIMIT orders
- Logs showed "Position fully closed, cancelling remaining orders..." but NO "Cancelled X orders"
**Root Cause:**
```typescript
// OLD CODE - lib/drift/orders.ts line 570
const ordersToCancel = userAccount.orders.filter(
(order: any) =>
order.marketIndex === marketConfig.driftMarketIndex &&
order.status === 0 // ❌ WRONG: Trigger orders have different status values
)
```
The filter `order.status === 0` only caught LIMIT orders in "open" state, but missed:
- **TRIGGER_MARKET** orders (hard stop loss)
- **TRIGGER_LIMIT** orders (soft stop loss)
These trigger orders have different status enum values in Drift SDK.
**Fix Applied:**
```typescript
// NEW CODE - lib/drift/orders.ts line 569-573
const ordersToCancel = userAccount.orders.filter(
(order: any) =>
order.marketIndex === marketConfig.driftMarketIndex &&
order.orderId > 0 // ✅ Active orders have orderId > 0 (catches ALL types)
)
```
**Why This Works:**
- All active orders (LIMIT, TRIGGER_MARKET, TRIGGER_LIMIT) have `orderId > 0`
- Inactive/cancelled orders have `orderId = 0`
- This catches trigger orders regardless of their status enum value
**Expected Behavior:**
- When position closes, you should now see:
```
🗑️ Position fully closed, cancelling remaining orders...
📋 Found 2 open orders to cancel (including trigger orders)
✅ Orders cancelled! Transaction: 5x7Y8z...
✅ Cancelled 2 orders
```
---
## Testing Recommendations
### Test 1: Verify Runner Activation
1. Place a test LONG trade
2. Wait for TP1 to hit (should close 75%)
3. Wait for TP2 to hit (should close 20%, leaving 5%)
4. Look for logs: `🏃 Runner activated: 5.0% remaining with trailing stop`
5. Watch for trailing stop updates as price moves
### Test 2: Verify Order Cancellation
1. Place a test trade with dual stops enabled
2. Manually close the position from Position Manager or let it hit TP2
3. Check Docker logs for cancellation messages
4. Verify on Drift UI that NO orders remain open for SOL-PERP
**Check Logs:**
```bash
docker logs trading-bot-v4 -f | grep -E "(Runner|Trailing|Cancelled|open orders)"
```
**Check Drift Orders:**
Go to https://app.drift.trade/ → Orders tab → Should show 0 open orders after close
---
## Files Modified
1. **config/trading.ts** (line 98)
- Changed `takeProfit2SizePercent: 100` → `80`
2. **lib/drift/orders.ts** (lines 569-573, 579)
- Fixed order filtering to catch trigger orders
- Changed `order.status === 0` → `order.orderId > 0`
- Updated log message to mention trigger orders
---
## Docker Deployment
Changes deployed via:
```bash
docker compose build trading-bot
docker compose up -d --force-recreate trading-bot
```
Container restarted successfully at: 2025-01-29 (timestamp in logs)
---
## Next Steps
1. **Monitor next trade** to confirm runner activates
2. **Check Drift UI** after any close to confirm no orphaned orders
3. **Adjust trailing stop settings** if needed:
- `trailingStopPercent: 0.3` (current: trail 0.3% below peak)
- `trailingStopActivation: 0.5` (current: activate at +0.5% profit)
---
## Related Configuration
Current trailing stop settings in `config/trading.ts`:
```typescript
useTrailingStop: true, // Enable trailing stop
trailingStopPercent: 0.3, // Trail 0.3% below peak
trailingStopActivation: 0.5, // Activate at +0.5% profit
takeProfit1SizePercent: 75, // TP1: Close 75%
takeProfit2SizePercent: 80, // TP2: Close 80% of remaining (= 20% total)
// Runner: 5% remains
```
**Math:**
- Entry: 100% ($50 position)
- After TP1: 25% remains ($12.50)
- After TP2: 25% × (100% - 80%) = 5% remains ($2.50)
- Runner: 5% with trailing stop

View File

@@ -97,7 +97,7 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = {
useMarketOrders: true, // Use market orders for reliable fills
confirmationTimeout: 30000, // 30 seconds max wait
takeProfit1SizePercent: 75, // Close 75% at TP1 to lock in profit
takeProfit2SizePercent: 100, // Close remaining 25% at TP2
takeProfit2SizePercent: 80, // Close 80% of remaining 25% at TP2 (leaves 5% as runner)
}
// Supported markets on Drift Protocol

View File

@@ -563,11 +563,12 @@ export async function cancelAllOrders(
throw new Error('User account not found')
}
// Filter orders for this market
// Filter orders for this market (check for active orders, not just status)
// Note: Trigger orders may have different status values, so we check for non-zero orderId
const ordersToCancel = userAccount.orders.filter(
(order: any) =>
order.marketIndex === marketConfig.driftMarketIndex &&
order.status === 0 // 0 = Open status
order.orderId > 0 // Active orders have orderId > 0
)
if (ordersToCancel.length === 0) {
@@ -575,9 +576,9 @@ export async function cancelAllOrders(
return { success: true, cancelledCount: 0 }
}
console.log(`📋 Found ${ordersToCancel.length} open orders to cancel`)
console.log(`📋 Found ${ordersToCancel.length} open orders to cancel (including trigger orders)`)
// Cancel all orders for this market
// Cancel all orders for this market (cancels all types: LIMIT, TRIGGER_MARKET, TRIGGER_LIMIT)
const txSig = await driftClient.cancelOrders(
undefined, // Cancel by market type
marketConfig.driftMarketIndex,