- Add Pyth Network price monitoring (WebSocket + polling fallback) - Add Position Manager with automatic exit logic (TP1/TP2/SL) - Implement dynamic stop-loss adjustment (breakeven + profit lock) - Add real-time P&L tracking and multi-position support - Create comprehensive test suite (3 test scripts) - Add 5 detailed documentation files (2500+ lines) - Update configuration to $50 position size for safe testing - All Phase 2 features complete and tested Core Components: - v4/lib/pyth/price-monitor.ts - Real-time price monitoring - v4/lib/trading/position-manager.ts - Autonomous position management - v4/app/api/trading/positions/route.ts - Query positions endpoint - v4/test-*.ts - Comprehensive testing suite Documentation: - PHASE_2_COMPLETE_REPORT.md - Implementation summary - v4/PHASE_2_SUMMARY.md - Detailed feature overview - v4/TESTING.md - Testing guide - v4/QUICKREF_PHASE2.md - Quick reference - install-phase2.sh - Automated installation script
142 lines
4.3 KiB
TypeScript
142 lines
4.3 KiB
TypeScript
/**
|
|
* 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)
|
|
})
|