feat: Add production logging gating (Phase 1, Task 1.1)
- Created logger utility with environment-based gating (lib/utils/logger.ts) - Replaced 517 console.log statements with logger.log (71% reduction) - Fixed import paths in 15 files (resolved comment-trapped imports) - Added DEBUG_LOGS=false to .env - Achieves 71% immediate log reduction (517/731 statements) - Expected 90% reduction in production when deployed Impact: Reduced I/O blocking, lower log volume in production Risk: LOW (easy rollback, non-invasive) Phase: Phase 1, Task 1.1 (Quick Wins - Console.log Production Gating) Files changed: - NEW: lib/utils/logger.ts (production-safe logging) - NEW: scripts/replace-console-logs.js (automation tool) - Modified: 15 lib/*.ts files (console.log → logger.log) - Modified: .env (DEBUG_LOGS=false) Next: Task 1.2 (Image Size Optimization)
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { getDriftService, initializeDriftService } from './client'
|
||||
import { logger } from '../utils/logger'
|
||||
import { getMarketConfig } from '../../config/trading'
|
||||
import BN from 'bn.js'
|
||||
import {
|
||||
@@ -81,7 +82,7 @@ export async function openPosition(
|
||||
params: OpenPositionParams
|
||||
): Promise<OpenPositionResult> {
|
||||
try {
|
||||
console.log('📊 Opening position:', params)
|
||||
logger.log('📊 Opening position:', params)
|
||||
|
||||
const driftService = getDriftService()
|
||||
const marketConfig = getMarketConfig(params.symbol)
|
||||
@@ -89,7 +90,7 @@ export async function openPosition(
|
||||
|
||||
// Get current oracle price
|
||||
const oraclePrice = await driftService.getOraclePrice(marketConfig.driftMarketIndex)
|
||||
console.log(`💰 Current ${params.symbol} price: $${oraclePrice.toFixed(4)}`)
|
||||
logger.log(`💰 Current ${params.symbol} price: $${oraclePrice.toFixed(4)}`)
|
||||
|
||||
// Calculate position size in base asset
|
||||
const baseAssetSize = params.sizeUSD / oraclePrice
|
||||
@@ -107,17 +108,17 @@ export async function openPosition(
|
||||
: 1 - (params.slippageTolerance / 100)
|
||||
const worstPrice = oraclePrice * slippageMultiplier
|
||||
|
||||
console.log(`📝 Order details:`)
|
||||
console.log(` Size: ${baseAssetSize.toFixed(4)} ${params.symbol.split('-')[0]}`)
|
||||
console.log(` Notional: $${params.sizeUSD.toFixed(2)}`)
|
||||
console.log(` Oracle price: $${oraclePrice.toFixed(4)}`)
|
||||
console.log(` Worst price (${params.slippageTolerance}% slippage): $${worstPrice.toFixed(4)}`)
|
||||
logger.log(`📝 Order details:`)
|
||||
logger.log(` Size: ${baseAssetSize.toFixed(4)} ${params.symbol.split('-')[0]}`)
|
||||
logger.log(` Notional: $${params.sizeUSD.toFixed(2)}`)
|
||||
logger.log(` Oracle price: $${oraclePrice.toFixed(4)}`)
|
||||
logger.log(` Worst price (${params.slippageTolerance}% slippage): $${worstPrice.toFixed(4)}`)
|
||||
|
||||
// Check DRY_RUN mode
|
||||
const isDryRun = process.env.DRY_RUN === 'true'
|
||||
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN MODE: Simulating order (not executing on blockchain)')
|
||||
logger.log('🧪 DRY RUN MODE: Simulating order (not executing on blockchain)')
|
||||
const mockTxSig = `DRY_RUN_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
||||
|
||||
return {
|
||||
@@ -141,13 +142,13 @@ export async function openPosition(
|
||||
}
|
||||
|
||||
// Place market order using simple placePerpOrder (like v3)
|
||||
console.log('🚀 Placing REAL market order...')
|
||||
logger.log('🚀 Placing REAL market order...')
|
||||
const txSig = await driftClient.placePerpOrder(orderParams)
|
||||
|
||||
console.log(`📝 Transaction submitted: ${txSig}`)
|
||||
logger.log(`📝 Transaction submitted: ${txSig}`)
|
||||
|
||||
// CRITICAL: Confirm transaction actually executed on-chain
|
||||
console.log('⏳ Confirming transaction on-chain...')
|
||||
logger.log('⏳ Confirming transaction on-chain...')
|
||||
const connection = driftService.getTradeConnection() // Use Alchemy for trade operations
|
||||
|
||||
try {
|
||||
@@ -161,7 +162,7 @@ export async function openPosition(
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Transaction confirmed on-chain: ${txSig}`)
|
||||
logger.log(`✅ Transaction confirmed on-chain: ${txSig}`)
|
||||
|
||||
} catch (confirmError) {
|
||||
console.error(`❌ Failed to confirm transaction:`, confirmError)
|
||||
@@ -172,7 +173,7 @@ export async function openPosition(
|
||||
}
|
||||
|
||||
// Wait a moment for position to update
|
||||
console.log('⏳ Waiting for position to update...')
|
||||
logger.log('⏳ Waiting for position to update...')
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
// Get actual fill price from position
|
||||
@@ -188,12 +189,12 @@ export async function openPosition(
|
||||
const expectedSizeUSD = params.sizeUSD
|
||||
const sizeRatio = actualSizeUSD / expectedSizeUSD
|
||||
|
||||
console.log(`💰 Fill details:`)
|
||||
console.log(` Fill price: $${fillPrice.toFixed(4)}`)
|
||||
console.log(` Slippage: ${slippage.toFixed(3)}%`)
|
||||
console.log(` Expected size: $${expectedSizeUSD.toFixed(2)}`)
|
||||
console.log(` Actual size: $${actualSizeUSD.toFixed(2)}`)
|
||||
console.log(` Size ratio: ${(sizeRatio * 100).toFixed(1)}%`)
|
||||
logger.log(`💰 Fill details:`)
|
||||
logger.log(` Fill price: $${fillPrice.toFixed(4)}`)
|
||||
logger.log(` Slippage: ${slippage.toFixed(3)}%`)
|
||||
logger.log(` Expected size: $${expectedSizeUSD.toFixed(2)}`)
|
||||
logger.log(` Actual size: $${actualSizeUSD.toFixed(2)}`)
|
||||
logger.log(` Size ratio: ${(sizeRatio * 100).toFixed(1)}%`)
|
||||
|
||||
// Flag as phantom if actual size is less than 50% of expected
|
||||
const isPhantom = sizeRatio < 0.5
|
||||
@@ -216,8 +217,8 @@ export async function openPosition(
|
||||
}
|
||||
} else {
|
||||
// Position not found yet (may be DRY_RUN mode)
|
||||
console.log(`⚠️ Position not immediately visible (may be DRY_RUN mode)`)
|
||||
console.log(` Using oracle price as estimate: $${oraclePrice.toFixed(4)}`)
|
||||
logger.log(`⚠️ Position not immediately visible (may be DRY_RUN mode)`)
|
||||
logger.log(` Using oracle price as estimate: $${oraclePrice.toFixed(4)}`)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -250,7 +251,7 @@ export async function openPosition(
|
||||
*/
|
||||
export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<PlaceExitOrdersResult> {
|
||||
try {
|
||||
console.log('🛡️ Placing exit orders on-chain:', options.symbol)
|
||||
logger.log('🛡️ Placing exit orders on-chain:', options.symbol)
|
||||
|
||||
const driftService = getDriftService()
|
||||
const driftClient = driftService.getClient()
|
||||
@@ -258,7 +259,7 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
|
||||
const isDryRun = process.env.DRY_RUN === 'true'
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN: Simulating placement of exit orders')
|
||||
logger.log('🧪 DRY RUN: Simulating placement of exit orders')
|
||||
return {
|
||||
success: true,
|
||||
signatures: [
|
||||
@@ -285,11 +286,11 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
const remainingAfterTP1 = options.positionSizeUSD - tp1USD
|
||||
const tp2USD = (remainingAfterTP1 * options.tp2SizePercent) / 100
|
||||
|
||||
console.log(`📊 Exit order sizes:`)
|
||||
console.log(` TP1: ${options.tp1SizePercent}% of $${options.positionSizeUSD.toFixed(2)} = $${tp1USD.toFixed(2)}`)
|
||||
console.log(` Remaining after TP1: $${remainingAfterTP1.toFixed(2)}`)
|
||||
console.log(` TP2: ${options.tp2SizePercent}% of remaining = $${tp2USD.toFixed(2)}`)
|
||||
console.log(` Runner (if any): $${(remainingAfterTP1 - tp2USD).toFixed(2)}`)
|
||||
logger.log(`📊 Exit order sizes:`)
|
||||
logger.log(` TP1: ${options.tp1SizePercent}% of $${options.positionSizeUSD.toFixed(2)} = $${tp1USD.toFixed(2)}`)
|
||||
logger.log(` Remaining after TP1: $${remainingAfterTP1.toFixed(2)}`)
|
||||
logger.log(` TP2: ${options.tp2SizePercent}% of remaining = $${tp2USD.toFixed(2)}`)
|
||||
logger.log(` Runner (if any): $${(remainingAfterTP1 - tp2USD).toFixed(2)}`)
|
||||
|
||||
// For orders that close a long, the order direction should be SHORT (sell)
|
||||
const orderDirection = options.direction === 'long' ? PositionDirection.SHORT : PositionDirection.LONG
|
||||
@@ -307,14 +308,14 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
reduceOnly: true,
|
||||
}
|
||||
|
||||
console.log('🚧 Placing TP1 limit order (reduce-only)...')
|
||||
logger.log('🚧 Placing TP1 limit order (reduce-only)...')
|
||||
const sig = await retryWithBackoff(async () =>
|
||||
await (driftClient as any).placePerpOrder(orderParams)
|
||||
)
|
||||
console.log('✅ TP1 order placed:', sig)
|
||||
logger.log('✅ TP1 order placed:', sig)
|
||||
signatures.push(sig)
|
||||
} else {
|
||||
console.log('⚠️ TP1 size below market min, skipping on-chain TP1')
|
||||
logger.log('⚠️ TP1 size below market min, skipping on-chain TP1')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,14 +332,14 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
reduceOnly: true,
|
||||
}
|
||||
|
||||
console.log('🚧 Placing TP2 limit order (reduce-only)...')
|
||||
logger.log('🚧 Placing TP2 limit order (reduce-only)...')
|
||||
const sig = await retryWithBackoff(async () =>
|
||||
await (driftClient as any).placePerpOrder(orderParams)
|
||||
)
|
||||
console.log('✅ TP2 order placed:', sig)
|
||||
logger.log('✅ TP2 order placed:', sig)
|
||||
signatures.push(sig)
|
||||
} else {
|
||||
console.log('⚠️ TP2 size below market min, skipping on-chain TP2')
|
||||
logger.log('⚠️ TP2 size below market min, skipping on-chain TP2')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +357,7 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
|
||||
if (useDualStops && options.softStopPrice && options.hardStopPrice) {
|
||||
// ============== DUAL STOP SYSTEM ==============
|
||||
console.log('🛡️🛡️ Placing DUAL STOP SYSTEM...')
|
||||
logger.log('🛡️🛡️ Placing DUAL STOP SYSTEM...')
|
||||
|
||||
// 1. Soft Stop (TRIGGER_LIMIT) - Avoids wicks
|
||||
const softStopBuffer = options.softStopBuffer ?? 0.4
|
||||
@@ -377,15 +378,15 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
reduceOnly: true,
|
||||
}
|
||||
|
||||
console.log(` 1️⃣ Soft Stop (TRIGGER_LIMIT):`)
|
||||
console.log(` Trigger: $${options.softStopPrice.toFixed(4)}`)
|
||||
console.log(` Limit: $${(options.softStopPrice * softStopMultiplier).toFixed(4)}`)
|
||||
console.log(` Purpose: Avoid false breakouts/wicks`)
|
||||
logger.log(` 1️⃣ Soft Stop (TRIGGER_LIMIT):`)
|
||||
logger.log(` Trigger: $${options.softStopPrice.toFixed(4)}`)
|
||||
logger.log(` Limit: $${(options.softStopPrice * softStopMultiplier).toFixed(4)}`)
|
||||
logger.log(` Purpose: Avoid false breakouts/wicks`)
|
||||
|
||||
const softStopSig = await retryWithBackoff(async () =>
|
||||
await (driftClient as any).placePerpOrder(softStopParams)
|
||||
)
|
||||
console.log(` ✅ Soft stop placed: ${softStopSig}`)
|
||||
logger.log(` ✅ Soft stop placed: ${softStopSig}`)
|
||||
signatures.push(softStopSig)
|
||||
|
||||
// 2. Hard Stop (TRIGGER_MARKET) - Guarantees exit
|
||||
@@ -401,17 +402,17 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
reduceOnly: true,
|
||||
}
|
||||
|
||||
console.log(` 2️⃣ Hard Stop (TRIGGER_MARKET):`)
|
||||
console.log(` Trigger: $${options.hardStopPrice.toFixed(4)}`)
|
||||
console.log(` Purpose: Guaranteed exit if soft stop doesn't fill`)
|
||||
logger.log(` 2️⃣ Hard Stop (TRIGGER_MARKET):`)
|
||||
logger.log(` Trigger: $${options.hardStopPrice.toFixed(4)}`)
|
||||
logger.log(` Purpose: Guaranteed exit if soft stop doesn't fill`)
|
||||
|
||||
const hardStopSig = await retryWithBackoff(async () =>
|
||||
await (driftClient as any).placePerpOrder(hardStopParams)
|
||||
)
|
||||
console.log(` ✅ Hard stop placed: ${hardStopSig}`)
|
||||
logger.log(` ✅ Hard stop placed: ${hardStopSig}`)
|
||||
signatures.push(hardStopSig)
|
||||
|
||||
console.log(`🎯 Dual stop system active: Soft @ $${options.softStopPrice.toFixed(2)} | Hard @ $${options.hardStopPrice.toFixed(2)}`)
|
||||
logger.log(`🎯 Dual stop system active: Soft @ $${options.softStopPrice.toFixed(2)} | Hard @ $${options.hardStopPrice.toFixed(2)}`)
|
||||
|
||||
} else {
|
||||
// ============== SINGLE STOP SYSTEM ==============
|
||||
@@ -437,15 +438,15 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
reduceOnly: true,
|
||||
}
|
||||
|
||||
console.log(`🛡️ Placing SL as TRIGGER_LIMIT (${stopLimitBuffer}% buffer)...`)
|
||||
console.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`)
|
||||
console.log(` Limit: $${(options.stopLossPrice * limitPriceMultiplier).toFixed(4)}`)
|
||||
console.log(` ⚠️ May not fill during fast moves - use for liquid markets only!`)
|
||||
logger.log(`🛡️ Placing SL as TRIGGER_LIMIT (${stopLimitBuffer}% buffer)...`)
|
||||
logger.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`)
|
||||
logger.log(` Limit: $${(options.stopLossPrice * limitPriceMultiplier).toFixed(4)}`)
|
||||
logger.log(` ⚠️ May not fill during fast moves - use for liquid markets only!`)
|
||||
|
||||
const sig = await retryWithBackoff(async () =>
|
||||
await (driftClient as any).placePerpOrder(orderParams)
|
||||
)
|
||||
console.log('✅ SL trigger-limit order placed:', sig)
|
||||
logger.log('✅ SL trigger-limit order placed:', sig)
|
||||
signatures.push(sig)
|
||||
} else {
|
||||
// TRIGGER_MARKET: Default, guaranteed execution
|
||||
@@ -461,19 +462,19 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise<
|
||||
reduceOnly: true,
|
||||
}
|
||||
|
||||
console.log(`🛡️ Placing SL as TRIGGER_MARKET (guaranteed execution - RECOMMENDED)...`)
|
||||
console.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`)
|
||||
console.log(` ✅ Will execute at market price when triggered (may slip but WILL fill)`)
|
||||
logger.log(`🛡️ Placing SL as TRIGGER_MARKET (guaranteed execution - RECOMMENDED)...`)
|
||||
logger.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`)
|
||||
logger.log(` ✅ Will execute at market price when triggered (may slip but WILL fill)`)
|
||||
|
||||
const sig = await retryWithBackoff(async () =>
|
||||
await (driftClient as any).placePerpOrder(orderParams)
|
||||
)
|
||||
console.log('✅ SL trigger-market order placed:', sig)
|
||||
logger.log('✅ SL trigger-market order placed:', sig)
|
||||
signatures.push(sig)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ SL size below market min, skipping on-chain SL')
|
||||
logger.log('⚠️ SL size below market min, skipping on-chain SL')
|
||||
}
|
||||
|
||||
return { success: true, signatures }
|
||||
@@ -490,7 +491,7 @@ export async function closePosition(
|
||||
params: ClosePositionParams
|
||||
): Promise<ClosePositionResult> {
|
||||
try {
|
||||
console.log('📊 Closing position:', params)
|
||||
logger.log('📊 Closing position:', params)
|
||||
|
||||
const driftService = getDriftService()
|
||||
const marketConfig = getMarketConfig(params.symbol)
|
||||
@@ -509,26 +510,26 @@ export async function closePosition(
|
||||
// CRITICAL FIX: If calculated size is below minimum, close 100% instead
|
||||
// This prevents "runner" positions from being too small to close
|
||||
if (sizeToClose < marketConfig.minOrderSize) {
|
||||
console.log(`⚠️ Calculated close size ${sizeToClose.toFixed(4)} is below minimum ${marketConfig.minOrderSize}`)
|
||||
console.log(` Forcing 100% close to avoid Drift rejection`)
|
||||
logger.log(`⚠️ Calculated close size ${sizeToClose.toFixed(4)} is below minimum ${marketConfig.minOrderSize}`)
|
||||
logger.log(` Forcing 100% close to avoid Drift rejection`)
|
||||
sizeToClose = position.size // Close entire position
|
||||
}
|
||||
|
||||
console.log(`📝 Close order details:`)
|
||||
console.log(` Current position: ${position.size.toFixed(4)} ${position.side}`)
|
||||
console.log(` Closing: ${params.percentToClose}% (${sizeToClose.toFixed(4)})`)
|
||||
console.log(` Entry price: $${position.entryPrice.toFixed(4)}`)
|
||||
console.log(` Unrealized P&L: $${position.unrealizedPnL.toFixed(2)}`)
|
||||
logger.log(`📝 Close order details:`)
|
||||
logger.log(` Current position: ${position.size.toFixed(4)} ${position.side}`)
|
||||
logger.log(` Closing: ${params.percentToClose}% (${sizeToClose.toFixed(4)})`)
|
||||
logger.log(` Entry price: $${position.entryPrice.toFixed(4)}`)
|
||||
logger.log(` Unrealized P&L: $${position.unrealizedPnL.toFixed(2)}`)
|
||||
|
||||
// Get current oracle price
|
||||
const oraclePrice = await driftService.getOraclePrice(marketConfig.driftMarketIndex)
|
||||
console.log(` Current price: $${oraclePrice.toFixed(4)}`)
|
||||
logger.log(` Current price: $${oraclePrice.toFixed(4)}`)
|
||||
|
||||
// Check DRY_RUN mode
|
||||
const isDryRun = process.env.DRY_RUN === 'true'
|
||||
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN MODE: Simulating close order (not executing on blockchain)')
|
||||
logger.log('🧪 DRY RUN MODE: Simulating close order (not executing on blockchain)')
|
||||
|
||||
// Calculate realized P&L with leverage (default 10x in dry run)
|
||||
const profitPercent = ((oraclePrice - position.entryPrice) / position.entryPrice) * 100 * (position.side === 'long' ? 1 : -1)
|
||||
@@ -538,10 +539,10 @@ export async function closePosition(
|
||||
|
||||
const mockTxSig = `DRY_RUN_CLOSE_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
||||
|
||||
console.log(`💰 Simulated close:`)
|
||||
console.log(` Close price: $${oraclePrice.toFixed(4)}`)
|
||||
console.log(` Profit %: ${profitPercent.toFixed(3)}% → Account P&L (10x): ${accountPnLPercent.toFixed(2)}%`)
|
||||
console.log(` Realized P&L: $${realizedPnL.toFixed(2)}`)
|
||||
logger.log(`💰 Simulated close:`)
|
||||
logger.log(` Close price: $${oraclePrice.toFixed(4)}`)
|
||||
logger.log(` Profit %: ${profitPercent.toFixed(3)}% → Account P&L (10x): ${accountPnLPercent.toFixed(2)}%`)
|
||||
logger.log(` Realized P&L: $${realizedPnL.toFixed(2)}`)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -565,16 +566,16 @@ export async function closePosition(
|
||||
|
||||
// Place market close order using simple placePerpOrder (like v3)
|
||||
// CRITICAL: Wrap in retry logic for rate limit protection
|
||||
console.log('🚀 Placing REAL market close order with retry protection...')
|
||||
logger.log('🚀 Placing REAL market close order with retry protection...')
|
||||
const txSig = await retryWithBackoff(async () => {
|
||||
return await driftClient.placePerpOrder(orderParams)
|
||||
}, 3, 8000) // 8s base delay, 3 max retries
|
||||
|
||||
console.log(`✅ Close order placed! Transaction: ${txSig}`)
|
||||
logger.log(`✅ Close order placed! Transaction: ${txSig}`)
|
||||
|
||||
// CRITICAL: Confirm transaction on-chain to prevent phantom closes
|
||||
// BUT: Use timeout to prevent API hangs during network congestion
|
||||
console.log('⏳ Confirming transaction on-chain (30s timeout)...')
|
||||
logger.log('⏳ Confirming transaction on-chain (30s timeout)...')
|
||||
const connection = driftService.getTradeConnection() // Use Alchemy for trade operations
|
||||
|
||||
try {
|
||||
@@ -590,7 +591,7 @@ export async function closePosition(
|
||||
throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`)
|
||||
}
|
||||
|
||||
console.log('✅ Transaction confirmed on-chain')
|
||||
logger.log('✅ Transaction confirmed on-chain')
|
||||
} catch (timeoutError: any) {
|
||||
if (timeoutError.message === 'Transaction confirmation timeout') {
|
||||
console.warn('⚠️ Transaction confirmation timed out after 30s')
|
||||
@@ -615,7 +616,7 @@ export async function closePosition(
|
||||
leverage = 10000 / Number(userAccount.maxMarginRatio)
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('⚠️ Could not determine leverage from account, using 10x default')
|
||||
logger.log('⚠️ Could not determine leverage from account, using 10x default')
|
||||
}
|
||||
|
||||
// Calculate closed notional value (USD)
|
||||
@@ -623,24 +624,24 @@ export async function closePosition(
|
||||
const realizedPnL = (closedNotional * profitPercent) / 100
|
||||
const accountPnLPercent = profitPercent * leverage
|
||||
|
||||
console.log(`💰 Close details:`)
|
||||
console.log(` Close price: $${oraclePrice.toFixed(4)}`)
|
||||
console.log(` Profit %: ${profitPercent.toFixed(3)}% | Account P&L (${leverage}x): ${accountPnLPercent.toFixed(2)}%`)
|
||||
console.log(` Closed notional: $${closedNotional.toFixed(2)}`)
|
||||
console.log(` Realized P&L: $${realizedPnL.toFixed(2)}`)
|
||||
logger.log(`💰 Close details:`)
|
||||
logger.log(` Close price: $${oraclePrice.toFixed(4)}`)
|
||||
logger.log(` Profit %: ${profitPercent.toFixed(3)}% | Account P&L (${leverage}x): ${accountPnLPercent.toFixed(2)}%`)
|
||||
logger.log(` Closed notional: $${closedNotional.toFixed(2)}`)
|
||||
logger.log(` Realized P&L: $${realizedPnL.toFixed(2)}`)
|
||||
|
||||
// If closing 100%, verify position actually closed and cancel remaining orders
|
||||
if (params.percentToClose === 100) {
|
||||
console.log('🗑️ Position fully closed, cancelling remaining orders...')
|
||||
logger.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`)
|
||||
logger.log(`✅ Cancelled ${cancelResult.cancelledCount} orders`)
|
||||
}
|
||||
|
||||
// CRITICAL: Verify position actually closed on Drift (Nov 16, 2025)
|
||||
// Transaction confirmed ≠ Drift state updated immediately
|
||||
// Wait 5 seconds for Drift internal state to propagate
|
||||
console.log('⏳ Waiting 5s for Drift state to propagate...')
|
||||
logger.log('⏳ Waiting 5s for Drift state to propagate...')
|
||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||
|
||||
try {
|
||||
@@ -661,7 +662,7 @@ export async function closePosition(
|
||||
needsVerification: true, // Flag for Position Manager
|
||||
}
|
||||
} else {
|
||||
console.log('✅ Position verified closed on Drift')
|
||||
logger.log('✅ Position verified closed on Drift')
|
||||
}
|
||||
} catch (verifyError) {
|
||||
console.warn('⚠️ Could not verify position closure:', verifyError)
|
||||
@@ -712,7 +713,7 @@ async function retryWithBackoff<T>(
|
||||
// Log successful execution time for rate limit monitoring
|
||||
if (attempt > 0) {
|
||||
const totalTime = Date.now() - startTime
|
||||
console.log(`✅ Retry successful after ${totalTime}ms (${attempt} retries)`)
|
||||
logger.log(`✅ Retry successful after ${totalTime}ms (${attempt} retries)`)
|
||||
|
||||
// Log to database for analytics
|
||||
try {
|
||||
@@ -756,8 +757,8 @@ async function retryWithBackoff<T>(
|
||||
}
|
||||
|
||||
const delay = baseDelay * Math.pow(2, attempt)
|
||||
console.log(`⏳ Rate limited (429), retrying in ${delay / 1000}s... (attempt ${attempt + 1}/${maxRetries})`)
|
||||
console.log(` Error context: ${errorMessage.substring(0, 100)}`)
|
||||
logger.log(`⏳ Rate limited (429), retrying in ${delay / 1000}s... (attempt ${attempt + 1}/${maxRetries})`)
|
||||
logger.log(` Error context: ${errorMessage.substring(0, 100)}`)
|
||||
|
||||
// Log rate limit hit to database
|
||||
try {
|
||||
@@ -783,12 +784,12 @@ export async function cancelAllOrders(
|
||||
symbol: string
|
||||
): Promise<{ success: boolean; cancelledCount?: number; error?: string }> {
|
||||
try {
|
||||
console.log(`🗑️ Cancelling all orders for ${symbol}...`)
|
||||
logger.log(`🗑️ Cancelling all orders for ${symbol}...`)
|
||||
|
||||
// Ensure Drift service is initialized
|
||||
let driftService = getDriftService()
|
||||
if (!driftService) {
|
||||
console.log('⚠️ Drift service not initialized, initializing now...')
|
||||
logger.log('⚠️ Drift service not initialized, initializing now...')
|
||||
driftService = await initializeDriftService()
|
||||
}
|
||||
|
||||
@@ -797,7 +798,7 @@ export async function cancelAllOrders(
|
||||
|
||||
const isDryRun = process.env.DRY_RUN === 'true'
|
||||
if (isDryRun) {
|
||||
console.log('🧪 DRY RUN: Simulating order cancellation')
|
||||
logger.log('🧪 DRY RUN: Simulating order cancellation')
|
||||
return { success: true, cancelledCount: 0 }
|
||||
}
|
||||
|
||||
@@ -827,12 +828,12 @@ export async function cancelAllOrders(
|
||||
)
|
||||
|
||||
if (ordersToCancel.length === 0) {
|
||||
console.log('✅ No open orders to cancel')
|
||||
logger.log('✅ No open orders to cancel')
|
||||
return { success: true, cancelledCount: 0 }
|
||||
}
|
||||
|
||||
console.log(`📋 Found ${ordersToCancel.length} open orders to cancel (including trigger orders)`)
|
||||
console.log(` (checked ${userAccount.orders.length} total order slots)`)
|
||||
logger.log(`📋 Found ${ordersToCancel.length} open orders to cancel (including trigger orders)`)
|
||||
logger.log(` (checked ${userAccount.orders.length} total order slots)`)
|
||||
|
||||
// Cancel all orders with retry logic for rate limits
|
||||
const txSig = await retryWithBackoff(async () => {
|
||||
@@ -843,7 +844,7 @@ export async function cancelAllOrders(
|
||||
)
|
||||
})
|
||||
|
||||
console.log(`✅ Orders cancelled! Transaction: ${txSig}`)
|
||||
logger.log(`✅ Orders cancelled! Transaction: ${txSig}`)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -883,21 +884,21 @@ export async function emergencyCloseAll(): Promise<{
|
||||
result: ClosePositionResult
|
||||
}>
|
||||
}> {
|
||||
console.log('🚨 EMERGENCY: Closing all positions')
|
||||
logger.log('🚨 EMERGENCY: Closing all positions')
|
||||
|
||||
try {
|
||||
const driftService = getDriftService()
|
||||
const positions = await driftService.getAllPositions()
|
||||
|
||||
if (positions.length === 0) {
|
||||
console.log('✅ No positions to close')
|
||||
logger.log('✅ No positions to close')
|
||||
return { success: true, results: [] }
|
||||
}
|
||||
|
||||
const results = []
|
||||
|
||||
for (const position of positions) {
|
||||
console.log(`🔴 Emergency closing ${position.symbol}...`)
|
||||
logger.log(`🔴 Emergency closing ${position.symbol}...`)
|
||||
const result = await closeEntirePosition(position.symbol, 2.0) // Allow 2% slippage
|
||||
results.push({
|
||||
symbol: position.symbol,
|
||||
@@ -905,7 +906,7 @@ export async function emergencyCloseAll(): Promise<{
|
||||
})
|
||||
}
|
||||
|
||||
console.log('✅ Emergency close complete')
|
||||
logger.log('✅ Emergency close complete')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
Reference in New Issue
Block a user