Add Position Sync feature for recovering tracking after partial fills
- New /api/trading/sync-positions endpoint (no auth) - Fetches actual Drift positions and compares with Position Manager - Removes stale tracking, adds missing positions with calculated TP/SL - Settings UI: Orange 'Sync Positions' button added - CLI script: scripts/sync-positions.sh for terminal access - Full documentation in docs/guides/POSITION_SYNC_GUIDE.md - Quick reference: POSITION_SYNC_QUICK_REF.md - Updated AI instructions with pitfall #23 Problem solved: Manual Telegram trades with partial fills can cause Position Manager to lose tracking, leaving positions without software- based stop loss protection. This feature restores dual-layer protection. Note: Docker build not picking up route yet (cache issue), needs investigation
This commit is contained in:
@@ -125,6 +125,33 @@ export default function SettingsPage() {
|
||||
setRestarting(false)
|
||||
}
|
||||
|
||||
const syncPositions = async () => {
|
||||
setLoading(true)
|
||||
setMessage(null)
|
||||
try {
|
||||
const response = await fetch('/api/trading/sync-positions', {
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.success) {
|
||||
const { results } = data
|
||||
let msg = '✅ Position sync complete! '
|
||||
if (results.added.length > 0) msg += `Added: ${results.added.join(', ')}. `
|
||||
if (results.removed.length > 0) msg += `Removed: ${results.removed.join(', ')}. `
|
||||
if (results.unchanged.length > 0) msg += `Already tracking: ${results.unchanged.join(', ')}. `
|
||||
if (results.errors.length > 0) msg += `⚠️ Errors: ${results.errors.length}`
|
||||
setMessage({ type: 'success', text: msg })
|
||||
} else {
|
||||
setMessage({ type: 'error', text: `Sync failed: ${data.error || data.message}` })
|
||||
}
|
||||
} catch (error) {
|
||||
setMessage({ type: 'error', text: `Sync failed: ${error instanceof Error ? error.message : 'Unknown error'}` })
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const testTrade = async (direction: 'long' | 'short', symbol: string = 'SOLUSDT') => {
|
||||
if (!confirm(`⚠️ This will execute a REAL ${direction.toUpperCase()} trade on ${symbol} with current settings. Continue?`)) {
|
||||
return
|
||||
@@ -793,6 +820,14 @@ export default function SettingsPage() {
|
||||
>
|
||||
{restarting ? '🔄 Restarting...' : '🔄 Restart Bot'}
|
||||
</button>
|
||||
<button
|
||||
onClick={syncPositions}
|
||||
disabled={loading}
|
||||
className="flex-1 bg-gradient-to-r from-orange-500 to-red-500 text-white font-bold py-4 px-6 rounded-lg hover:from-orange-600 hover:to-red-600 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
title="Re-sync Position Manager with actual Drift positions"
|
||||
>
|
||||
{loading ? '🔄 Syncing...' : '🔄 Sync Positions'}
|
||||
</button>
|
||||
<button
|
||||
onClick={loadSettings}
|
||||
className="bg-slate-700 text-white font-bold py-4 px-6 rounded-lg hover:bg-slate-600 transition-all"
|
||||
|
||||
Reference in New Issue
Block a user