fix: Remove v9 label from 1-minute data collection

- 1-minute data is pure market sampling, not trading signals
- signalQualityVersion now null for timeframe='1'
- Other timeframes still labeled with v9
- Prevents confusion in analytics/reporting
This commit is contained in:
mindesbunister
2025-12-05 15:21:53 +01:00
parent 1b45d879d0
commit 0bba1a6739
7 changed files with 944 additions and 1 deletions

102
.archive/test-drift-v4.ts Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env tsx
/**
* Test Drift v4 Integration
*
* Verifies connection to Drift Protocol and basic functionality
*/
import { initializeDriftService, getDriftService } from '../lib/drift/client'
import { getMergedConfig } from '../config/trading'
async function main() {
console.log('🧪 Testing Drift v4 Integration\n')
try {
// Test 1: Configuration
console.log('📋 Test 1: Configuration')
const config = getMergedConfig()
console.log('✅ Config loaded:')
console.log(` Position size: $${config.positionSize}`)
console.log(` Leverage: ${config.leverage}x`)
console.log(` Stop loss: ${config.stopLossPercent}%`)
console.log(` TP1: ${config.takeProfit1Percent}%`)
console.log(` TP2: ${config.takeProfit2Percent}%`)
console.log('')
// Test 2: Drift Connection
console.log('📡 Test 2: Drift Connection')
const drift = await initializeDriftService()
console.log('✅ Drift service initialized')
console.log(` Wallet: ${drift.getClient().wallet.publicKey.toString()}`)
console.log('')
// Test 3: Account Balance
console.log('💰 Test 3: USDC Balance')
const balance = await drift.getUSDCBalance()
console.log(`✅ USDC Balance: $${balance.toFixed(2)}`)
console.log('')
// Test 4: Account Health
console.log('💊 Test 4: Account Health')
const health = await drift.getAccountHealth()
console.log('✅ Account health:')
console.log(` Total collateral: $${health.totalCollateral.toFixed(2)}`)
console.log(` Total liability: $${health.totalLiability.toFixed(2)}`)
console.log(` Free collateral: $${health.freeCollateral.toFixed(2)}`)
console.log(` Margin ratio: ${health.marginRatio === Infinity ? '∞' : health.marginRatio.toFixed(2)}`)
console.log('')
// Test 5: Active Positions
console.log('📊 Test 5: Active Positions')
const positions = await drift.getAllPositions()
console.log(`✅ Active positions: ${positions.length}`)
if (positions.length > 0) {
for (const pos of positions) {
console.log(` ${pos.symbol}:`)
console.log(` Side: ${pos.side}`)
console.log(` Size: ${pos.size.toFixed(4)}`)
console.log(` Entry: $${pos.entryPrice.toFixed(4)}`)
console.log(` P&L: $${pos.unrealizedPnL.toFixed(2)}`)
}
} else {
console.log(' No active positions')
}
console.log('')
// Test 6: Oracle Prices
console.log('💹 Test 6: Oracle Prices')
const solPrice = await drift.getOraclePrice(0) // SOL-PERP
console.log(`✅ SOL/USD: $${solPrice.toFixed(4)}`)
console.log('')
// Test 7: Disconnect
console.log('🔌 Test 7: Disconnect')
await drift.disconnect()
console.log('✅ Disconnected from Drift')
console.log('')
console.log('✅ All tests passed!')
console.log('')
console.log('🎯 Ready to trade!')
console.log('')
console.log('Next steps:')
console.log('1. Set up n8n workflow (import n8n-workflow-v4.json)')
console.log('2. Configure TradingView alerts')
console.log('3. Test with a manual alert trigger')
console.log('4. Start trading!')
} catch (error) {
console.error('\n❌ Test failed:', error)
console.error('\nCommon issues:')
console.error('- DRIFT_WALLET_PRIVATE_KEY not set or invalid')
console.error('- Wallet not initialized on Drift')
console.error('- Insufficient SOL for gas fees')
console.error('- RPC connection issues')
console.error('\nCheck v4/SETUP.md for troubleshooting')
process.exit(1)
}
}
main()

