learning_ai_invt_trdg/backend/ORDER_STATUS_SYNC.md

264 lines
8.4 KiB
Markdown

# Order Status Synchronization - Solution Documentation
## Problem Statement
Orders were getting stuck in `pending_new` status indefinitely, causing stale data in the dashboard. This happened because:
1. **One-way data flow**: Bot → Database (no sync back)
2. **No status updates on fill**: When orders were filled, the database was never updated
3. **No background reconciliation**: No periodic check to sync actual order statuses from the exchange
## Solution Overview
We implemented a **three-layer solution** to handle stale order statuses:
### 1. Immediate Updates (Real-time Fix)
**Files Modified:**
- `src/services/TradeExecutor.ts`
**Changes:**
- Added `updateOrderStatus()` call when orders are **filled** (previously only called on cancel/reject)
- Added status update for both entry and exit orders
- Ensures database is updated immediately when order status changes
```typescript
// After order is verified as filled
supabaseService.updateOrderStatus?.(order.id, verifiedOrder.status || 'filled', new Date());
```
### 2. Background Sync Service (Periodic Reconciliation)
**Files Created:**
- `src/services/OrderStatusSyncService.ts`
**Files Modified:**
- `src/services/SupabaseService.ts` - Added `getStaleOrders()` method
- `src/index.ts` - Integrated sync service into main bot
**How it works:**
1. Runs every **5 minutes** in the background
2. Queries database for orders in `pending_new` status older than 5 minutes
3. Checks actual status on the exchange via `exchange.getOrder()`
4. Updates database with real status
5. Marks very old orders (>24h) as `unknown` if not found on exchange
**Key Features:**
- Non-blocking (runs in background)
- Handles up to 100 stale orders per sync
- Graceful error handling
- Detailed logging for monitoring
### 3. Visual Indicators (User Awareness)
**Files Modified:**
- `src/tabs/PositionsTab.tsx` (Dashboard)
**Features:**
- **Warning banner** at top when stale orders detected
- **Yellow badge** on individual stale orders (>5 min old)
- **Warning icon** (⚠️) next to stale order status
- Real-time age calculation
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Trading Bot Flow │
└─────────────────────────────────────────────────────────────┘
1. Order Placed
2. TradeExecutor.openPosition()
3. waitForFill() - Poll exchange for status
4. ✅ NEW: updateOrderStatus() - Update DB immediately
5. Track position locally
┌─────────────────────────────────────────────────────────────┐
│ Background Sync Service │
└─────────────────────────────────────────────────────────────┘
Every 5 minutes:
1. Query DB for pending_new orders > 5 min old
2. For each order:
- Check exchange.getOrder()
- Get actual status
- Update DB
3. Mark >24h orders as 'unknown' if not found
┌─────────────────────────────────────────────────────────────┐
│ Dashboard Display │
└─────────────────────────────────────────────────────────────┘
1. Fetch orders from DB
2. Calculate age for each order
3. Detect stale orders (pending_new > 5 min)
4. Show warning banner + visual indicators
```
## Database Schema Assumptions
The solution assumes the `orders` table has:
- `id` or `order_id` - Primary key
- `status` - Order status (pending_new, filled, canceled, etc.)
- `created_at` - Timestamp when order was created
- `updated_at` - Timestamp of last update
- `filled_at` - Timestamp when order was filled (optional)
## Configuration
### Sync Interval
Default: **5 minutes**
To change, modify in `src/index.ts`:
```typescript
const orderSyncService = new OrderStatusSyncService(
dataExchange,
10 * 60 * 1000 // 10 minutes
);
```
### Stale Threshold
Default: **5 minutes**
To change, modify in `src/services/SupabaseService.ts`:
```typescript
async getStaleOrders(staleThresholdMinutes: number = 10) // 10 minutes
```
## Manual Cleanup
For one-time cleanup of very old stale orders:
```bash
# Run the cleanup script
npm run cleanup-stale-orders
```
This will mark all orders >24 hours old in `pending_new` status as `unknown`.
## Monitoring & Logs
Look for these log messages:
### Successful Sync
```
[OrderSync] Found 5 stale orders to check
[OrderSync] Updating order abc123: pending_new → filled
[OrderSync] Sync complete: 5 updated, 0 not found on exchange, 0 failed
```
### No Stale Orders
```
[OrderSync] No stale orders found
```
### Errors
```
[OrderSync] Failed to sync order abc123: Order not found on exchange
[Supabase] Error fetching stale orders: <error message>
```
## Testing
### Test Immediate Updates
1. Place a new order via the bot
2. Check database - should see `pending_new` initially
3. Wait for order to fill (~3-30 seconds)
4. Check database - should see `filled` status
### Test Background Sync
1. Manually set an order to `pending_new` in DB (that's actually filled)
2. Wait 5 minutes
3. Check logs for sync activity
4. Verify order status updated to `filled`
### Test Dashboard Indicators
1. Create a stale order (pending_new > 5 min)
2. Open dashboard
3. Should see:
- Yellow warning banner at top
- Yellow badge on the order
- ⚠️ icon next to status
## Troubleshooting
### Orders still showing as pending_new after sync
**Possible causes:**
1. Exchange doesn't support `getOrder()` API
2. Order ID mismatch between bot and exchange
3. Supabase credentials not configured
**Solution:**
- Check logs for specific error messages
- Verify exchange connector implements `getOrder()`
- Confirm order IDs match between systems
### Sync service not running
**Check:**
```bash
# Look for this in logs on bot startup:
[OrderSync] Background order status sync service started
```
**If missing:**
- Verify `OrderStatusSyncService` is imported in `index.ts`
- Check for startup errors
### Database not updating
**Possible causes:**
1. Supabase credentials missing/invalid
2. Table permissions issue
3. Field name mismatch (`id` vs `order_id`)
**Solution:**
- Check Supabase connection logs
- Verify table has both `id` and `order_id` columns (or update code)
- Test with manual query
## Performance Considerations
- **Sync batch size**: Limited to 100 orders per sync to avoid overload
- **Sync frequency**: 5 minutes balances freshness vs API rate limits
- **Exchange API calls**: One call per stale order (consider rate limits)
## Future Enhancements
1. **WebSocket status updates** - Real-time order status from exchange
2. **Retry logic** - Exponential backoff for failed syncs
3. **Metrics dashboard** - Track sync success rate, stale order trends
4. **Alert on persistent stale orders** - Notify if orders stay stale >1 hour
5. **Bulk status check** - If exchange supports batch order queries
## Related Files
### Core Implementation
- `src/services/TradeExecutor.ts` - Immediate status updates
- `src/services/OrderStatusSyncService.ts` - Background sync
- `src/services/SupabaseService.ts` - Database queries
- `src/index.ts` - Service initialization
### Dashboard
- `src/tabs/PositionsTab.tsx` - Visual indicators
### Utilities
- `src/scripts/cleanupStaleOrders.ts` - Manual cleanup
## Summary
This solution ensures order statuses are **always accurate** through:
1.**Immediate updates** when orders fill
2.**Background reconciliation** every 5 minutes
3.**Visual warnings** for users when stale data detected
4.**Manual cleanup** tools for maintenance
**Result:** No more stale `pending_new` orders! 🎉