--- description: Track crypto positions with entry prices, current values, and PnL calculations shortcut: tp --- # Track Crypto Position Comprehensive position tracking for cryptocurrency investments with real-time price updates and advanced analytics. ## Usage When the user wants to track a crypto position, gather the following information and implement a complete tracking system: ### Required Information - **Symbol**: The cryptocurrency ticker (BTC, ETH, SOL, etc.) - **Entry Price**: Purchase price per unit - **Quantity**: Amount purchased - **Entry Date**: When the position was opened - **Exchange**: Where the trade was executed (optional) - **Target Price**: Profit target (optional) - **Stop Loss**: Risk management level (optional) ## Implementation ### 1. Database Schema Create a structured database to track positions: ```sql CREATE TABLE IF NOT EXISTS crypto_positions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), symbol VARCHAR(10) NOT NULL, entry_price DECIMAL(20,8) NOT NULL, quantity DECIMAL(20,8) NOT NULL, entry_date TIMESTAMP NOT NULL, current_price DECIMAL(20,8), last_updated TIMESTAMP, exchange VARCHAR(50), target_price DECIMAL(20,8), stop_loss DECIMAL(20,8), status VARCHAR(20) DEFAULT 'open', notes TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS position_history ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), position_id UUID REFERENCES crypto_positions(id), price DECIMAL(20,8) NOT NULL, value DECIMAL(20,8) NOT NULL, pnl DECIMAL(20,8) NOT NULL, pnl_percentage DECIMAL(10,4) NOT NULL, recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_positions_symbol ON crypto_positions(symbol); CREATE INDEX idx_positions_status ON crypto_positions(status); CREATE INDEX idx_history_position ON position_history(position_id); ``` ### 2. Position Tracking Class ```javascript class CryptoPositionTracker { constructor() { this.priceFeeds = { coingecko: 'https://api.coingecko.com/api/v3', binance: 'https://api.binance.com/api/v3', coinbase: 'https://api.coinbase.com/v2' }; } async trackPosition(positionData) { const { symbol, entryPrice, quantity, entryDate, exchange = 'Unknown', targetPrice = null, stopLoss = null, notes = '' } = positionData; // Validate input this.validatePositionData(positionData); // Get current price const currentPrice = await this.getCurrentPrice(symbol); // Calculate metrics const metrics = this.calculateMetrics({ entryPrice, quantity, currentPrice }); // Store position const position = await this.storePosition({ symbol: symbol.toUpperCase(), entry_price: entryPrice, quantity, entry_date: entryDate, current_price: currentPrice, exchange, target_price: targetPrice, stop_loss: stopLoss, notes }); // Record initial history await this.recordHistory(position.id, currentPrice, metrics); return { position, metrics, analysis: this.analyzePosition(position, metrics) }; } calculateMetrics({ entryPrice, quantity, currentPrice }) { const entryValue = entryPrice * quantity; const currentValue = currentPrice * quantity; const unrealizedPnL = currentValue - entryValue; const pnlPercentage = ((currentValue - entryValue) / entryValue) * 100; return { entryValue: parseFloat(entryValue.toFixed(2)), currentValue: parseFloat(currentValue.toFixed(2)), unrealizedPnL: parseFloat(unrealizedPnL.toFixed(2)), pnlPercentage: parseFloat(pnlPercentage.toFixed(2)), roi: pnlPercentage, riskRewardRatio: this.calculateRiskReward({ entryPrice, currentPrice, targetPrice: position.target_price, stopLoss: position.stop_loss }) }; } calculateRiskReward({ entryPrice, currentPrice, targetPrice, stopLoss }) { if (!targetPrice || !stopLoss) return null; const potentialReward = targetPrice - entryPrice; const potentialRisk = entryPrice - stopLoss; if (potentialRisk === 0) return null; return parseFloat((potentialReward / potentialRisk).toFixed(2)); } analyzePosition(position, metrics) { const analysis = { status: this.determineStatus(metrics), recommendation: this.getRecommendation(position, metrics), risks: this.identifyRisks(position, metrics), opportunities: this.identifyOpportunities(position, metrics) }; return analysis; } determineStatus(metrics) { if (metrics.pnlPercentage > 20) return 'STRONG_PROFIT'; if (metrics.pnlPercentage > 5) return 'PROFIT'; if (metrics.pnlPercentage > -5) return 'NEUTRAL'; if (metrics.pnlPercentage > -20) return 'LOSS'; return 'SIGNIFICANT_LOSS'; } getRecommendation(position, metrics) { const recommendations = []; // Check stop loss if (position.stop_loss && position.current_price <= position.stop_loss) { recommendations.push({ action: 'EXIT', reason: 'Stop loss hit', urgency: 'HIGH' }); } // Check target if (position.target_price && position.current_price >= position.target_price) { recommendations.push({ action: 'TAKE_PROFIT', reason: 'Target price reached', urgency: 'MEDIUM' }); } // Check significant profit if (metrics.pnlPercentage > 50) { recommendations.push({ action: 'PARTIAL_PROFIT', reason: 'Consider taking partial profits (50%+ gain)', urgency: 'LOW' }); } // Check significant loss if (metrics.pnlPercentage < -30 && !position.stop_loss) { recommendations.push({ action: 'SET_STOP_LOSS', reason: 'Significant loss without stop loss protection', urgency: 'HIGH' }); } return recommendations; } async getCurrentPrice(symbol) { // Implementation would fetch from multiple sources // and return average or most reliable price try { const prices = await Promise.all([ this.fetchCoingeckoPrice(symbol), this.fetchBinancePrice(symbol) ]); return prices.reduce((sum, price) => sum + price, 0) / prices.length; } catch (error) { throw new Error(`Failed to fetch price for ${symbol}: ${error.message}`); } } async updateAllPositions() { const openPositions = await this.getOpenPositions(); const updates = []; for (const position of openPositions) { try { const currentPrice = await this.getCurrentPrice(position.symbol); const metrics = this.calculateMetrics({ entryPrice: position.entry_price, quantity: position.quantity, currentPrice }); await this.updatePosition(position.id, { current_price: currentPrice, last_updated: new Date() }); await this.recordHistory(position.id, currentPrice, metrics); updates.push({ symbol: position.symbol, currentPrice, metrics, status: 'UPDATED' }); } catch (error) { updates.push({ symbol: position.symbol, status: 'ERROR', error: error.message }); } } return updates; } } ``` ### 3. Display Format When displaying position information, format it clearly: ```javascript function displayPosition(position, metrics) { const output = ` ╔════════════════════════════════════════════════════════════════╗ ║ CRYPTO POSITION TRACKER ║ ╠════════════════════════════════════════════════════════════════╣ ║ Symbol: ${position.symbol.padEnd(48)} ║ ║ Entry Price: $${position.entry_price.toFixed(2).padEnd(47)} ║ ║ Current Price: $${position.current_price.toFixed(2).padEnd(47)} ║ ║ Quantity: ${position.quantity.toString().padEnd(48)} ║ ╠════════════════════════════════════════════════════════════════╣ ║ METRICS ║ ╠════════════════════════════════════════════════════════════════╣ ║ Entry Value: $${metrics.entryValue.toFixed(2).padEnd(47)} ║ ║ Current Value: $${metrics.currentValue.toFixed(2).padEnd(47)} ║ ║ Unrealized P&L: ${formatPnL(metrics.unrealizedPnL).padEnd(47)} ║ ║ P&L %: ${formatPnLPercentage(metrics.pnlPercentage).padEnd(48)} ║ ╠════════════════════════════════════════════════════════════════╣ ║ Status: ${determineStatusEmoji(metrics.pnlPercentage)} ${metrics.status.padEnd(43)} ║ ╚════════════════════════════════════════════════════════════════╝ `; return output; } function formatPnL(value) { const formatted = `$${Math.abs(value).toFixed(2)}`; if (value >= 0) { return `+${formatted} `; } else { return `-${formatted} `; } } function formatPnLPercentage(percentage) { const formatted = `${Math.abs(percentage).toFixed(2)}%`; if (percentage >= 0) { return `+${formatted} `; } else { return `-${formatted} `; } } function determineStatusEmoji(percentage) { if (percentage > 20) return ''; if (percentage > 5) return ''; if (percentage > -5) return ''; if (percentage > -20) return '️'; return ''; } ``` ### 4. Alert System Set up automatic alerts for significant events: ```javascript class PositionAlertSystem { constructor() { this.alertThresholds = { profitTarget: 0.20, // 20% profit lossWarning: -0.10, // 10% loss criticalLoss: -0.25, // 25% loss volatilitySpike: 0.15 // 15% daily move }; } async checkAlerts(position, previousPrice, currentPrice) { const alerts = []; const priceChange = ((currentPrice - previousPrice) / previousPrice) * 100; // Check profit targets if (metrics.pnlPercentage >= this.alertThresholds.profitTarget * 100) { alerts.push({ type: 'PROFIT_TARGET', message: ` ${position.symbol} hit profit target: +${metrics.pnlPercentage.toFixed(2)}%`, severity: 'INFO', action: 'Consider taking profits' }); } // Check loss warnings if (metrics.pnlPercentage <= this.alertThresholds.lossWarning * 100 && metrics.pnlPercentage > this.alertThresholds.criticalLoss * 100) { alerts.push({ type: 'LOSS_WARNING', message: `️ ${position.symbol} loss warning: ${metrics.pnlPercentage.toFixed(2)}%`, severity: 'WARNING', action: 'Review position and consider stop loss' }); } // Check critical loss if (metrics.pnlPercentage <= this.alertThresholds.criticalLoss * 100) { alerts.push({ type: 'CRITICAL_LOSS', message: ` ${position.symbol} critical loss: ${metrics.pnlPercentage.toFixed(2)}%`, severity: 'CRITICAL', action: 'Immediate review required' }); } // Check volatility if (Math.abs(priceChange) >= this.alertThresholds.volatilitySpike * 100) { alerts.push({ type: 'VOLATILITY_SPIKE', message: ` ${position.symbol} volatility spike: ${priceChange > 0 ? '+' : ''}${priceChange.toFixed(2)}% in 24h`, severity: 'INFO', action: 'Monitor closely for opportunities or risks' }); } return alerts; } } ``` ## Error Handling Always implement comprehensive error handling: ```javascript try { const position = await tracker.trackPosition({ symbol: 'BTC', entryPrice: 45000, quantity: 0.5, entryDate: new Date('2024-01-01'), targetPrice: 60000, stopLoss: 40000 }); displayPosition(position.position, position.metrics); } catch (error) { if (error.code === 'INVALID_SYMBOL') { console.error(`Invalid cryptocurrency symbol: ${error.symbol}`); } else if (error.code === 'API_ERROR') { console.error(`Failed to fetch price data: ${error.message}`); } else { console.error(`Unexpected error: ${error.message}`); } } ``` This command provides comprehensive position tracking with real-time updates, PnL calculations, risk analysis, and actionable recommendations for crypto investments.