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:
mindesbunister
2025-10-27 10:39:05 +01:00
parent f571d459e4
commit d3c04ea9c9
9 changed files with 1122 additions and 8 deletions

View File

@@ -45,6 +45,19 @@ export interface CreateTradeParams {
isTestTrade?: boolean
}
export interface UpdateTradeStateParams {
positionId: string
currentSize: number
tp1Hit: boolean
slMovedToBreakeven: boolean
slMovedToProfit: boolean
stopLossPrice: number
realizedPnL: number
unrealizedPnL: number
peakPnL: number
lastPrice: number
}
export interface UpdateTradeExitParams {
positionId: string
exitPrice: number
@@ -144,6 +157,66 @@ export async function updateTradeExit(params: UpdateTradeExitParams) {
}
}
/**
* Update active trade state (for Position Manager persistence)
*/
export async function updateTradeState(params: UpdateTradeStateParams) {
const prisma = getPrismaClient()
try {
const trade = await prisma.trade.update({
where: { positionId: params.positionId },
data: {
// Store Position Manager state in configSnapshot
configSnapshot: {
...(await prisma.trade.findUnique({
where: { positionId: params.positionId },
select: { configSnapshot: true }
}))?.configSnapshot as any,
// Add Position Manager state
positionManagerState: {
currentSize: params.currentSize,
tp1Hit: params.tp1Hit,
slMovedToBreakeven: params.slMovedToBreakeven,
slMovedToProfit: params.slMovedToProfit,
stopLossPrice: params.stopLossPrice,
realizedPnL: params.realizedPnL,
unrealizedPnL: params.unrealizedPnL,
peakPnL: params.peakPnL,
lastPrice: params.lastPrice,
lastUpdate: new Date().toISOString(),
}
}
},
})
return trade
} catch (error) {
console.error('❌ Failed to update trade state:', error)
// Don't throw - state updates are non-critical
}
}
/**
* Get all open trades (for Position Manager recovery)
*/
export async function getOpenTrades() {
const prisma = getPrismaClient()
try {
const trades = await prisma.trade.findMany({
where: { status: 'open' },
orderBy: { entryTime: 'asc' },
})
console.log(`📊 Found ${trades.length} open trades to restore`)
return trades
} catch (error) {
console.error('❌ Failed to get open trades:', error)
return []
}
}
/**
* Add price update for a trade (for tracking max gain/drawdown)
*/