206
.archive/test-full-flow.ts Normal file
View File

@@ -0,0 +1,206 @@
/**
* Test Full Trading Flow
*
* End-to-end test: Execute trade → Monitor → Auto-exit
*
* WARNING: This executes a REAL trade on Drift!
* Make sure you have a small position size configured.
*/
import 'dotenv/config'
const API_URL = process.env.API_URL || 'http://localhost:3000'
const API_KEY = process.env.API_KEY || ''
interface ExecuteResponse {
success: boolean
message: string
trade?: {
id: string
symbol: string
direction: string
entryPrice: number
positionSize: number
leverage: number
}
position?: any
}
interface PositionsResponse {
success: boolean
monitoring: {
isActive: boolean
tradeCount: number
symbols: string[]
}
positions: Array<{
id: string
symbol: string
direction: string
entryPrice: number
currentPrice: number
unrealizedPnL: number
profitPercent: number
accountPnL: number
tp1Hit: boolean
slMovedToBreakeven: boolean
}>
}
async function testFullFlow() {
console.log('🧪 Testing Full Trading Flow (END-TO-END)\n')
console.log('⚠️ WARNING: This will execute a REAL trade on Drift!')
console.log(' Make sure position size is small ($10-50)\n')
if (!API_KEY) {
console.error('❌ Error: API_KEY not set in .env')
console.log(' Add: API_KEY=your_secret_key_here')
process.exit(1)
}
// Wait for user confirmation
console.log('Press Ctrl+C to cancel, or wait 5 seconds to continue...')
await new Promise(resolve => setTimeout(resolve, 5000))
console.log()
// Step 1: Execute trade
console.log('📝 Step 1: Executing trade...')
const executePayload = {
symbol: 'SOLUSDT',
direction: 'long',
timeframe: '5',
}
console.log(' Payload:', JSON.stringify(executePayload, null, 2))
const executeResponse = await fetch(`${API_URL}/api/trading/execute`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(executePayload),
})
if (!executeResponse.ok) {
const error = await executeResponse.text()
console.error('❌ Execute failed:', error)
process.exit(1)
}
const executeData: ExecuteResponse = await executeResponse.json()
if (!executeData.success || !executeData.trade) {
console.error('❌ Execute failed:', executeData.message)
process.exit(1)
}
console.log('✅ Trade executed!')
console.log(' ID:', executeData.trade.id)
console.log(' Symbol:', executeData.trade.symbol)
console.log(' Direction:', executeData.trade.direction.toUpperCase())
console.log(' Entry Price: $', executeData.trade.entryPrice.toFixed(4))
console.log(' Position Size: $', executeData.trade.positionSize.toFixed(2))
console.log(' Leverage:', executeData.trade.leverage + 'x')
console.log()
const tradeId = executeData.trade.id
// Step 2: Monitor position
console.log('📝 Step 2: Monitoring position...')
console.log(' Duration: 120 seconds (2 minutes)')
console.log(' Updates: Every 10 seconds')
console.log(' Waiting for automatic exit...\n')
const startTime = Date.now()
let lastStatus: PositionsResponse | null = null
for (let i = 0; i < 12; i++) { // 12 x 10s = 120s
await new Promise(resolve => setTimeout(resolve, 10000))
const elapsed = (Date.now() - startTime) / 1000
console.log(`⏱️ ${elapsed.toFixed(0)}s elapsed...`)
// Fetch positions
const positionsResponse = await fetch(`${API_URL}/api/trading/positions`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
},
})
if (!positionsResponse.ok) {
console.error(' ⚠️ Failed to fetch positions')
continue
}
const positionsData: PositionsResponse = await positionsResponse.json()
lastStatus = positionsData
// Find our trade
const ourTrade = positionsData.positions.find(p => p.id === tradeId)
if (!ourTrade) {
console.log(' ✅ TRADE CLOSED AUTOMATICALLY!')
console.log(' Position no longer in active list')
break
}
// Display status
console.log(` Current Price: $${ourTrade.currentPrice.toFixed(4)}`)
console.log(` Unrealized P&L: $${ourTrade.unrealizedPnL.toFixed(2)} (${ourTrade.accountPnL.toFixed(2)}% account)`)
console.log(` TP1 Hit: ${ourTrade.tp1Hit ? 'YES ✅' : 'No'}`)
console.log(` SL Moved: ${ourTrade.slMovedToBreakeven ? 'YES ✅' : 'No'}`)
console.log()
}
// Step 3: Final check
console.log('📝 Step 3: Final check...')
const finalResponse = await fetch(`${API_URL}/api/trading/positions`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
},
})
if (finalResponse.ok) {
const finalData: PositionsResponse = await finalResponse.json()
const stillActive = finalData.positions.find(p => p.id === tradeId)
if (stillActive) {
console.log('⚠️ Trade still active after 2 minutes')
console.log(' This is normal if price hasn\'t hit targets yet')
console.log(' Position will auto-close when TP/SL is hit')
console.log()
console.log(' Current status:')
console.log(' Price:', stillActive.currentPrice)
console.log(' P&L:', stillActive.unrealizedPnL.toFixed(2))
console.log(' TP1 Hit:', stillActive.tp1Hit)
} else {
console.log('✅ Trade successfully closed automatically!')
console.log(' Check your Drift account for final P&L')
}
}
console.log()
console.log('🎉 End-to-end test complete!')
console.log()
console.log('📊 What happened:')
console.log(' 1. Trade was executed via API')
console.log(' 2. Position manager started monitoring')
console.log(' 3. Pyth price monitor updated every 2s')
console.log(' 4. Exit conditions checked automatically')
console.log(' 5. Trade closed when TP/SL was hit')
console.log()
console.log('💡 Next steps:')
console.log(' 1. Trigger more trades from TradingView')
console.log(' 2. Monitor the logs for auto-exits')
console.log(' 3. Verify P&L on Drift UI')
console.log(' 4. Adjust parameters if needed')
}
// Run test
testFullFlow().catch(error => {
console.error('❌ Test failed:', error)
process.exit(1)
})

