From 344a79a753aee778d7c6c3447a1cbcbcdb525068 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Wed, 29 Oct 2025 15:38:47 +0100 Subject: [PATCH] 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 --- FIXES_RUNNER_AND_CANCELLATION.md | 162 +++++++++++++++++++++++++++++++ config/trading.ts | 2 +- lib/drift/orders.ts | 13 +-- 3 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 FIXES_RUNNER_AND_CANCELLATION.md diff --git a/FIXES_RUNNER_AND_CANCELLATION.md b/FIXES_RUNNER_AND_CANCELLATION.md new file mode 100644 index 0000000..69b5234 --- /dev/null +++ b/FIXES_RUNNER_AND_CANCELLATION.md @@ -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 diff --git a/config/trading.ts b/config/trading.ts index 2ed9e1f..60b29d2 100644 --- a/config/trading.ts +++ b/config/trading.ts @@ -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 diff --git a/lib/drift/orders.ts b/lib/drift/orders.ts index 794eb12..0b9a6ee 100644 --- a/lib/drift/orders.ts +++ b/lib/drift/orders.ts @@ -563,21 +563,22 @@ 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) { console.log('✅ No open orders to cancel') return { success: true, cancelledCount: 0 } } + + console.log(`📋 Found ${ordersToCancel.length} open orders to cancel (including trigger orders)`) - console.log(`📋 Found ${ordersToCancel.length} open orders to cancel`) - - // 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,