Files
gh-jeremylongshore-claude-c…/commands/track-position.md
2025-11-29 18:53:07 +08:00

14 KiB
Raw Permalink Blame History

description, shortcut
description shortcut
Track crypto positions with entry prices, current values, and PnL calculations 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:

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

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:

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:

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:

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.