View File

@@ -0,0 +1,185 @@
/**
* Test Position Manager
*
* Tests position tracking, monitoring, and automatic exit logic
*/
import { getPositionManager } from '../lib/trading/position-manager'
import type { ActiveTrade } from '../lib/trading/position-manager'
async function testPositionManager() {
console.log('🧪 Testing Position Manager...\n')
const manager = getPositionManager()
// Test 1: Add a simulated long trade
console.log('📝 Test 1: Adding simulated LONG trade...')
const entryPrice = 140.0
const positionSize = 10000
const leverage = 10
const longTrade: ActiveTrade = {
id: `test-long-${Date.now()}`,
positionId: 'test-signature-long',
symbol: 'SOL-PERP',
direction: 'long',
entryPrice,
entryTime: Date.now(),
positionSize,
leverage,
// Exit prices
stopLossPrice: entryPrice * 0.985, // -1.5%
tp1Price: entryPrice * 1.007, // +0.7%
tp2Price: entryPrice * 1.015, // +1.5%
emergencyStopPrice: entryPrice * 0.98, // -2.0%
// Position state
currentSize: positionSize,
tp1Hit: false,
tp2Hit: false,
slMovedToBreakeven: false,
slMovedToProfit: false,
// Trailing stop
trailingStopActive: false,
peakPrice: entryPrice,
// P&L tracking
realizedPnL: 0,
unrealizedPnL: 0,
peakPnL: 0,
// Monitoring
priceCheckCount: 0,
lastPrice: entryPrice,
lastUpdateTime: Date.now(),
}
await manager.addTrade(longTrade)
console.log('✅ Long trade added')
console.log(` Entry: $${entryPrice}`)
console.log(` SL: $${longTrade.stopLossPrice.toFixed(2)} (-1.5%)`)
console.log(` TP1: $${longTrade.tp1Price.toFixed(2)} (+0.7%)`)
console.log(` TP2: $${longTrade.tp2Price.toFixed(2)} (+1.5%)`)
console.log()
// Test 2: Add a simulated short trade
console.log('📝 Test 2: Adding simulated SHORT trade...')
const shortTrade: ActiveTrade = {
id: `test-short-${Date.now()}`,
positionId: 'test-signature-short',
symbol: 'BTC-PERP',
direction: 'short',
entryPrice: 43000,
entryTime: Date.now(),
positionSize: 10000,
leverage: 10,
// Exit prices (reversed for short)
stopLossPrice: 43000 * 1.015, // +1.5% (loss on short)
tp1Price: 43000 * 0.993, // -0.7% (profit on short)
tp2Price: 43000 * 0.985, // -1.5% (profit on short)
emergencyStopPrice: 43000 * 1.02, // +2.0% (emergency)
// Position state
currentSize: 10000,
tp1Hit: false,
tp2Hit: false,
slMovedToBreakeven: false,
slMovedToProfit: false,
// Trailing stop
trailingStopActive: false,
peakPrice: 43000,
// P&L tracking
realizedPnL: 0,
unrealizedPnL: 0,
peakPnL: 0,
// Monitoring
priceCheckCount: 0,
lastPrice: 43000,
lastUpdateTime: Date.now(),
}
await manager.addTrade(shortTrade)
console.log('✅ Short trade added')
console.log(` Entry: $${shortTrade.entryPrice}`)
console.log(` SL: $${shortTrade.stopLossPrice.toFixed(2)} (+1.5%)`)
console.log(` TP1: $${shortTrade.tp1Price.toFixed(2)} (-0.7%)`)
console.log(` TP2: $${shortTrade.tp2Price.toFixed(2)} (-1.5%)`)
console.log()
// Test 3: Check status
console.log('📝 Test 3: Checking manager status...')
const status = manager.getStatus()
console.log('✅ Status:', JSON.stringify(status, null, 2))
console.log()
// Test 4: Monitor for 60 seconds
console.log('📝 Test 4: Monitoring positions for 60 seconds...')
console.log(' (Real prices from Pyth will update every 2s)')
console.log(' Watch for automatic exit conditions!\n')
let updates = 0
const startTime = Date.now()
const interval = setInterval(() => {
const elapsed = (Date.now() - startTime) / 1000
const currentStatus = manager.getStatus()
if (updates % 5 === 0) { // Print every 10 seconds
console.log(`⏱️ ${elapsed.toFixed(0)}s - Active trades: ${currentStatus.activeTradesCount}`)
if (currentStatus.activeTradesCount === 0) {
console.log(' All trades closed!')
clearInterval(interval)
}
}
updates++
}, 2000)
// Run for 60 seconds
await new Promise(resolve => setTimeout(resolve, 60000))
clearInterval(interval)
// Test 5: Check final status
console.log('\n📝 Test 5: Final status check...')
const finalStatus = manager.getStatus()
console.log('Status:', JSON.stringify(finalStatus, null, 2))
console.log()
// Test 6: Close all remaining positions
if (finalStatus.activeTradesCount > 0) {
console.log('📝 Test 6: Closing all remaining positions...')
await manager.closeAll()
console.log('✅ All positions closed')
} else {
console.log('📝 Test 6: No positions to close (already closed automatically!)')
}
console.log()
console.log('🎉 Position manager test complete!')
console.log()
console.log('📊 What to check:')
console.log(' ✅ Both trades were added successfully')
console.log(' ✅ Manager started monitoring (check logs)')
console.log(' ✅ Real prices were fetched from Pyth')
console.log(' ✅ Exit conditions were checked every 2s')
console.log(' ✅ If price hit targets, trades closed automatically')
console.log()
console.log('💡 Next steps:')
console.log(' 1. Review the logs for price updates')
console.log(' 2. Check if any exits were triggered')
console.log(' 3. Run test-full-flow.ts for end-to-end test')
}
// Run test
testPositionManager().catch(error => {
console.error('❌ Test failed:', error)
process.exit(1)
})

