Add /close command and auto-flip logic with order cleanup
- Added /close Telegram command for full position closure - Updated /reduce to accept 10-100% (was 10-90%) - Implemented auto-flip logic: automatically closes opposite position when signal reverses - Fixed risk check to allow opposite direction trades (signal flips) - Enhanced Position Manager to cancel orders when removing trades - Added startup initialization for Position Manager (restores trades on restart) - Fixed analytics to show stopped-out trades (manual DB update for orphaned trade) - Updated reduce endpoint to route 100% closes through closePosition for proper cleanup - All position closures now guarantee TP/SL order cancellation on Drift
This commit is contained in:
33
lib/startup/init-position-manager.ts
Normal file
33
lib/startup/init-position-manager.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Position Manager Startup Initialization
|
||||
*
|
||||
* Ensures Position Manager starts monitoring on bot startup
|
||||
* This prevents orphaned trades when the bot restarts
|
||||
*/
|
||||
|
||||
import { getInitializedPositionManager } from '../trading/position-manager'
|
||||
|
||||
let initStarted = false
|
||||
|
||||
export async function initializePositionManagerOnStartup() {
|
||||
if (initStarted) {
|
||||
return
|
||||
}
|
||||
|
||||
initStarted = true
|
||||
|
||||
console.log('🚀 Initializing Position Manager on startup...')
|
||||
|
||||
try {
|
||||
const manager = await getInitializedPositionManager()
|
||||
const status = manager.getStatus()
|
||||
|
||||
console.log(`✅ Position Manager ready - ${status.activeTradesCount} active trades`)
|
||||
|
||||
if (status.activeTradesCount > 0) {
|
||||
console.log(`📊 Monitoring: ${status.symbols.join(', ')}`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to initialize Position Manager on startup:', error)
|
||||
}
|
||||
}
|
||||
@@ -155,10 +155,23 @@ export class PositionManager {
|
||||
/**
|
||||
* Remove a trade from monitoring
|
||||
*/
|
||||
removeTrade(tradeId: string): void {
|
||||
async removeTrade(tradeId: string): Promise<void> {
|
||||
const trade = this.activeTrades.get(tradeId)
|
||||
if (trade) {
|
||||
console.log(`🗑️ Removing trade: ${trade.symbol}`)
|
||||
|
||||
// Cancel all orders for this symbol (cleanup orphaned orders)
|
||||
try {
|
||||
const { cancelAllOrders } = await import('../drift/orders')
|
||||
const cancelResult = await cancelAllOrders(trade.symbol)
|
||||
if (cancelResult.success && cancelResult.cancelledCount! > 0) {
|
||||
console.log(`✅ Cancelled ${cancelResult.cancelledCount} orphaned orders`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to cancel orders during trade removal:', error)
|
||||
// Continue with removal even if cancel fails
|
||||
}
|
||||
|
||||
this.activeTrades.delete(tradeId)
|
||||
|
||||
// Stop monitoring if no more trades
|
||||
@@ -474,7 +487,7 @@ export class PositionManager {
|
||||
}
|
||||
}
|
||||
|
||||
this.removeTrade(trade.id)
|
||||
await this.removeTrade(trade.id)
|
||||
console.log(`✅ Position closed | P&L: $${trade.realizedPnL.toFixed(2)} | Reason: ${reason}`)
|
||||
} else {
|
||||
// Partial close (TP1)
|
||||
|
||||
Reference in New Issue
Block a user