Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:53:07 +08:00
commit 581108d2fe
15 changed files with 1431 additions and 0 deletions

418
commands/track-position.md Normal file
View File

@@ -0,0 +1,418 @@
---
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.