feat: add quality score display and timezone fixes
- Add qualityScore to ExecuteTradeResponse interface and response object - Update analytics page to always show Signal Quality card (N/A if unavailable) - Fix n8n workflow to pass context metrics and qualityScore to execute endpoint - Fix timezone in Telegram notifications (Europe/Berlin) - Fix symbol normalization in /api/trading/close endpoint - Update Drift ETH-PERP minimum order size (0.002 ETH not 0.01) - Add transaction confirmation to closePosition() to prevent phantom closes - Add 30-second grace period for new trades in Position Manager - Fix execution order: database save before Position Manager.addTrade() - Update copilot instructions with transaction confirmation pattern
This commit is contained in:
@@ -313,28 +313,27 @@ export default function AnalyticsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{lastTrade.signalQualityScore !== undefined ? (
|
||||
<div className="bg-gray-700/30 rounded-lg p-4">
|
||||
<div className="text-sm text-gray-400 mb-1">Signal Quality</div>
|
||||
<div className={`text-xl font-bold ${lastTrade.signalQualityScore >= 80 ? 'text-green-400' : lastTrade.signalQualityScore >= 70 ? 'text-yellow-400' : 'text-orange-400'}`}>
|
||||
{lastTrade.signalQualityScore}/100
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{lastTrade.signalQualityScore >= 80 ? 'Excellent' : lastTrade.signalQualityScore >= 70 ? 'Good' : 'Marginal'}
|
||||
</div>
|
||||
</div>
|
||||
) : lastTrade.exitTime && lastTrade.exitPrice ? (
|
||||
<div className="bg-gray-700/30 rounded-lg p-4">
|
||||
<div className="text-sm text-gray-400 mb-1">Exit</div>
|
||||
<div className="text-xl font-bold text-white">${lastTrade.exitPrice.toFixed(4)}</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{new Date(lastTrade.exitTime).toLocaleString()}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="bg-gray-700/30 rounded-lg p-4">
|
||||
<div className="text-sm text-gray-400 mb-1">Signal Quality</div>
|
||||
{lastTrade.signalQualityScore !== undefined ? (
|
||||
<>
|
||||
<div className={`text-xl font-bold ${lastTrade.signalQualityScore >= 80 ? 'text-green-400' : lastTrade.signalQualityScore >= 70 ? 'text-yellow-400' : 'text-orange-400'}`}>
|
||||
{lastTrade.signalQualityScore}/100
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{lastTrade.signalQualityScore >= 80 ? 'Excellent' : lastTrade.signalQualityScore >= 70 ? 'Good' : 'Marginal'}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="text-xl font-bold text-gray-500">N/A</div>
|
||||
<div className="text-xs text-gray-500">No score available</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{lastTrade.exitTime && lastTrade.exitPrice && lastTrade.signalQualityScore !== undefined && (
|
||||
{lastTrade.exitTime && lastTrade.exitPrice && (
|
||||
<div className="grid md:grid-cols-1 gap-4 mb-4">
|
||||
<div className="bg-gray-700/30 rounded-lg p-4">
|
||||
<div className="text-sm text-gray-400 mb-1">Exit</div>
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { closePosition } from '@/lib/drift/orders'
|
||||
import { initializeDriftService } from '@/lib/drift/client'
|
||||
import { normalizeTradingViewSymbol } from '@/config/trading'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const runtime = 'nodejs'
|
||||
|
||||
interface CloseRequest {
|
||||
symbol: string // e.g., 'SOL-PERP'
|
||||
symbol: string // e.g., 'SOL-PERP' or 'SOLUSDT'
|
||||
percentToClose?: number // 0-100, default 100 (close entire position)
|
||||
}
|
||||
|
||||
@@ -46,14 +47,16 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
console.log(`📊 Closing position: ${symbol} (${percentToClose}%)`)
|
||||
// Normalize symbol (SOLUSDT -> SOL-PERP)
|
||||
const driftSymbol = normalizeTradingViewSymbol(symbol)
|
||||
console.log(`📊 Closing position: ${driftSymbol} (${percentToClose}%)`)
|
||||
|
||||
// Initialize Drift service if not already initialized
|
||||
await initializeDriftService()
|
||||
|
||||
// Close position
|
||||
const result = await closePosition({
|
||||
symbol,
|
||||
symbol: driftSymbol,
|
||||
percentToClose,
|
||||
slippageTolerance: 1.0,
|
||||
})
|
||||
@@ -72,7 +75,7 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
transactionSignature: result.transactionSignature,
|
||||
symbol,
|
||||
symbol: driftSymbol,
|
||||
closePrice: result.closePrice,
|
||||
closedSize: result.closedSize,
|
||||
realizedPnL: result.realizedPnL,
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ExecuteTradeRequest {
|
||||
rsi?: number
|
||||
volumeRatio?: number
|
||||
pricePosition?: number
|
||||
qualityScore?: number // Calculated by check-risk endpoint
|
||||
}
|
||||
|
||||
export interface ExecuteTradeResponse {
|
||||
@@ -43,6 +44,7 @@ export interface ExecuteTradeResponse {
|
||||
tp2Percent?: number
|
||||
entrySlippage?: number
|
||||
timestamp?: string
|
||||
qualityScore?: number // Signal quality score (0-100)
|
||||
error?: string
|
||||
message?: string
|
||||
}
|
||||
@@ -281,11 +283,6 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
console.error('❌ Unexpected error placing exit orders:', err)
|
||||
}
|
||||
|
||||
// Add to position manager for monitoring AFTER orders are placed
|
||||
await positionManager.addTrade(activeTrade)
|
||||
|
||||
console.log('✅ Trade added to position manager for monitoring')
|
||||
|
||||
// Create response object
|
||||
const response: ExecuteTradeResponse = {
|
||||
success: true,
|
||||
@@ -303,6 +300,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
tp2Percent: config.takeProfit2Percent,
|
||||
entrySlippage: openResult.slippage,
|
||||
timestamp: new Date().toISOString(),
|
||||
qualityScore: body.qualityScore, // Include quality score in response
|
||||
}
|
||||
|
||||
// Attach exit order signatures to response
|
||||
@@ -341,6 +339,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
rsiAtEntry: body.rsi,
|
||||
volumeAtEntry: body.volumeRatio,
|
||||
pricePositionAtEntry: body.pricePosition,
|
||||
signalQualityScore: body.qualityScore,
|
||||
})
|
||||
|
||||
console.log('💾 Trade saved to database')
|
||||
@@ -349,6 +348,11 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
|
||||
// Don't fail the trade if database save fails
|
||||
}
|
||||
|
||||
// NOW add to position manager for monitoring (after database save)
|
||||
await positionManager.addTrade(activeTrade)
|
||||
|
||||
console.log('✅ Trade added to position manager for monitoring')
|
||||
|
||||
console.log('✅ Trade executed successfully!')
|
||||
|
||||
return NextResponse.json(response)
|
||||
|
||||
@@ -190,12 +190,6 @@ export async function POST(request: NextRequest): Promise<NextResponse<TestTrade
|
||||
lastUpdateTime: Date.now(),
|
||||
}
|
||||
|
||||
// Add to position manager for monitoring
|
||||
const positionManager = await getInitializedPositionManager()
|
||||
await positionManager.addTrade(activeTrade)
|
||||
|
||||
console.log('✅ Trade added to position manager for monitoring')
|
||||
|
||||
// Create response object
|
||||
const response: TestTradeResponse = {
|
||||
success: true,
|
||||
@@ -248,7 +242,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<TestTrade
|
||||
console.error('❌ Unexpected error placing exit orders:', err)
|
||||
}
|
||||
|
||||
// Save trade to database
|
||||
// Save trade to database FIRST (before Position Manager)
|
||||
try {
|
||||
await createTrade({
|
||||
positionId: openResult.transactionSignature!,
|
||||
@@ -281,6 +275,12 @@ export async function POST(request: NextRequest): Promise<NextResponse<TestTrade
|
||||
// Don't fail the trade if database save fails
|
||||
}
|
||||
|
||||
// NOW add to position manager for monitoring (after database save)
|
||||
const positionManager = await getInitializedPositionManager()
|
||||
await positionManager.addTrade(activeTrade)
|
||||
|
||||
console.log('✅ Trade added to position manager for monitoring')
|
||||
|
||||
console.log('✅ Test trade executed successfully!')
|
||||
|
||||
return NextResponse.json(response)
|
||||
|
||||
Reference in New Issue
Block a user