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:
162
FIXES_RUNNER_AND_CANCELLATION.md
Normal file
162
FIXES_RUNNER_AND_CANCELLATION.md
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user