View File

@@ -0,0 +1,141 @@
/**
* Test Pyth Price Monitor
*
* Tests real-time price monitoring with WebSocket and polling fallback
*/
import { getPythPriceMonitor } from './lib/pyth/price-monitor'
interface PriceStats {
symbol: string
count: number
prices: number[]
minPrice: number
maxPrice: number
avgPrice: number
lastUpdate: number
}
async function testPriceMonitor() {
console.log('🧪 Testing Pyth Price Monitor...\n')
const monitor = getPythPriceMonitor()
const stats = new Map<string, PriceStats>()
const symbols = ['SOL-PERP', 'BTC-PERP', 'ETH-PERP']
// Initialize stats
symbols.forEach(sym => {
stats.set(sym, {
symbol: sym,
count: 0,
prices: [],
minPrice: Infinity,
maxPrice: -Infinity,
avgPrice: 0,
lastUpdate: 0,
})
})
console.log(`📊 Monitoring: ${symbols.join(', ')}`)
console.log('⏱️ Duration: 30 seconds')
console.log('📡 Source: Pyth Network (WebSocket + Polling)\n')
// Start monitoring
await monitor.start({
symbols,
onPriceUpdate: (update) => {
const stat = stats.get(update.symbol)
if (!stat) return
// Update statistics
stat.count++
stat.prices.push(update.price)
stat.minPrice = Math.min(stat.minPrice, update.price)
stat.maxPrice = Math.max(stat.maxPrice, update.price)
stat.avgPrice = stat.prices.reduce((a, b) => a + b, 0) / stat.prices.length
stat.lastUpdate = Date.now()
// Display update
const changePercent = stat.prices.length > 1
? ((update.price - stat.prices[0]) / stat.prices[0] * 100).toFixed(3)
: '0.000'
console.log(
`💰 ${update.symbol.padEnd(10)} ` +
`$${update.price.toFixed(4).padStart(10)} ` +
`(${changePercent > '0' ? '+' : ''}${changePercent}%) ` +
`[${stat.count} updates]`
)
},
})
console.log('✅ Price monitor started!\n')
// Run for 30 seconds
const startTime = Date.now()
await new Promise(resolve => setTimeout(resolve, 30000))
// Stop monitoring
await monitor.stop()
const duration = (Date.now() - startTime) / 1000
console.log('\n📊 Test Results:\n')
// Display statistics
stats.forEach(stat => {
const priceRange = stat.maxPrice - stat.minPrice
const rangePercent = (priceRange / stat.minPrice * 100).toFixed(3)
const updatesPerSec = (stat.count / duration).toFixed(2)
const timeSinceUpdate = stat.lastUpdate ? (Date.now() - stat.lastUpdate) / 1000 : 0
console.log(`${stat.symbol}:`)
console.log(` Updates: ${stat.count} (${updatesPerSec}/sec)`)
console.log(` Avg Price: $${stat.avgPrice.toFixed(4)}`)
console.log(` Min Price: $${stat.minPrice.toFixed(4)}`)
console.log(` Max Price: $${stat.maxPrice.toFixed(4)}`)
console.log(` Range: $${priceRange.toFixed(4)} (${rangePercent}%)`)
console.log(` Last Update: ${timeSinceUpdate.toFixed(1)}s ago`)
console.log()
})
// Evaluate results
console.log('✅ Evaluation:\n')
const allSymbolsUpdated = Array.from(stats.values()).every(s => s.count > 0)
const avgUpdateRate = Array.from(stats.values())
.reduce((sum, s) => sum + s.count, 0) / stats.size / duration
if (!allSymbolsUpdated) {
console.log('❌ FAIL: Not all symbols received updates')
process.exit(1)
}
if (avgUpdateRate < 0.3) {
console.log(`⚠️ WARNING: Low update rate (${avgUpdateRate.toFixed(2)}/sec)`)
console.log(' Expected: ~0.5-2 updates/sec per symbol')
} else {
console.log(`✅ PASS: Good update rate (${avgUpdateRate.toFixed(2)}/sec)`)
}
const maxGap = Array.from(stats.values())
.map(s => s.lastUpdate ? (Date.now() - s.lastUpdate) / 1000 : Infinity)
.reduce((max, gap) => Math.max(max, gap), 0)
if (maxGap > 5) {
console.log(`⚠️ WARNING: Large gap since last update (${maxGap.toFixed(1)}s)`)
} else {
console.log(`✅ PASS: Recent updates (${maxGap.toFixed(1)}s ago)`)
}
console.log('\n🎉 Price monitor test complete!')
console.log('\n💡 Next steps:')
console.log(' 1. If WebSocket is working: Updates should be ~0.5-2/sec')
console.log(' 2. If polling fallback: Updates should be ~0.5/sec (every 2s)')
console.log(' 3. Run test-position-manager.ts to test exit logic')
}
// Run test
testPriceMonitor().catch(error => {
console.error('❌ Test failed:', error)
process.exit(1)
})

