feat: Position Manager persistence + order cleanup + improved stop loss
- Add Position Manager state persistence to survive restarts - Auto-restore open trades from database on startup - Save state after TP1, SL adjustments, profit locks - Persist to configSnapshot JSON field - Add automatic order cancellation - Cancel all TP/SL orders when position fully closed - New cancelAllOrders() function in drift/orders.ts - Prevents orphaned orders after manual closes - Improve stop loss management - Move SL to +0.35% after TP1 (was +0.15%) - Gives more breathing room for retracements - Still locks in half of TP1 profit - Add database sync when Position Manager closes trades - Auto-update Trade record with exit data - Save P&L, exit reason, hold time - Fix analytics showing stale data - Add trade state management functions - updateTradeState() for Position Manager persistence - getOpenTrades() for startup restoration - getInitializedPositionManager() for async init - Create n8n database analytics workflows - Daily report workflow (automated at midnight) - Pattern analysis (hourly/daily performance) - Stop loss effectiveness analysis - Database analytics query workflow - Complete setup guide (N8N_DATABASE_SETUP.md)
This commit is contained in:
@@ -498,6 +498,15 @@ export async function closePosition(
|
||||
console.log(` Close price: $${oraclePrice.toFixed(4)}`)
|
||||
console.log(` Realized P&L: $${realizedPnL.toFixed(2)}`)
|
||||
|
||||
// If closing 100%, cancel all remaining orders for this market
|
||||
if (params.percentToClose === 100) {
|
||||
console.log('🗑️ Position fully closed, cancelling remaining orders...')
|
||||
const cancelResult = await cancelAllOrders(params.symbol)
|
||||
if (cancelResult.success && cancelResult.cancelledCount! > 0) {
|
||||
console.log(`✅ Cancelled ${cancelResult.cancelledCount} orders`)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
transactionSignature: txSig,
|
||||
@@ -515,6 +524,68 @@ export async function closePosition(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all open orders for a specific market
|
||||
*/
|
||||
export async function cancelAllOrders(
|
||||
symbol: string
|
||||
): Promise<{ success: boolean; cancelledCount?: number; error?: string }> {
|
||||
try {
|
||||
console.log(`🗑️ Cancelling all orders for ${symbol}...`)
|
||||
|
||||
const driftService = getDriftService()
|
||||
const driftClient = driftService.getClient()
|
||||
const marketConfig = getMarketConfig(symbol)
|
||||
|
||||
const isDryRun = process.env.DRY_RUN === 'true'
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN: Simulating order cancellation')
|
||||
return { success: true, cancelledCount: 0 }
|
||||
}
|
||||
|
||||
// Get user account to check for orders
|
||||
const userAccount = driftClient.getUserAccount()
|
||||
if (!userAccount) {
|
||||
throw new Error('User account not found')
|
||||
}
|
||||
|
||||
// Filter orders for this market
|
||||
const ordersToCancel = userAccount.orders.filter(
|
||||
(order: any) =>
|
||||
order.marketIndex === marketConfig.driftMarketIndex &&
|
||||
order.status === 0 // 0 = Open status
|
||||
)
|
||||
|
||||
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`)
|
||||
|
||||
// Cancel all orders for this market
|
||||
const txSig = await driftClient.cancelOrders(
|
||||
undefined, // Cancel by market type
|
||||
marketConfig.driftMarketIndex,
|
||||
undefined // No specific direction filter
|
||||
)
|
||||
|
||||
console.log(`✅ Orders cancelled! Transaction: ${txSig}`)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
cancelledCount: ordersToCancel.length,
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to cancel orders:', error)
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close entire position for a market
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user