Initial commit
This commit is contained in:
16
.claude-plugin/plugin.json
Normal file
16
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "market-price-tracker",
|
||||||
|
"description": "Real-time market price tracking with multi-exchange feeds and advanced alerts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Intent Solutions IO",
|
||||||
|
"email": "jeremy@intentsolutions.ai",
|
||||||
|
"url": "https://intentsolutions.ai"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# market-price-tracker
|
||||||
|
|
||||||
|
Real-time market price tracking with multi-exchange feeds and advanced alerts
|
||||||
640
commands/analyze-trends.md
Normal file
640
commands/analyze-trends.md
Normal file
@@ -0,0 +1,640 @@
|
|||||||
|
---
|
||||||
|
description: Analyze price trends with technical indicators, pattern recognition, and market structure analysis
|
||||||
|
shortcut: at
|
||||||
|
---
|
||||||
|
|
||||||
|
# Analyze Market Trends
|
||||||
|
|
||||||
|
Advanced trend analysis system using technical indicators, chart patterns, and market structure to identify trading opportunities.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
When the user wants to analyze market trends, implement comprehensive technical analysis with these components:
|
||||||
|
|
||||||
|
### Required Parameters
|
||||||
|
- **Symbol**: Asset to analyze
|
||||||
|
- **Timeframe**: 1m, 5m, 15m, 1h, 4h, 1d, 1w
|
||||||
|
- **Period**: How far back to analyze (e.g., "30 days", "6 months")
|
||||||
|
- **Analysis Type**: technical, fundamental, sentiment, or combined
|
||||||
|
- **Output Format**: report, signals, dashboard
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
### 1. Technical Analysis Engine
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class TrendAnalyzer {
|
||||||
|
constructor() {
|
||||||
|
this.indicators = new TechnicalIndicators();
|
||||||
|
this.patterns = new PatternRecognition();
|
||||||
|
this.marketStructure = new MarketStructureAnalysis();
|
||||||
|
this.signals = new SignalGenerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
async analyzeTrends(params) {
|
||||||
|
const {
|
||||||
|
symbol,
|
||||||
|
timeframe = '1h',
|
||||||
|
period = '30d',
|
||||||
|
analysisType = 'technical',
|
||||||
|
includeVolume = true
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
// Fetch historical data
|
||||||
|
const historicalData = await this.fetchHistoricalData(symbol, timeframe, period);
|
||||||
|
|
||||||
|
// Perform analysis based on type
|
||||||
|
const analysis = {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
symbol,
|
||||||
|
timeframe,
|
||||||
|
period,
|
||||||
|
dataPoints: historicalData.length,
|
||||||
|
trend: await this.identifyTrend(historicalData),
|
||||||
|
momentum: await this.analyzeMomentum(historicalData),
|
||||||
|
volatility: await this.analyzeVolatility(historicalData),
|
||||||
|
patterns: await this.detectPatterns(historicalData),
|
||||||
|
indicators: await this.calculateIndicators(historicalData),
|
||||||
|
structure: await this.analyzeStructure(historicalData),
|
||||||
|
signals: await this.generateSignals(historicalData),
|
||||||
|
forecast: await this.generateForecast(historicalData)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add volume analysis if requested
|
||||||
|
if (includeVolume) {
|
||||||
|
analysis.volume = await this.analyzeVolume(historicalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate trading recommendations
|
||||||
|
analysis.recommendations = this.generateRecommendations(analysis);
|
||||||
|
|
||||||
|
return analysis;
|
||||||
|
}
|
||||||
|
|
||||||
|
async identifyTrend(data) {
|
||||||
|
const prices = data.map(d => d.close);
|
||||||
|
const highs = data.map(d => d.high);
|
||||||
|
const lows = data.map(d => d.low);
|
||||||
|
|
||||||
|
// Calculate trend using multiple methods
|
||||||
|
const methods = {
|
||||||
|
movingAverage: this.trendByMovingAverage(prices),
|
||||||
|
higherHighsLows: this.trendByHigherHighsLows(highs, lows),
|
||||||
|
linearRegression: this.trendByLinearRegression(prices),
|
||||||
|
adx: this.trendByADX(data)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine overall trend
|
||||||
|
const trendVotes = Object.values(methods);
|
||||||
|
const bullishCount = trendVotes.filter(v => v === 'BULLISH').length;
|
||||||
|
const bearishCount = trendVotes.filter(v => v === 'BEARISH').length;
|
||||||
|
|
||||||
|
let overallTrend;
|
||||||
|
if (bullishCount > bearishCount + 1) {
|
||||||
|
overallTrend = 'STRONG_BULLISH';
|
||||||
|
} else if (bullishCount > bearishCount) {
|
||||||
|
overallTrend = 'BULLISH';
|
||||||
|
} else if (bearishCount > bullishCount + 1) {
|
||||||
|
overallTrend = 'STRONG_BEARISH';
|
||||||
|
} else if (bearishCount > bullishCount) {
|
||||||
|
overallTrend = 'BEARISH';
|
||||||
|
} else {
|
||||||
|
overallTrend = 'NEUTRAL';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
overall: overallTrend,
|
||||||
|
strength: this.calculateTrendStrength(data),
|
||||||
|
duration: this.calculateTrendDuration(data),
|
||||||
|
methods,
|
||||||
|
confidence: (Math.max(bullishCount, bearishCount) / trendVotes.length) * 100
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
trendByMovingAverage(prices) {
|
||||||
|
const ma20 = this.calculateSMA(prices, 20);
|
||||||
|
const ma50 = this.calculateSMA(prices, 50);
|
||||||
|
const ma200 = this.calculateSMA(prices, 200);
|
||||||
|
|
||||||
|
const currentPrice = prices[prices.length - 1];
|
||||||
|
|
||||||
|
if (currentPrice > ma20 && ma20 > ma50 && ma50 > ma200) {
|
||||||
|
return 'BULLISH';
|
||||||
|
} else if (currentPrice < ma20 && ma20 < ma50 && ma50 < ma200) {
|
||||||
|
return 'BEARISH';
|
||||||
|
} else {
|
||||||
|
return 'NEUTRAL';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trendByHigherHighsLows(highs, lows) {
|
||||||
|
const recentHighs = highs.slice(-10);
|
||||||
|
const recentLows = lows.slice(-10);
|
||||||
|
|
||||||
|
let higherHighs = 0;
|
||||||
|
let lowerLows = 0;
|
||||||
|
let higherLows = 0;
|
||||||
|
let lowerHighs = 0;
|
||||||
|
|
||||||
|
for (let i = 1; i < recentHighs.length; i++) {
|
||||||
|
if (recentHighs[i] > recentHighs[i-1]) higherHighs++;
|
||||||
|
if (recentHighs[i] < recentHighs[i-1]) lowerHighs++;
|
||||||
|
if (recentLows[i] > recentLows[i-1]) higherLows++;
|
||||||
|
if (recentLows[i] < recentLows[i-1]) lowerLows++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (higherHighs > lowerHighs && higherLows > lowerLows) {
|
||||||
|
return 'BULLISH';
|
||||||
|
} else if (lowerHighs > higherHighs && lowerLows > higherLows) {
|
||||||
|
return 'BEARISH';
|
||||||
|
} else {
|
||||||
|
return 'NEUTRAL';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateTrendStrength(data) {
|
||||||
|
const adx = this.calculateADX(data, 14);
|
||||||
|
const currentADX = adx[adx.length - 1];
|
||||||
|
|
||||||
|
if (currentADX > 50) return 'VERY_STRONG';
|
||||||
|
if (currentADX > 40) return 'STRONG';
|
||||||
|
if (currentADX > 25) return 'MODERATE';
|
||||||
|
if (currentADX > 20) return 'WEAK';
|
||||||
|
return 'VERY_WEAK';
|
||||||
|
}
|
||||||
|
|
||||||
|
async analyzeMomentum(data) {
|
||||||
|
const prices = data.map(d => d.close);
|
||||||
|
|
||||||
|
return {
|
||||||
|
rsi: this.calculateRSI(prices, 14),
|
||||||
|
stochastic: this.calculateStochastic(data, 14, 3, 3),
|
||||||
|
macd: this.calculateMACD(prices),
|
||||||
|
momentum: this.calculateMomentum(prices, 10),
|
||||||
|
roc: this.calculateROC(prices, 12),
|
||||||
|
williamsPR: this.calculateWilliamsPR(data, 14),
|
||||||
|
cci: this.calculateCCI(data, 20),
|
||||||
|
mfi: this.calculateMFI(data, 14),
|
||||||
|
interpretation: this.interpretMomentum(prices)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateRSI(prices, period = 14) {
|
||||||
|
if (prices.length < period + 1) return null;
|
||||||
|
|
||||||
|
const gains = [];
|
||||||
|
const losses = [];
|
||||||
|
|
||||||
|
for (let i = 1; i < prices.length; i++) {
|
||||||
|
const change = prices[i] - prices[i - 1];
|
||||||
|
gains.push(change > 0 ? change : 0);
|
||||||
|
losses.push(change < 0 ? Math.abs(change) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const avgGain = gains.slice(-period).reduce((a, b) => a + b) / period;
|
||||||
|
const avgLoss = losses.slice(-period).reduce((a, b) => a + b) / period;
|
||||||
|
|
||||||
|
if (avgLoss === 0) return 100;
|
||||||
|
|
||||||
|
const rs = avgGain / avgLoss;
|
||||||
|
const rsi = 100 - (100 / (1 + rs));
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: rsi,
|
||||||
|
signal: rsi > 70 ? 'OVERBOUGHT' : rsi < 30 ? 'OVERSOLD' : 'NEUTRAL',
|
||||||
|
divergence: this.checkDivergence(prices, rsi)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateMACD(prices) {
|
||||||
|
const ema12 = this.calculateEMA(prices, 12);
|
||||||
|
const ema26 = this.calculateEMA(prices, 26);
|
||||||
|
const macdLine = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.min(ema12.length, ema26.length); i++) {
|
||||||
|
macdLine.push(ema12[i] - ema26[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const signal = this.calculateEMA(macdLine, 9);
|
||||||
|
const histogram = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.min(macdLine.length, signal.length); i++) {
|
||||||
|
histogram.push(macdLine[i] - signal[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
macd: macdLine[macdLine.length - 1],
|
||||||
|
signal: signal[signal.length - 1],
|
||||||
|
histogram: histogram[histogram.length - 1],
|
||||||
|
crossover: this.detectCrossover(macdLine, signal),
|
||||||
|
trend: histogram[histogram.length - 1] > 0 ? 'BULLISH' : 'BEARISH'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async detectPatterns(data) {
|
||||||
|
const patterns = [];
|
||||||
|
const prices = data.map(d => ({ open: d.open, high: d.high, low: d.low, close: d.close }));
|
||||||
|
|
||||||
|
// Chart Patterns
|
||||||
|
const chartPatterns = {
|
||||||
|
headAndShoulders: this.detectHeadAndShoulders(prices),
|
||||||
|
doubleTop: this.detectDoubleTop(prices),
|
||||||
|
doubleBottom: this.detectDoubleBottom(prices),
|
||||||
|
triangle: this.detectTriangle(prices),
|
||||||
|
wedge: this.detectWedge(prices),
|
||||||
|
flag: this.detectFlag(prices),
|
||||||
|
pennant: this.detectPennant(prices),
|
||||||
|
cup: this.detectCupAndHandle(prices)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Candlestick Patterns
|
||||||
|
const candlePatterns = {
|
||||||
|
hammer: this.detectHammer(prices),
|
||||||
|
doji: this.detectDoji(prices),
|
||||||
|
engulfing: this.detectEngulfing(prices),
|
||||||
|
morningStar: this.detectMorningStar(prices),
|
||||||
|
eveningStar: this.detectEveningStar(prices),
|
||||||
|
shootingStar: this.detectShootingStar(prices),
|
||||||
|
harami: this.detectHarami(prices),
|
||||||
|
threeWhiteSoldiers: this.detectThreeWhiteSoldiers(prices)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Combine and score patterns
|
||||||
|
for (const [name, result] of Object.entries(chartPatterns)) {
|
||||||
|
if (result.detected) {
|
||||||
|
patterns.push({
|
||||||
|
type: 'CHART',
|
||||||
|
name: name.toUpperCase(),
|
||||||
|
confidence: result.confidence,
|
||||||
|
direction: result.direction,
|
||||||
|
target: result.target,
|
||||||
|
stopLoss: result.stopLoss
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [name, result] of Object.entries(candlePatterns)) {
|
||||||
|
if (result.detected) {
|
||||||
|
patterns.push({
|
||||||
|
type: 'CANDLE',
|
||||||
|
name: name.toUpperCase(),
|
||||||
|
confidence: result.confidence,
|
||||||
|
signal: result.signal,
|
||||||
|
position: result.position
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
detectHeadAndShoulders(prices) {
|
||||||
|
const highs = prices.map(p => p.high);
|
||||||
|
const result = { detected: false, confidence: 0, direction: null };
|
||||||
|
|
||||||
|
if (highs.length < 50) return result;
|
||||||
|
|
||||||
|
// Look for pattern in recent data
|
||||||
|
const recent = highs.slice(-50);
|
||||||
|
const peaks = this.findPeaks(recent);
|
||||||
|
|
||||||
|
if (peaks.length >= 3) {
|
||||||
|
const [leftShoulder, head, rightShoulder] = peaks.slice(-3);
|
||||||
|
|
||||||
|
// Check if middle peak is highest (head)
|
||||||
|
if (head.value > leftShoulder.value &&
|
||||||
|
head.value > rightShoulder.value &&
|
||||||
|
Math.abs(leftShoulder.value - rightShoulder.value) / leftShoulder.value < 0.03) {
|
||||||
|
|
||||||
|
result.detected = true;
|
||||||
|
result.confidence = 85;
|
||||||
|
result.direction = 'BEARISH';
|
||||||
|
result.neckline = Math.min(
|
||||||
|
...recent.slice(leftShoulder.index, rightShoulder.index + 1)
|
||||||
|
);
|
||||||
|
result.target = result.neckline - (head.value - result.neckline);
|
||||||
|
result.stopLoss = head.value * 1.01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async analyzeVolume(data) {
|
||||||
|
const volumes = data.map(d => d.volume);
|
||||||
|
const prices = data.map(d => d.close);
|
||||||
|
|
||||||
|
return {
|
||||||
|
average: volumes.reduce((a, b) => a + b) / volumes.length,
|
||||||
|
trend: this.analyzeVolumeTrend(volumes),
|
||||||
|
obv: this.calculateOBV(prices, volumes),
|
||||||
|
adl: this.calculateADL(data),
|
||||||
|
mfi: this.calculateMFI(data, 14),
|
||||||
|
vwap: this.calculateVWAP(data),
|
||||||
|
volumeProfile: this.calculateVolumeProfile(data),
|
||||||
|
accumulation: this.detectAccumulationDistribution(data),
|
||||||
|
spikes: this.detectVolumeSpikes(volumes)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateOBV(prices, volumes) {
|
||||||
|
const obv = [volumes[0]];
|
||||||
|
|
||||||
|
for (let i = 1; i < prices.length; i++) {
|
||||||
|
if (prices[i] > prices[i - 1]) {
|
||||||
|
obv.push(obv[i - 1] + volumes[i]);
|
||||||
|
} else if (prices[i] < prices[i - 1]) {
|
||||||
|
obv.push(obv[i - 1] - volumes[i]);
|
||||||
|
} else {
|
||||||
|
obv.push(obv[i - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: obv,
|
||||||
|
current: obv[obv.length - 1],
|
||||||
|
trend: this.calculateTrend(obv.slice(-20)),
|
||||||
|
divergence: this.checkVolumePriceDivergence(prices, obv)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateSignals(data) {
|
||||||
|
const signals = [];
|
||||||
|
const analysis = {
|
||||||
|
trend: await this.identifyTrend(data),
|
||||||
|
momentum: await this.analyzeMomentum(data),
|
||||||
|
patterns: await this.detectPatterns(data)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trend-based signals
|
||||||
|
if (analysis.trend.overall === 'STRONG_BULLISH') {
|
||||||
|
signals.push({
|
||||||
|
type: 'BUY',
|
||||||
|
strength: 'STRONG',
|
||||||
|
reason: 'Strong bullish trend confirmed',
|
||||||
|
confidence: analysis.trend.confidence
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Momentum signals
|
||||||
|
if (analysis.momentum.rsi.value < 30) {
|
||||||
|
signals.push({
|
||||||
|
type: 'BUY',
|
||||||
|
strength: 'MEDIUM',
|
||||||
|
reason: 'RSI oversold condition',
|
||||||
|
confidence: 70
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern signals
|
||||||
|
for (const pattern of analysis.patterns) {
|
||||||
|
if (pattern.type === 'CHART' && pattern.confidence > 80) {
|
||||||
|
signals.push({
|
||||||
|
type: pattern.direction === 'BULLISH' ? 'BUY' : 'SELL',
|
||||||
|
strength: 'STRONG',
|
||||||
|
reason: `${pattern.name} pattern detected`,
|
||||||
|
confidence: pattern.confidence,
|
||||||
|
target: pattern.target,
|
||||||
|
stopLoss: pattern.stopLoss
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MACD crossover signals
|
||||||
|
if (analysis.momentum.macd.crossover === 'BULLISH') {
|
||||||
|
signals.push({
|
||||||
|
type: 'BUY',
|
||||||
|
strength: 'MEDIUM',
|
||||||
|
reason: 'MACD bullish crossover',
|
||||||
|
confidence: 65
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.prioritizeSignals(signals);
|
||||||
|
}
|
||||||
|
|
||||||
|
prioritizeSignals(signals) {
|
||||||
|
// Sort by confidence and strength
|
||||||
|
return signals.sort((a, b) => {
|
||||||
|
const strengthScore = { STRONG: 3, MEDIUM: 2, WEAK: 1 };
|
||||||
|
const scoreA = a.confidence * strengthScore[a.strength];
|
||||||
|
const scoreB = b.confidence * strengthScore[b.strength];
|
||||||
|
return scoreB - scoreA;
|
||||||
|
}).slice(0, 5); // Top 5 signals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Market Structure Analysis
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class MarketStructureAnalysis {
|
||||||
|
analyzeStructure(data) {
|
||||||
|
return {
|
||||||
|
marketPhase: this.identifyMarketPhase(data),
|
||||||
|
keyLevels: this.identifyKeyLevels(data),
|
||||||
|
liquidityZones: this.findLiquidityZones(data),
|
||||||
|
orderFlow: this.analyzeOrderFlow(data),
|
||||||
|
marketProfile: this.createMarketProfile(data),
|
||||||
|
supplyDemand: this.identifySupplyDemandZones(data)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
identifyMarketPhase(data) {
|
||||||
|
const volatility = this.calculateVolatility(data);
|
||||||
|
const trend = this.calculateTrendStrength(data);
|
||||||
|
const volume = this.analyzeVolumeCharacteristics(data);
|
||||||
|
|
||||||
|
if (volatility < 0.01 && trend < 25) {
|
||||||
|
return {
|
||||||
|
phase: 'ACCUMULATION',
|
||||||
|
characteristics: 'Low volatility, sideways movement, smart money accumulating',
|
||||||
|
tradingStrategy: 'Buy at support, sell at resistance'
|
||||||
|
};
|
||||||
|
} else if (trend > 40 && volume.trend === 'INCREASING') {
|
||||||
|
return {
|
||||||
|
phase: 'MARK_UP',
|
||||||
|
characteristics: 'Strong trend, increasing volume, institutional buying',
|
||||||
|
tradingStrategy: 'Trend following, buy dips'
|
||||||
|
};
|
||||||
|
} else if (volatility > 0.03 && trend < 25) {
|
||||||
|
return {
|
||||||
|
phase: 'DISTRIBUTION',
|
||||||
|
characteristics: 'High volatility, topping pattern, smart money distributing',
|
||||||
|
tradingStrategy: 'Take profits, short at resistance'
|
||||||
|
};
|
||||||
|
} else if (trend > 40 && volume.trend === 'DECREASING') {
|
||||||
|
return {
|
||||||
|
phase: 'MARK_DOWN',
|
||||||
|
characteristics: 'Downtrend, panic selling, capitulation',
|
||||||
|
tradingStrategy: 'Stay out or short rallies'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
phase: 'TRANSITION',
|
||||||
|
characteristics: 'Changing market dynamics',
|
||||||
|
tradingStrategy: 'Wait for confirmation'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
identifyKeyLevels(data) {
|
||||||
|
const levels = [];
|
||||||
|
const highs = data.map(d => d.high);
|
||||||
|
const lows = data.map(d => d.low);
|
||||||
|
const closes = data.map(d => d.close);
|
||||||
|
|
||||||
|
// Psychological levels (round numbers)
|
||||||
|
const currentPrice = closes[closes.length - 1];
|
||||||
|
const roundLevels = this.findRoundNumbers(currentPrice);
|
||||||
|
|
||||||
|
// Historical support/resistance
|
||||||
|
const historicalLevels = this.findHistoricalLevels(highs, lows, closes);
|
||||||
|
|
||||||
|
// Volume-based levels
|
||||||
|
const volumeLevels = this.findVolumeLevels(data);
|
||||||
|
|
||||||
|
// Fibonacci levels
|
||||||
|
const fibLevels = this.calculateFibonacciLevels(
|
||||||
|
Math.min(...lows),
|
||||||
|
Math.max(...highs)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
psychological: roundLevels,
|
||||||
|
historical: historicalLevels,
|
||||||
|
volume: volumeLevels,
|
||||||
|
fibonacci: fibLevels,
|
||||||
|
combined: this.combineAndRankLevels([
|
||||||
|
...roundLevels,
|
||||||
|
...historicalLevels,
|
||||||
|
...volumeLevels,
|
||||||
|
...fibLevels
|
||||||
|
])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
findLiquidityZones(data) {
|
||||||
|
const zones = [];
|
||||||
|
const volumes = data.map(d => d.volume);
|
||||||
|
const avgVolume = volumes.reduce((a, b) => a + b) / volumes.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length - 10; i++) {
|
||||||
|
const window = data.slice(i, i + 10);
|
||||||
|
const windowVolume = window.reduce((sum, d) => sum + d.volume, 0);
|
||||||
|
|
||||||
|
if (windowVolume > avgVolume * 10 * 1.5) {
|
||||||
|
const highPrice = Math.max(...window.map(d => d.high));
|
||||||
|
const lowPrice = Math.min(...window.map(d => d.low));
|
||||||
|
|
||||||
|
zones.push({
|
||||||
|
type: 'HIGH_LIQUIDITY',
|
||||||
|
upperBound: highPrice,
|
||||||
|
lowerBound: lowPrice,
|
||||||
|
volume: windowVolume,
|
||||||
|
strength: windowVolume / (avgVolume * 10)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Display and Reporting
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class TrendReport {
|
||||||
|
generateReport(analysis) {
|
||||||
|
return `
|
||||||
|
╔════════════════════════════════════════════════════════════════╗
|
||||||
|
║ TREND ANALYSIS REPORT ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ Symbol: ${analysis.symbol.padEnd(48)} ║
|
||||||
|
║ Timeframe: ${analysis.timeframe.padEnd(48)} ║
|
||||||
|
║ Period: ${analysis.period.padEnd(48)} ║
|
||||||
|
║ Data Points: ${analysis.dataPoints.toString().padEnd(48)} ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ TREND ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ Direction: ${this.formatTrend(analysis.trend.overall).padEnd(48)} ║
|
||||||
|
║ Strength: ${analysis.trend.strength.padEnd(48)} ║
|
||||||
|
║ Duration: ${analysis.trend.duration.padEnd(48)} ║
|
||||||
|
║ Confidence: ${this.formatPercentage(analysis.trend.confidence).padEnd(48)} ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ MOMENTUM ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ RSI (14): ${this.formatRSI(analysis.momentum.rsi).padEnd(48)} ║
|
||||||
|
║ MACD: ${this.formatMACD(analysis.momentum.macd).padEnd(48)} ║
|
||||||
|
║ Stochastic: ${this.formatStochastic(analysis.momentum.stochastic).padEnd(48)} ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ PATTERNS ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
${this.formatPatterns(analysis.patterns)}
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ TOP SIGNALS ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
${this.formatSignals(analysis.signals)}
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ RECOMMENDATIONS ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
${this.formatRecommendations(analysis.recommendations)}
|
||||||
|
╚════════════════════════════════════════════════════════════════╝
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatTrend(trend) {
|
||||||
|
const icons = {
|
||||||
|
STRONG_BULLISH: ' Strong Bullish',
|
||||||
|
BULLISH: ' Bullish',
|
||||||
|
NEUTRAL: ' Neutral',
|
||||||
|
BEARISH: ' Bearish',
|
||||||
|
STRONG_BEARISH: ' Strong Bearish'
|
||||||
|
};
|
||||||
|
return icons[trend] || trend;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatPatterns(patterns) {
|
||||||
|
if (patterns.length === 0) {
|
||||||
|
return '║ No significant patterns detected ║';
|
||||||
|
}
|
||||||
|
|
||||||
|
return patterns.slice(0, 3).map(p =>
|
||||||
|
`║ ${p.name.padEnd(20)} Confidence: ${p.confidence}% ${p.direction.padEnd(20)} ║`
|
||||||
|
).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
formatSignals(signals) {
|
||||||
|
if (signals.length === 0) {
|
||||||
|
return '║ No strong signals at this time ║';
|
||||||
|
}
|
||||||
|
|
||||||
|
return signals.slice(0, 3).map(s =>
|
||||||
|
`║ ${s.type} - ${s.reason.padEnd(35)} [${s.confidence}%] ║`
|
||||||
|
).join('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const analyzer = new TrendAnalyzer();
|
||||||
|
const analysis = await analyzer.analyzeTrends({
|
||||||
|
symbol: 'BTC/USDT',
|
||||||
|
timeframe: '4h',
|
||||||
|
period: '30d',
|
||||||
|
analysisType: 'technical'
|
||||||
|
});
|
||||||
|
|
||||||
|
const report = new TrendReport();
|
||||||
|
console.log(report.generateReport(analysis));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Trend analysis failed:', error);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This command provides comprehensive trend analysis with technical indicators, pattern recognition, and actionable trading signals.
|
||||||
727
commands/track-price.md
Normal file
727
commands/track-price.md
Normal file
@@ -0,0 +1,727 @@
|
|||||||
|
---
|
||||||
|
description: Track real-time prices across crypto, stocks, forex, and commodities with multi-source feeds
|
||||||
|
shortcut: tp
|
||||||
|
---
|
||||||
|
|
||||||
|
# Track Market Price
|
||||||
|
|
||||||
|
Real-time price tracking system with institutional-grade data feeds from multiple sources for accuracy and reliability.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
When the user wants to track market prices, implement a comprehensive price monitoring system with these capabilities:
|
||||||
|
|
||||||
|
### Required Information
|
||||||
|
- **Symbol**: Asset ticker (BTC, AAPL, EUR/USD, etc.)
|
||||||
|
- **Asset Type**: crypto, stock, forex, commodity
|
||||||
|
- **Interval**: 1s, 5s, 30s, 1m, 5m (real-time streaming)
|
||||||
|
- **Exchanges**: Specific exchanges or "ALL" for aggregate
|
||||||
|
- **Alert Conditions**: Price thresholds, percentage changes
|
||||||
|
- **Duration**: How long to track (continuous or time-limited)
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
### 1. Multi-Source Price Aggregator
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class MarketPriceTracker {
|
||||||
|
constructor() {
|
||||||
|
this.dataSources = {
|
||||||
|
crypto: {
|
||||||
|
binance: 'wss://stream.binance.com:9443/ws',
|
||||||
|
coinbase: 'wss://ws-feed.exchange.coinbase.com',
|
||||||
|
kraken: 'wss://ws.kraken.com',
|
||||||
|
ftx: 'wss://ftx.com/ws/',
|
||||||
|
coingecko: 'https://api.coingecko.com/api/v3',
|
||||||
|
messari: 'https://data.messari.io/api/v1'
|
||||||
|
},
|
||||||
|
stocks: {
|
||||||
|
alphaVantage: process.env.ALPHA_VANTAGE_API,
|
||||||
|
iex: 'https://api.iextrading.com/1.0',
|
||||||
|
polygon: 'wss://socket.polygon.io',
|
||||||
|
finnhub: 'wss://ws.finnhub.io',
|
||||||
|
yahoo: 'https://query1.finance.yahoo.com/v8'
|
||||||
|
},
|
||||||
|
forex: {
|
||||||
|
oanda: 'wss://stream-fxtrade.oanda.com',
|
||||||
|
forexConnect: 'https://api-fxtrade.oanda.com/v3',
|
||||||
|
currencyLayer: process.env.CURRENCY_LAYER_API,
|
||||||
|
exchangeRates: 'https://api.exchangerate.host'
|
||||||
|
},
|
||||||
|
commodities: {
|
||||||
|
quandl: process.env.QUANDL_API,
|
||||||
|
metalsPrices: 'https://api.metals.live/v1',
|
||||||
|
oilPrices: 'https://api.oilpriceapi.com/v1'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.priceCache = new Map();
|
||||||
|
this.connections = new Map();
|
||||||
|
this.aggregationStrategy = 'VWAP'; // Volume Weighted Average Price
|
||||||
|
}
|
||||||
|
|
||||||
|
async trackPrice(params) {
|
||||||
|
const {
|
||||||
|
symbol,
|
||||||
|
assetType,
|
||||||
|
interval = '1s',
|
||||||
|
exchanges = 'ALL',
|
||||||
|
alertConditions = [],
|
||||||
|
duration = 'continuous'
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
// Validate symbol format
|
||||||
|
this.validateSymbol(symbol, assetType);
|
||||||
|
|
||||||
|
// Initialize tracking
|
||||||
|
const trackingSession = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
symbol,
|
||||||
|
assetType,
|
||||||
|
interval,
|
||||||
|
startTime: Date.now(),
|
||||||
|
duration,
|
||||||
|
exchanges: this.selectExchanges(exchanges, assetType),
|
||||||
|
alerts: this.parseAlertConditions(alertConditions),
|
||||||
|
priceHistory: [],
|
||||||
|
statistics: {
|
||||||
|
high: 0,
|
||||||
|
low: Infinity,
|
||||||
|
open: 0,
|
||||||
|
volume: 0,
|
||||||
|
vwap: 0,
|
||||||
|
changes: {
|
||||||
|
'1m': 0,
|
||||||
|
'5m': 0,
|
||||||
|
'15m': 0,
|
||||||
|
'1h': 0,
|
||||||
|
'24h': 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start real-time tracking
|
||||||
|
await this.initializeConnections(trackingSession);
|
||||||
|
|
||||||
|
// Begin price aggregation
|
||||||
|
this.startPriceAggregation(trackingSession);
|
||||||
|
|
||||||
|
// Monitor alerts
|
||||||
|
this.startAlertMonitoring(trackingSession);
|
||||||
|
|
||||||
|
return trackingSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
async initializeConnections(session) {
|
||||||
|
const connections = [];
|
||||||
|
|
||||||
|
for (const exchange of session.exchanges) {
|
||||||
|
try {
|
||||||
|
const connection = await this.connectToExchange(
|
||||||
|
exchange,
|
||||||
|
session.symbol,
|
||||||
|
session.assetType
|
||||||
|
);
|
||||||
|
|
||||||
|
connections.push({
|
||||||
|
exchange,
|
||||||
|
connection,
|
||||||
|
status: 'connected',
|
||||||
|
latency: 0,
|
||||||
|
lastUpdate: null
|
||||||
|
});
|
||||||
|
|
||||||
|
// Subscribe to price updates
|
||||||
|
this.subscribeToPrice(connection, session);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to connect to ${exchange}:`, error);
|
||||||
|
connections.push({
|
||||||
|
exchange,
|
||||||
|
status: 'failed',
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.connections = connections;
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectToExchange(exchange, symbol, assetType) {
|
||||||
|
const sourceConfig = this.dataSources[assetType][exchange];
|
||||||
|
|
||||||
|
if (sourceConfig.startsWith('wss://')) {
|
||||||
|
// WebSocket connection
|
||||||
|
return this.createWebSocketConnection(sourceConfig, symbol, exchange);
|
||||||
|
} else {
|
||||||
|
// REST API polling
|
||||||
|
return this.createPollingConnection(sourceConfig, symbol, exchange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createWebSocketConnection(url, symbol, exchange) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const ws = new WebSocket(url);
|
||||||
|
|
||||||
|
ws.on('open', () => {
|
||||||
|
// Subscribe to symbol
|
||||||
|
const subscribeMsg = this.getSubscribeMessage(exchange, symbol);
|
||||||
|
ws.send(JSON.stringify(subscribeMsg));
|
||||||
|
resolve(ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('error', reject);
|
||||||
|
|
||||||
|
ws.on('message', (data) => {
|
||||||
|
this.handlePriceUpdate(exchange, data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubscribeMessage(exchange, symbol) {
|
||||||
|
const messages = {
|
||||||
|
binance: {
|
||||||
|
method: 'SUBSCRIBE',
|
||||||
|
params: [`${symbol.toLowerCase()}@trade`, `${symbol.toLowerCase()}@depth`],
|
||||||
|
id: 1
|
||||||
|
},
|
||||||
|
coinbase: {
|
||||||
|
type: 'subscribe',
|
||||||
|
product_ids: [symbol],
|
||||||
|
channels: ['ticker', 'level2']
|
||||||
|
},
|
||||||
|
kraken: {
|
||||||
|
event: 'subscribe',
|
||||||
|
pair: [symbol],
|
||||||
|
subscription: { name: 'ticker' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return messages[exchange] || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePriceUpdate(exchange, data) {
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
const price = this.extractPrice(exchange, parsed);
|
||||||
|
|
||||||
|
if (price) {
|
||||||
|
const update = {
|
||||||
|
exchange,
|
||||||
|
price: price.price,
|
||||||
|
volume: price.volume,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
bid: price.bid,
|
||||||
|
ask: price.ask,
|
||||||
|
spread: price.ask - price.bid
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update cache
|
||||||
|
if (!this.priceCache.has(exchange)) {
|
||||||
|
this.priceCache.set(exchange, []);
|
||||||
|
}
|
||||||
|
this.priceCache.get(exchange).push(update);
|
||||||
|
|
||||||
|
// Trigger aggregation
|
||||||
|
this.aggregatePrices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractPrice(exchange, data) {
|
||||||
|
const extractors = {
|
||||||
|
binance: (d) => ({
|
||||||
|
price: parseFloat(d.p),
|
||||||
|
volume: parseFloat(d.q),
|
||||||
|
bid: parseFloat(d.b),
|
||||||
|
ask: parseFloat(d.a)
|
||||||
|
}),
|
||||||
|
coinbase: (d) => ({
|
||||||
|
price: parseFloat(d.price),
|
||||||
|
volume: parseFloat(d.volume_24h),
|
||||||
|
bid: parseFloat(d.best_bid),
|
||||||
|
ask: parseFloat(d.best_ask)
|
||||||
|
}),
|
||||||
|
kraken: (d) => ({
|
||||||
|
price: parseFloat(d[1].c[0]),
|
||||||
|
volume: parseFloat(d[1].v[1]),
|
||||||
|
bid: parseFloat(d[1].b[0]),
|
||||||
|
ask: parseFloat(d[1].a[0])
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
return extractors[exchange]?.(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregatePrices() {
|
||||||
|
const allPrices = [];
|
||||||
|
|
||||||
|
for (const [exchange, prices] of this.priceCache.entries()) {
|
||||||
|
if (prices.length > 0) {
|
||||||
|
const recent = prices.filter(p =>
|
||||||
|
Date.now() - p.timestamp < 5000 // Last 5 seconds
|
||||||
|
);
|
||||||
|
allPrices.push(...recent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allPrices.length === 0) return null;
|
||||||
|
|
||||||
|
// Calculate aggregated price based on strategy
|
||||||
|
let aggregatedPrice;
|
||||||
|
|
||||||
|
switch (this.aggregationStrategy) {
|
||||||
|
case 'VWAP':
|
||||||
|
aggregatedPrice = this.calculateVWAP(allPrices);
|
||||||
|
break;
|
||||||
|
case 'MEDIAN':
|
||||||
|
aggregatedPrice = this.calculateMedian(allPrices);
|
||||||
|
break;
|
||||||
|
case 'WEIGHTED':
|
||||||
|
aggregatedPrice = this.calculateWeightedAverage(allPrices);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
aggregatedPrice = this.calculateSimpleAverage(allPrices);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
price: aggregatedPrice,
|
||||||
|
sources: allPrices.length,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
spread: this.calculateSpread(allPrices),
|
||||||
|
confidence: this.calculateConfidence(allPrices)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateVWAP(prices) {
|
||||||
|
let totalValue = 0;
|
||||||
|
let totalVolume = 0;
|
||||||
|
|
||||||
|
for (const p of prices) {
|
||||||
|
totalValue += p.price * p.volume;
|
||||||
|
totalVolume += p.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalVolume > 0 ? totalValue / totalVolume : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateConfidence(prices) {
|
||||||
|
if (prices.length < 2) return 0;
|
||||||
|
|
||||||
|
const values = prices.map(p => p.price);
|
||||||
|
const mean = values.reduce((a, b) => a + b) / values.length;
|
||||||
|
const variance = values.reduce((sum, val) =>
|
||||||
|
sum + Math.pow(val - mean, 2), 0) / values.length;
|
||||||
|
const stdDev = Math.sqrt(variance);
|
||||||
|
const coefficientOfVariation = (stdDev / mean) * 100;
|
||||||
|
|
||||||
|
// Lower CV means higher confidence
|
||||||
|
if (coefficientOfVariation < 0.5) return 99;
|
||||||
|
if (coefficientOfVariation < 1) return 95;
|
||||||
|
if (coefficientOfVariation < 2) return 90;
|
||||||
|
if (coefficientOfVariation < 5) return 75;
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
startAlertMonitoring(session) {
|
||||||
|
const checkInterval = this.parseInterval(session.interval);
|
||||||
|
|
||||||
|
session.alertMonitor = setInterval(() => {
|
||||||
|
const currentPrice = this.getCurrentPrice(session.symbol);
|
||||||
|
if (!currentPrice) return;
|
||||||
|
|
||||||
|
for (const alert of session.alerts) {
|
||||||
|
if (this.checkAlertCondition(alert, currentPrice, session)) {
|
||||||
|
this.triggerAlert(alert, currentPrice, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, checkInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAlertCondition(alert, price, session) {
|
||||||
|
switch (alert.type) {
|
||||||
|
case 'PRICE_ABOVE':
|
||||||
|
return price.price > alert.threshold;
|
||||||
|
|
||||||
|
case 'PRICE_BELOW':
|
||||||
|
return price.price < alert.threshold;
|
||||||
|
|
||||||
|
case 'PERCENT_CHANGE':
|
||||||
|
const changePercent = this.calculatePercentChange(
|
||||||
|
session.statistics.open,
|
||||||
|
price.price
|
||||||
|
);
|
||||||
|
return Math.abs(changePercent) > alert.threshold;
|
||||||
|
|
||||||
|
case 'VOLUME_SPIKE':
|
||||||
|
return price.volume > session.statistics.avgVolume * alert.multiplier;
|
||||||
|
|
||||||
|
case 'SPREAD_WIDE':
|
||||||
|
return price.spread > alert.threshold;
|
||||||
|
|
||||||
|
case 'VOLATILITY':
|
||||||
|
return this.calculateVolatility(session) > alert.threshold;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerAlert(alert, price, session) {
|
||||||
|
const alertData = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
type: alert.type,
|
||||||
|
symbol: session.symbol,
|
||||||
|
price: price.price,
|
||||||
|
threshold: alert.threshold,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
message: this.formatAlertMessage(alert, price, session),
|
||||||
|
severity: alert.severity || 'INFO',
|
||||||
|
action: alert.action || 'NOTIFY'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send alert through notification channels
|
||||||
|
this.sendAlert(alertData);
|
||||||
|
|
||||||
|
// Log alert
|
||||||
|
if (!session.triggeredAlerts) {
|
||||||
|
session.triggeredAlerts = [];
|
||||||
|
}
|
||||||
|
session.triggeredAlerts.push(alertData);
|
||||||
|
|
||||||
|
// Execute automated actions if configured
|
||||||
|
if (alert.action === 'AUTO_TRADE') {
|
||||||
|
this.executeAutomatedAction(alert, price, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Price Display Interface
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class PriceDisplay {
|
||||||
|
constructor() {
|
||||||
|
this.displayMode = 'detailed'; // 'simple', 'detailed', 'professional'
|
||||||
|
this.updateFrequency = 1000; // milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
displayPrice(session, aggregatedPrice) {
|
||||||
|
const display = `
|
||||||
|
╔════════════════════════════════════════════════════════════════╗
|
||||||
|
║ REAL-TIME PRICE TRACKER ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ Symbol: ${session.symbol.padEnd(48)} ║
|
||||||
|
║ Asset Type: ${session.assetType.padEnd(48)} ║
|
||||||
|
║ Current Price: ${this.formatPrice(aggregatedPrice.price).padEnd(48)} ║
|
||||||
|
║ Confidence: ${this.formatConfidence(aggregatedPrice.confidence).padEnd(48)} ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ PRICE METRICS ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ 24H High: ${this.formatPrice(session.statistics.high).padEnd(48)} ║
|
||||||
|
║ 24H Low: ${this.formatPrice(session.statistics.low).padEnd(48)} ║
|
||||||
|
║ 24H Change: ${this.formatChange(session.statistics.changes['24h']).padEnd(48)} ║
|
||||||
|
║ Volume: ${this.formatVolume(session.statistics.volume).padEnd(48)} ║
|
||||||
|
║ VWAP: ${this.formatPrice(session.statistics.vwap).padEnd(48)} ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ EXCHANGE PRICES ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
${this.formatExchangePrices(session)}
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ ALERTS ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
${this.formatAlerts(session)}
|
||||||
|
╚════════════════════════════════════════════════════════════════╝
|
||||||
|
`;
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatExchangePrices(session) {
|
||||||
|
const lines = [];
|
||||||
|
for (const conn of session.connections) {
|
||||||
|
if (conn.status === 'connected' && conn.lastPrice) {
|
||||||
|
lines.push(`║ ${conn.exchange.padEnd(15)} ${this.formatPrice(conn.lastPrice).padEnd(15)} ${this.formatLatency(conn.latency).padEnd(26)} ║`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
formatAlerts(session) {
|
||||||
|
if (!session.alerts || session.alerts.length === 0) {
|
||||||
|
return '║ No active alerts ║';
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = [];
|
||||||
|
for (const alert of session.alerts) {
|
||||||
|
const status = alert.triggered ? '' : '⏳';
|
||||||
|
lines.push(`║ ${status} ${alert.type}: ${alert.threshold} ║`);
|
||||||
|
}
|
||||||
|
return lines.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
formatPrice(price) {
|
||||||
|
if (price > 1000) {
|
||||||
|
return `$${price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
||||||
|
} else if (price > 1) {
|
||||||
|
return `$${price.toFixed(4)}`;
|
||||||
|
} else {
|
||||||
|
return `$${price.toFixed(8)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatConfidence(confidence) {
|
||||||
|
const bars = '█'.repeat(Math.floor(confidence / 10));
|
||||||
|
const empty = '░'.repeat(10 - Math.floor(confidence / 10));
|
||||||
|
return `${bars}${empty} ${confidence}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Advanced Analytics
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class PriceAnalytics {
|
||||||
|
constructor() {
|
||||||
|
this.indicators = {};
|
||||||
|
this.patterns = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzePrice(priceHistory) {
|
||||||
|
return {
|
||||||
|
technicalIndicators: this.calculateTechnicalIndicators(priceHistory),
|
||||||
|
pricePatterns: this.detectPatterns(priceHistory),
|
||||||
|
supportResistance: this.findSupportResistance(priceHistory),
|
||||||
|
volatility: this.analyzeVolatility(priceHistory),
|
||||||
|
momentum: this.analyzeMomentum(priceHistory),
|
||||||
|
marketStructure: this.analyzeMarketStructure(priceHistory)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateTechnicalIndicators(prices) {
|
||||||
|
return {
|
||||||
|
sma: {
|
||||||
|
sma20: this.calculateSMA(prices, 20),
|
||||||
|
sma50: this.calculateSMA(prices, 50),
|
||||||
|
sma200: this.calculateSMA(prices, 200)
|
||||||
|
},
|
||||||
|
ema: {
|
||||||
|
ema12: this.calculateEMA(prices, 12),
|
||||||
|
ema26: this.calculateEMA(prices, 26)
|
||||||
|
},
|
||||||
|
rsi: this.calculateRSI(prices, 14),
|
||||||
|
macd: this.calculateMACD(prices),
|
||||||
|
bollingerBands: this.calculateBollingerBands(prices, 20, 2),
|
||||||
|
atr: this.calculateATR(prices, 14),
|
||||||
|
obv: this.calculateOBV(prices),
|
||||||
|
vwap: this.calculateDailyVWAP(prices)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
detectPatterns(prices) {
|
||||||
|
const patterns = [];
|
||||||
|
|
||||||
|
// Head and Shoulders
|
||||||
|
if (this.detectHeadAndShoulders(prices)) {
|
||||||
|
patterns.push({
|
||||||
|
type: 'HEAD_AND_SHOULDERS',
|
||||||
|
direction: 'BEARISH',
|
||||||
|
confidence: 85
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double Top/Bottom
|
||||||
|
const doublePattern = this.detectDoubleTopBottom(prices);
|
||||||
|
if (doublePattern) {
|
||||||
|
patterns.push(doublePattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triangle Patterns
|
||||||
|
const triangle = this.detectTriangle(prices);
|
||||||
|
if (triangle) {
|
||||||
|
patterns.push(triangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flag/Pennant
|
||||||
|
const flagPattern = this.detectFlagPennant(prices);
|
||||||
|
if (flagPattern) {
|
||||||
|
patterns.push(flagPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
findSupportResistance(prices) {
|
||||||
|
const levels = [];
|
||||||
|
const priceValues = prices.map(p => p.price);
|
||||||
|
|
||||||
|
// Find local maxima and minima
|
||||||
|
for (let i = 2; i < priceValues.length - 2; i++) {
|
||||||
|
// Resistance (local maximum)
|
||||||
|
if (priceValues[i] > priceValues[i-1] &&
|
||||||
|
priceValues[i] > priceValues[i-2] &&
|
||||||
|
priceValues[i] > priceValues[i+1] &&
|
||||||
|
priceValues[i] > priceValues[i+2]) {
|
||||||
|
levels.push({
|
||||||
|
type: 'RESISTANCE',
|
||||||
|
price: priceValues[i],
|
||||||
|
strength: this.calculateLevelStrength(prices, priceValues[i]),
|
||||||
|
touches: this.countTouches(prices, priceValues[i])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support (local minimum)
|
||||||
|
if (priceValues[i] < priceValues[i-1] &&
|
||||||
|
priceValues[i] < priceValues[i-2] &&
|
||||||
|
priceValues[i] < priceValues[i+1] &&
|
||||||
|
priceValues[i] < priceValues[i+2]) {
|
||||||
|
levels.push({
|
||||||
|
type: 'SUPPORT',
|
||||||
|
price: priceValues[i],
|
||||||
|
strength: this.calculateLevelStrength(prices, priceValues[i]),
|
||||||
|
touches: this.countTouches(prices, priceValues[i])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cluster similar levels
|
||||||
|
return this.clusterLevels(levels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Alert Configuration
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class AlertConfiguration {
|
||||||
|
parseAlertConditions(conditions) {
|
||||||
|
const parsed = [];
|
||||||
|
|
||||||
|
for (const condition of conditions) {
|
||||||
|
if (typeof condition === 'string') {
|
||||||
|
// Parse string format: "above 50000", "below 45000", "change 5%"
|
||||||
|
const match = condition.match(/(\w+)\s+([0-9.]+)(%)?/);
|
||||||
|
if (match) {
|
||||||
|
parsed.push(this.createAlert(match[1], parseFloat(match[2]), match[3] === '%'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Object format already
|
||||||
|
parsed.push(condition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
createAlert(type, value, isPercent) {
|
||||||
|
const alertTypes = {
|
||||||
|
'above': 'PRICE_ABOVE',
|
||||||
|
'below': 'PRICE_BELOW',
|
||||||
|
'change': 'PERCENT_CHANGE',
|
||||||
|
'volume': 'VOLUME_SPIKE',
|
||||||
|
'spread': 'SPREAD_WIDE',
|
||||||
|
'volatility': 'VOLATILITY'
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: alertTypes[type] || 'CUSTOM',
|
||||||
|
threshold: value,
|
||||||
|
isPercent,
|
||||||
|
enabled: true,
|
||||||
|
cooldown: 300000, // 5 minutes between repeat alerts
|
||||||
|
lastTriggered: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. WebSocket Manager
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class WebSocketManager {
|
||||||
|
constructor() {
|
||||||
|
this.connections = new Map();
|
||||||
|
this.reconnectAttempts = new Map();
|
||||||
|
this.maxReconnectAttempts = 5;
|
||||||
|
this.reconnectDelay = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
async manage(url, handlers) {
|
||||||
|
const ws = new WebSocket(url);
|
||||||
|
const connectionId = crypto.randomUUID();
|
||||||
|
|
||||||
|
ws.on('open', () => {
|
||||||
|
console.log(`WebSocket connected: ${url}`);
|
||||||
|
this.connections.set(connectionId, ws);
|
||||||
|
this.reconnectAttempts.set(connectionId, 0);
|
||||||
|
handlers.onOpen?.(ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('message', (data) => {
|
||||||
|
handlers.onMessage?.(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('error', (error) => {
|
||||||
|
console.error(`WebSocket error: ${url}`, error);
|
||||||
|
handlers.onError?.(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('close', () => {
|
||||||
|
console.log(`WebSocket closed: ${url}`);
|
||||||
|
this.connections.delete(connectionId);
|
||||||
|
this.attemptReconnect(url, handlers, connectionId);
|
||||||
|
});
|
||||||
|
|
||||||
|
return connectionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptReconnect(url, handlers, connectionId) {
|
||||||
|
const attempts = this.reconnectAttempts.get(connectionId) || 0;
|
||||||
|
|
||||||
|
if (attempts < this.maxReconnectAttempts) {
|
||||||
|
const delay = this.reconnectDelay * Math.pow(2, attempts);
|
||||||
|
console.log(`Reconnecting in ${delay}ms... (attempt ${attempts + 1})`);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.reconnectAttempts.set(connectionId, attempts + 1);
|
||||||
|
this.manage(url, handlers);
|
||||||
|
}, delay);
|
||||||
|
} else {
|
||||||
|
console.error(`Max reconnection attempts reached for ${url}`);
|
||||||
|
handlers.onMaxReconnectFailed?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const tracker = new MarketPriceTracker();
|
||||||
|
const session = await tracker.trackPrice({
|
||||||
|
symbol: 'BTC/USDT',
|
||||||
|
assetType: 'crypto',
|
||||||
|
interval: '1s',
|
||||||
|
exchanges: ['binance', 'coinbase', 'kraken'],
|
||||||
|
alertConditions: [
|
||||||
|
'above 50000',
|
||||||
|
'below 45000',
|
||||||
|
'change 5%',
|
||||||
|
'volume 2x'
|
||||||
|
],
|
||||||
|
duration: '24h'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display real-time updates
|
||||||
|
const display = new PriceDisplay();
|
||||||
|
setInterval(async () => {
|
||||||
|
const price = tracker.getCurrentPrice(session.symbol);
|
||||||
|
console.clear();
|
||||||
|
console.log(display.displayPrice(session, price));
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Price tracking failed:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This command provides institutional-grade real-time price tracking with multi-exchange aggregation, advanced alerts, and comprehensive analytics.
|
||||||
89
plugin.lock.json
Normal file
89
plugin.lock.json
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:jeremylongshore/claude-code-plugins-plus:plugins/crypto/market-price-tracker",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "16ca5701c9d9fd3b3bda7c4ec84bfad58cb652c9",
|
||||||
|
"treeHash": "de3aa04d54e8feb5414004b0507da6a0f0c7c15c4866dca481050e4389863ee4",
|
||||||
|
"generatedAt": "2025-11-28T10:18:33.430628Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "market-price-tracker",
|
||||||
|
"description": "Real-time market price tracking with multi-exchange feeds and advanced alerts",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "1037f0e86eed8da073444155dcad3bb51a90233b9c839390c47cd70e1d0dc910"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "f237a6bf67e7da0ede495e2ba80ff9a74c3f763f8737cfa5c3bc3c47a242d3f4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/analyze-trends.md",
|
||||||
|
"sha256": "f17d18d08a685fde5a545da6574fd8ff86bcf9fbd740e560b75e94512621fa82"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/track-price.md",
|
||||||
|
"sha256": "664434cbc19c96845b84e314c792791e1c38cdd7179be744c774829c34179b4e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/references/examples.md",
|
||||||
|
"sha256": "922bbc3c4ebf38b76f515b5c1998ebde6bf902233e00e2c5a0e9176f975a7572"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/references/best-practices.md",
|
||||||
|
"sha256": "c8f32b3566252f50daacd346d7045a1060c718ef5cfb07c55a0f2dec5f1fb39e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/references/README.md",
|
||||||
|
"sha256": "7cf039498448a36e5480704b748b4d17d2c341966c16b583285d5b88ae7da658"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/scripts/helper-template.sh",
|
||||||
|
"sha256": "0881d5660a8a7045550d09ae0acc15642c24b70de6f08808120f47f86ccdf077"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/scripts/validation.sh",
|
||||||
|
"sha256": "92551a29a7f512d2036e4f1fb46c2a3dc6bff0f7dde4a9f699533e446db48502"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/scripts/README.md",
|
||||||
|
"sha256": "7b79d99b557e0d4201ed110cff55aa6640d2e0cc4abb699c20959cff5a62f3f6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/assets/test-data.json",
|
||||||
|
"sha256": "ac17dca3d6e253a5f39f2a2f1b388e5146043756b05d9ce7ac53a0042eee139d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/assets/README.md",
|
||||||
|
"sha256": "33f9548da8bf39202af0b1f55321de502708306bc5f64a3be1eb932e858f73bc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/assets/skill-schema.json",
|
||||||
|
"sha256": "f5639ba823a24c9ac4fb21444c0717b7aefde1a4993682897f5bf544f863c2cd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/skill-adapter/assets/config-template.json",
|
||||||
|
"sha256": "0c2ba33d2d3c5ccb266c0848fc43caa68a2aa6a80ff315d4b378352711f83e1c"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "de3aa04d54e8feb5414004b0507da6a0f0c7c15c4866dca481050e4389863ee4"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
7
skills/skill-adapter/assets/README.md
Normal file
7
skills/skill-adapter/assets/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Assets
|
||||||
|
|
||||||
|
Bundled resources for market-price-tracker skill
|
||||||
|
|
||||||
|
- [ ] alert_templates.json: JSON templates for different types of price alerts (e.g., price above threshold, percentage change).
|
||||||
|
- [ ] example_data.json: Example data structures for real-time price feeds and technical analysis results.
|
||||||
|
- [ ] config_template.json: Configuration template for setting up data sources, API keys, and alert preferences.
|
||||||
32
skills/skill-adapter/assets/config-template.json
Normal file
32
skills/skill-adapter/assets/config-template.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"skill": {
|
||||||
|
"name": "skill-name",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"enabled": true,
|
||||||
|
"settings": {
|
||||||
|
"verbose": false,
|
||||||
|
"autoActivate": true,
|
||||||
|
"toolRestrictions": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"triggers": {
|
||||||
|
"keywords": [
|
||||||
|
"example-trigger-1",
|
||||||
|
"example-trigger-2"
|
||||||
|
],
|
||||||
|
"patterns": []
|
||||||
|
},
|
||||||
|
"tools": {
|
||||||
|
"allowed": [
|
||||||
|
"Read",
|
||||||
|
"Grep",
|
||||||
|
"Bash"
|
||||||
|
],
|
||||||
|
"restricted": []
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"author": "Plugin Author",
|
||||||
|
"category": "general",
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
28
skills/skill-adapter/assets/skill-schema.json
Normal file
28
skills/skill-adapter/assets/skill-schema.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "Claude Skill Configuration",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["name", "description"],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-z0-9-]+$",
|
||||||
|
"maxLength": 64,
|
||||||
|
"description": "Skill identifier (lowercase, hyphens only)"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 1024,
|
||||||
|
"description": "What the skill does and when to use it"
|
||||||
|
},
|
||||||
|
"allowed-tools": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Comma-separated list of allowed tools"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
||||||
|
"description": "Semantic version (x.y.z)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
skills/skill-adapter/assets/test-data.json
Normal file
27
skills/skill-adapter/assets/test-data.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"testCases": [
|
||||||
|
{
|
||||||
|
"name": "Basic activation test",
|
||||||
|
"input": "trigger phrase example",
|
||||||
|
"expected": {
|
||||||
|
"activated": true,
|
||||||
|
"toolsUsed": ["Read", "Grep"],
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Complex workflow test",
|
||||||
|
"input": "multi-step trigger example",
|
||||||
|
"expected": {
|
||||||
|
"activated": true,
|
||||||
|
"steps": 3,
|
||||||
|
"toolsUsed": ["Read", "Write", "Bash"],
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fixtures": {
|
||||||
|
"sampleInput": "example data",
|
||||||
|
"expectedOutput": "processed result"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
skills/skill-adapter/references/README.md
Normal file
8
skills/skill-adapter/references/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# References
|
||||||
|
|
||||||
|
Bundled resources for market-price-tracker skill
|
||||||
|
|
||||||
|
- [ ] crypto_exchanges_api.md: API documentation for various crypto exchanges like Binance, Coinbase, Kraken.
|
||||||
|
- [ ] stock_data_api.md: API documentation for stock data providers like Alpha Vantage, IEX Cloud, Polygon.io.
|
||||||
|
- [ ] forex_feeds_api.md: API documentation for forex data feeds like OANDA, Forex Connect, Currency Layer.
|
||||||
|
- [ ] technical_indicators.md: Detailed explanations and formulas for technical indicators like RSI, MACD, Bollinger Bands.
|
||||||
69
skills/skill-adapter/references/best-practices.md
Normal file
69
skills/skill-adapter/references/best-practices.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Skill Best Practices
|
||||||
|
|
||||||
|
Guidelines for optimal skill usage and development.
|
||||||
|
|
||||||
|
## For Users
|
||||||
|
|
||||||
|
### Activation Best Practices
|
||||||
|
|
||||||
|
1. **Use Clear Trigger Phrases**
|
||||||
|
- Match phrases from skill description
|
||||||
|
- Be specific about intent
|
||||||
|
- Provide necessary context
|
||||||
|
|
||||||
|
2. **Provide Sufficient Context**
|
||||||
|
- Include relevant file paths
|
||||||
|
- Specify scope of analysis
|
||||||
|
- Mention any constraints
|
||||||
|
|
||||||
|
3. **Understand Tool Permissions**
|
||||||
|
- Check allowed-tools in frontmatter
|
||||||
|
- Know what the skill can/cannot do
|
||||||
|
- Request appropriate actions
|
||||||
|
|
||||||
|
### Workflow Optimization
|
||||||
|
|
||||||
|
- Start with simple requests
|
||||||
|
- Build up to complex workflows
|
||||||
|
- Verify each step before proceeding
|
||||||
|
- Use skill consistently for related tasks
|
||||||
|
|
||||||
|
## For Developers
|
||||||
|
|
||||||
|
### Skill Development Guidelines
|
||||||
|
|
||||||
|
1. **Clear Descriptions**
|
||||||
|
- Include explicit trigger phrases
|
||||||
|
- Document all capabilities
|
||||||
|
- Specify limitations
|
||||||
|
|
||||||
|
2. **Proper Tool Permissions**
|
||||||
|
- Use minimal necessary tools
|
||||||
|
- Document security implications
|
||||||
|
- Test with restricted tools
|
||||||
|
|
||||||
|
3. **Comprehensive Documentation**
|
||||||
|
- Provide usage examples
|
||||||
|
- Document common pitfalls
|
||||||
|
- Include troubleshooting guide
|
||||||
|
|
||||||
|
### Maintenance
|
||||||
|
|
||||||
|
- Keep version updated
|
||||||
|
- Test after tool updates
|
||||||
|
- Monitor user feedback
|
||||||
|
- Iterate on descriptions
|
||||||
|
|
||||||
|
## Performance Tips
|
||||||
|
|
||||||
|
- Scope skills to specific domains
|
||||||
|
- Avoid overlapping trigger phrases
|
||||||
|
- Keep descriptions under 1024 chars
|
||||||
|
- Test activation reliability
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- Never include secrets in skill files
|
||||||
|
- Validate all inputs
|
||||||
|
- Use read-only tools when possible
|
||||||
|
- Document security requirements
|
||||||
70
skills/skill-adapter/references/examples.md
Normal file
70
skills/skill-adapter/references/examples.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Skill Usage Examples
|
||||||
|
|
||||||
|
This document provides practical examples of how to use this skill effectively.
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
### Example 1: Simple Activation
|
||||||
|
|
||||||
|
**User Request:**
|
||||||
|
```
|
||||||
|
[Describe trigger phrase here]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skill Response:**
|
||||||
|
1. Analyzes the request
|
||||||
|
2. Performs the required action
|
||||||
|
3. Returns results
|
||||||
|
|
||||||
|
### Example 2: Complex Workflow
|
||||||
|
|
||||||
|
**User Request:**
|
||||||
|
```
|
||||||
|
[Describe complex scenario]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Workflow:**
|
||||||
|
1. Step 1: Initial analysis
|
||||||
|
2. Step 2: Data processing
|
||||||
|
3. Step 3: Result generation
|
||||||
|
4. Step 4: Validation
|
||||||
|
|
||||||
|
## Advanced Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Chaining Operations
|
||||||
|
|
||||||
|
Combine this skill with other tools:
|
||||||
|
```
|
||||||
|
Step 1: Use this skill for [purpose]
|
||||||
|
Step 2: Chain with [other tool]
|
||||||
|
Step 3: Finalize with [action]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 2: Error Handling
|
||||||
|
|
||||||
|
If issues occur:
|
||||||
|
- Check trigger phrase matches
|
||||||
|
- Verify context is available
|
||||||
|
- Review allowed-tools permissions
|
||||||
|
|
||||||
|
## Tips & Best Practices
|
||||||
|
|
||||||
|
- ✅ Be specific with trigger phrases
|
||||||
|
- ✅ Provide necessary context
|
||||||
|
- ✅ Check tool permissions match needs
|
||||||
|
- ❌ Avoid vague requests
|
||||||
|
- ❌ Don't mix unrelated tasks
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
**Issue:** Skill doesn't activate
|
||||||
|
**Solution:** Use exact trigger phrases from description
|
||||||
|
|
||||||
|
**Issue:** Unexpected results
|
||||||
|
**Solution:** Check input format and context
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- Main SKILL.md for full documentation
|
||||||
|
- scripts/ for automation helpers
|
||||||
|
- assets/ for configuration examples
|
||||||
7
skills/skill-adapter/scripts/README.md
Normal file
7
skills/skill-adapter/scripts/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Scripts
|
||||||
|
|
||||||
|
Bundled resources for market-price-tracker skill
|
||||||
|
|
||||||
|
- [ ] price_tracker.py: Script to track prices of crypto, stocks, forex, commodities using WebSocket connections and data aggregation.
|
||||||
|
- [ ] alert_manager.py: Script to manage price alerts based on user-defined conditions and send notifications.
|
||||||
|
- [ ] technical_analysis.py: Script to calculate technical indicators like RSI, MACD, and moving averages.
|
||||||
42
skills/skill-adapter/scripts/helper-template.sh
Executable file
42
skills/skill-adapter/scripts/helper-template.sh
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Helper script template for skill automation
|
||||||
|
# Customize this for your skill's specific needs
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function show_usage() {
|
||||||
|
echo "Usage: $0 [options]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo " -v, --verbose Enable verbose output"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
VERBOSE=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-h|--help)
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-v|--verbose)
|
||||||
|
VERBOSE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Your skill logic here
|
||||||
|
if [ "$VERBOSE" = true ]; then
|
||||||
|
echo "Running skill automation..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Complete"
|
||||||
32
skills/skill-adapter/scripts/validation.sh
Executable file
32
skills/skill-adapter/scripts/validation.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Skill validation helper
|
||||||
|
# Validates skill activation and functionality
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🔍 Validating skill..."
|
||||||
|
|
||||||
|
# Check if SKILL.md exists
|
||||||
|
if [ ! -f "../SKILL.md" ]; then
|
||||||
|
echo "❌ Error: SKILL.md not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate frontmatter
|
||||||
|
if ! grep -q "^---$" "../SKILL.md"; then
|
||||||
|
echo "❌ Error: No frontmatter found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check required fields
|
||||||
|
if ! grep -q "^name:" "../SKILL.md"; then
|
||||||
|
echo "❌ Error: Missing 'name' field"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q "^description:" "../SKILL.md"; then
|
||||||
|
echo "❌ Error: Missing 'description' field"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Skill validation passed"
|
||||||
Reference in New Issue
Block a user