View File

@@ -171,7 +171,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
timeframe: timeframe, timeframe: timeframe,
signalPrice: currentPrice, signalPrice: currentPrice,
signalQualityScore: qualityResult.score, // CRITICAL: Real quality score for analysis signalQualityScore: qualityResult.score, // CRITICAL: Real quality score for analysis
signalQualityVersion: 'v9', // Current indicator version signalQualityVersion: timeframe === '1' ? null : 'v9', // 1-minute data = pure market sampling, no indicator version
minScoreRequired: minQualityScore, minScoreRequired: minQualityScore,
scoreBreakdown: { reasons: qualityResult.reasons }, scoreBreakdown: { reasons: qualityResult.reasons },
indicatorVersion: body.indicatorVersion || 'v5', indicatorVersion: body.indicatorVersion || 'v5',

102
archive/test-drift-v4.ts Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env tsx
/**
* Test Drift v4 Integration
*
* Verifies connection to Drift Protocol and basic functionality
*/
import { initializeDriftService, getDriftService } from '../lib/drift/client'
import { getMergedConfig } from '../config/trading'
async function main() {
console.log('🧪 Testing Drift v4 Integration\n')
try {
// Test 1: Configuration
console.log('📋 Test 1: Configuration')
const config = getMergedConfig()
console.log('✅ Config loaded:')
console.log(` Position size: $${config.positionSize}`)
console.log(` Leverage: ${config.leverage}x`)
console.log(` Stop loss: ${config.stopLossPercent}%`)
console.log(` TP1: ${config.takeProfit1Percent}%`)
console.log(` TP2: ${config.takeProfit2Percent}%`)
console.log('')
// Test 2: Drift Connection
console.log('📡 Test 2: Drift Connection')
const drift = await initializeDriftService()
console.log('✅ Drift service initialized')
console.log(` Wallet: ${drift.getClient().wallet.publicKey.toString()}`)
console.log('')
// Test 3: Account Balance
console.log('💰 Test 3: USDC Balance')
const balance = await drift.getUSDCBalance()
console.log(`✅ USDC Balance: $${balance.toFixed(2)}`)
console.log('')
// Test 4: Account Health
console.log('💊 Test 4: Account Health')
const health = await drift.getAccountHealth()
console.log('✅ Account health:')
console.log(` Total collateral: $${health.totalCollateral.toFixed(2)}`)
console.log(` Total liability: $${health.totalLiability.toFixed(2)}`)
console.log(` Free collateral: $${health.freeCollateral.toFixed(2)}`)
console.log(` Margin ratio: ${health.marginRatio === Infinity ? '∞' : health.marginRatio.toFixed(2)}`)
console.log('')
// Test 5: Active Positions
console.log('📊 Test 5: Active Positions')
const positions = await drift.getAllPositions()
console.log(`✅ Active positions: ${positions.length}`)
if (positions.length > 0) {
for (const pos of positions) {
console.log(` ${pos.symbol}:`)
console.log(` Side: ${pos.side}`)
console.log(` Size: ${pos.size.toFixed(4)}`)
console.log(` Entry: $${pos.entryPrice.toFixed(4)}`)
console.log(` P&L: $${pos.unrealizedPnL.toFixed(2)}`)
}
} else {
console.log(' No active positions')
}
console.log('')
// Test 6: Oracle Prices
console.log('💹 Test 6: Oracle Prices')
const solPrice = await drift.getOraclePrice(0) // SOL-PERP
console.log(`✅ SOL/USD: $${solPrice.toFixed(4)}`)
console.log('')
// Test 7: Disconnect
console.log('🔌 Test 7: Disconnect')
await drift.disconnect()
console.log('✅ Disconnected from Drift')
console.log('')
console.log('✅ All tests passed!')
console.log('')
console.log('🎯 Ready to trade!')
console.log('')
console.log('Next steps:')
console.log('1. Set up n8n workflow (import n8n-workflow-v4.json)')
console.log('2. Configure TradingView alerts')
console.log('3. Test with a manual alert trigger')
console.log('4. Start trading!')
} catch (error) {
console.error('\n❌ Test failed:', error)
console.error('\nCommon issues:')
console.error('- DRIFT_WALLET_PRIVATE_KEY not set or invalid')
console.error('- Wallet not initialized on Drift')
console.error('- Insufficient SOL for gas fees')
console.error('- RPC connection issues')
console.error('\nCheck v4/SETUP.md for troubleshooting')
process.exit(1)
}
}
main()

