8.4 KiB
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:
- One-way data flow: Bot → Database (no sync back)
- No status updates on fill: When orders were filled, the database was never updated
- 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
// 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- AddedgetStaleOrders()methodsrc/index.ts- Integrated sync service into main bot
How it works:
- Runs every 5 minutes in the background
- Queries database for orders in
pending_newstatus older than 5 minutes - Checks actual status on the exchange via
exchange.getOrder() - Updates database with real status
- Marks very old orders (>24h) as
unknownif 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:
idororder_id- Primary keystatus- Order status (pending_new, filled, canceled, etc.)created_at- Timestamp when order was createdupdated_at- Timestamp of last updatefilled_at- Timestamp when order was filled (optional)
Configuration
Sync Interval
Default: 5 minutes
To change, modify in src/index.ts:
const orderSyncService = new OrderStatusSyncService(
dataExchange,
10 * 60 * 1000 // 10 minutes
);
Stale Threshold
Default: 5 minutes
To change, modify in src/services/SupabaseService.ts:
async getStaleOrders(staleThresholdMinutes: number = 10) // 10 minutes
Manual Cleanup
For one-time cleanup of very old stale orders:
# 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
- Place a new order via the bot
- Check database - should see
pending_newinitially - Wait for order to fill (~3-30 seconds)
- Check database - should see
filledstatus
Test Background Sync
- Manually set an order to
pending_newin DB (that's actually filled) - Wait 5 minutes
- Check logs for sync activity
- Verify order status updated to
filled
Test Dashboard Indicators
- Create a stale order (pending_new > 5 min)
- Open dashboard
- 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:
- Exchange doesn't support
getOrder()API - Order ID mismatch between bot and exchange
- 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:
# Look for this in logs on bot startup:
[OrderSync] Background order status sync service started
If missing:
- Verify
OrderStatusSyncServiceis imported inindex.ts - Check for startup errors
Database not updating
Possible causes:
- Supabase credentials missing/invalid
- Table permissions issue
- Field name mismatch (
idvsorder_id)
Solution:
- Check Supabase connection logs
- Verify table has both
idandorder_idcolumns (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
- WebSocket status updates - Real-time order status from exchange
- Retry logic - Exponential backoff for failed syncs
- Metrics dashboard - Track sync success rate, stale order trends
- Alert on persistent stale orders - Notify if orders stay stale >1 hour
- Bulk status check - If exchange supports batch order queries
Related Files
Core Implementation
src/services/TradeExecutor.ts- Immediate status updatessrc/services/OrderStatusSyncService.ts- Background syncsrc/services/SupabaseService.ts- Database queriessrc/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:
- ✅ Immediate updates when orders fill
- ✅ Background reconciliation every 5 minutes
- ✅ Visual warnings for users when stale data detected
- ✅ Manual cleanup tools for maintenance
Result: No more stale pending_new orders! 🎉