View File

@@ -0,0 +1,207 @@
/**
* Test Position Manager
*
* Tests position tracking, monitoring, and automatic exit logic
*/
import { getPositionManager } from '../lib/trading/position-manager'
import type { ActiveTrade } from '../lib/trading/position-manager'
async function testPositionManager() {
console.log('🧪 Testing Position Manager...\n')
const manager = getPositionManager()
// Test 1: Add a simulated long trade
console.log('📝 Test 1: Adding simulated LONG trade...')
const entryPrice = 140.0
const positionSize = 10000
const leverage = 10
const longTrade: ActiveTrade = {
id: `test-long-${Date.now()}`,
positionId: 'test-signature-long',
symbol: 'SOL-PERP',
direction: 'long',
entryPrice,
entryTime: Date.now(),
positionSize,
leverage,
// Exit prices
stopLossPrice: entryPrice * 0.985, // -1.5%
tp1Price: entryPrice * 1.007, // +0.7%
tp2Price: entryPrice * 1.015, // +1.5%
emergencyStopPrice: entryPrice * 0.98, // -2.0%
// Position state
currentSize: positionSize,
tp1Hit: false,
tp2Hit: false,
slMovedToBreakeven: false,
slMovedToProfit: false,
// Trailing stop
trailingStopActive: false,
peakPrice: entryPrice,
// P&L tracking
realizedPnL: 0,
unrealizedPnL: 0,
peakPnL: 0,
// MAE/MFE tracking
maxFavorableExcursion: 0,
maxAdverseExcursion: 0,
maxFavorablePrice: entryPrice,
maxAdversePrice: entryPrice,
// Scaling tracking
originalAdx: 20,
timesScaled: 0,
totalScaleAdded: 0,
// Monitoring
priceCheckCount: 0,
lastPrice: entryPrice,
lastUpdateTime: Date.now(),
}
await manager.addTrade(longTrade)
console.log('✅ Long trade added')
console.log(` Entry: $${entryPrice}`)
console.log(` SL: $${longTrade.stopLossPrice.toFixed(2)} (-1.5%)`)
console.log(` TP1: $${longTrade.tp1Price.toFixed(2)} (+0.7%)`)
console.log(` TP2: $${longTrade.tp2Price.toFixed(2)} (+1.5%)`)
console.log()
// Test 2: Add a simulated short trade
console.log('📝 Test 2: Adding simulated SHORT trade...')
const shortTrade: ActiveTrade = {
id: `test-short-${Date.now()}`,
positionId: 'test-signature-short',
symbol: 'BTC-PERP',
direction: 'short',
entryPrice: 43000,
entryTime: Date.now(),
positionSize: 10000,
leverage: 10,
// Exit prices (reversed for short)
stopLossPrice: 43000 * 1.015, // +1.5% (loss on short)
tp1Price: 43000 * 0.993, // -0.7% (profit on short)
tp2Price: 43000 * 0.985, // -1.5% (profit on short)
emergencyStopPrice: 43000 * 1.02, // +2.0% (emergency)
// Position state
currentSize: 10000,
tp1Hit: false,
tp2Hit: false,
slMovedToBreakeven: false,
slMovedToProfit: false,
// Trailing stop
trailingStopActive: false,
peakPrice: 43000,
// P&L tracking
realizedPnL: 0,
unrealizedPnL: 0,
peakPnL: 0,
// MAE/MFE tracking
maxFavorableExcursion: 0,
maxAdverseExcursion: 0,
maxFavorablePrice: 43000,
maxAdversePrice: 43000,
// Scaling tracking
originalAdx: 18,
timesScaled: 0,
totalScaleAdded: 0,
// Monitoring
priceCheckCount: 0,
lastPrice: 43000,
lastUpdateTime: Date.now(),
}
await manager.addTrade(shortTrade)
console.log('✅ Short trade added')
console.log(` Entry: $${shortTrade.entryPrice}`)
console.log(` SL: $${shortTrade.stopLossPrice.toFixed(2)} (+1.5%)`)
console.log(` TP1: $${shortTrade.tp1Price.toFixed(2)} (-0.7%)`)
console.log(` TP2: $${shortTrade.tp2Price.toFixed(2)} (-1.5%)`)
console.log()
// Test 3: Check status
console.log('📝 Test 3: Checking manager status...')
const status = manager.getStatus()
console.log('✅ Status:', JSON.stringify(status, null, 2))
console.log()
// Test 4: Monitor for 60 seconds
console.log('📝 Test 4: Monitoring positions for 60 seconds...')
console.log(' (Real prices from Pyth will update every 2s)')
console.log(' Watch for automatic exit conditions!\n')
let updates = 0
const startTime = Date.now()
const interval = setInterval(() => {
const elapsed = (Date.now() - startTime) / 1000
const currentStatus = manager.getStatus()
if (updates % 5 === 0) { // Print every 10 seconds
console.log(`⏱️ ${elapsed.toFixed(0)}s - Active trades: ${currentStatus.activeTradesCount}`)
if (currentStatus.activeTradesCount === 0) {
console.log(' All trades closed!')
clearInterval(interval)
}
}
updates++
}, 2000)
// Run for 60 seconds
await new Promise(resolve => setTimeout(resolve, 60000))
clearInterval(interval)
// Test 5: Check final status
console.log('\n📝 Test 5: Final status check...')
const finalStatus = manager.getStatus()
console.log('Status:', JSON.stringify(finalStatus, null, 2))
console.log()
// Test 6: Close all remaining positions
if (finalStatus.activeTradesCount > 0) {
console.log('📝 Test 6: Closing all remaining positions...')
await manager.closeAll()
console.log('✅ All positions closed')
} else {
console.log('📝 Test 6: No positions to close (already closed automatically!)')
}
console.log()
console.log('🎉 Position manager test complete!')
console.log()
console.log('📊 What to check:')
console.log(' ✅ Both trades were added successfully')
console.log(' ✅ Manager started monitoring (check logs)')
console.log(' ✅ Real prices were fetched from Pyth')
console.log(' ✅ Exit conditions were checked every 2s')
console.log(' ✅ If price hit targets, trades closed automatically')
console.log()
console.log('💡 Next steps:')
console.log(' 1. Review the logs for price updates')
console.log(' 2. Check if any exits were triggered')
console.log(' 3. Run test-full-flow.ts for end-to-end test')
}
// Run test
testPositionManager().catch(error => {
console.error('❌ Test failed:', error)
process.exit(1)
})