Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:53:19 +08:00
commit 1e3b5bcace
14 changed files with 1327 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
{
"name": "market-movers-scanner",
"description": "Scan for top market movers - gainers, losers, volume spikes, and unusual activity",
"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
View File

@@ -0,0 +1,3 @@
# market-movers-scanner
Scan for top market movers - gainers, losers, volume spikes, and unusual activity

900
commands/scan-movers.md Normal file
View File

@@ -0,0 +1,900 @@
---
description: Scan for top market movers across crypto, stocks, and forex with real-time updates
shortcut: sm
---
# Scan Market Movers
Comprehensive market scanner identifying top gainers, losers, volume leaders, and unusual activity across multiple asset classes.
## Usage
When the user wants to scan for market movers, implement a real-time scanning system with these capabilities:
### Scan Parameters
- **Markets**: crypto, stocks, forex, all
- **Timeframe**: 1h, 4h, 24h, 7d, 30d
- **Categories**: gainers, losers, volume, volatility, unusual
- **Limit**: Top N results (default: 20)
- **Filters**: Market cap, volume thresholds, price ranges
- **Sort**: By percentage, volume, market cap, volatility
## Implementation
### 1. Market Scanner Engine
```javascript
class MarketMoversScanner {
constructor() {
this.dataSources = {
crypto: {
coingecko: 'https://api.coingecko.com/api/v3',
coinmarketcap: process.env.CMC_API_KEY,
messari: 'https://data.messari.io/api/v1',
binance: 'https://api.binance.com/api/v3'
},
stocks: {
yahoo: 'https://query1.finance.yahoo.com/v1',
alphavantage: process.env.ALPHA_VANTAGE_API,
iex: 'https://api.iextrading.com/1.0',
polygon: process.env.POLYGON_API_KEY
},
forex: {
oanda: process.env.OANDA_API_KEY,
fixer: process.env.FIXER_API_KEY,
currencylayer: process.env.CURRENCY_LAYER_API
}
};
this.scanCache = new Map();
this.updateInterval = 60000; // 1 minute
this.lastUpdate = {};
}
async scanMarkets(params) {
const {
markets = 'all',
timeframe = '24h',
categories = ['gainers', 'losers', 'volume'],
limit = 20,
filters = {},
sortBy = 'percentage'
} = params;
// Initialize scan results
const results = {
timestamp: Date.now(),
timeframe,
markets: markets === 'all' ? ['crypto', 'stocks', 'forex'] : [markets],
data: {
gainers: [],
losers: [],
volumeLeaders: [],
volatilityLeaders: [],
unusual: [],
breakouts: [],
newHighs: [],
newLows: []
},
statistics: {},
alerts: []
};
// Scan each market
for (const market of results.markets) {
const marketData = await this.scanMarket(market, timeframe, filters);
results.data = this.mergeMarketData(results.data, marketData);
}
// Process categories
for (const category of categories) {
results.data[category] = await this.processCategory(
category,
results.data,
limit,
sortBy
);
}
// Calculate statistics
results.statistics = this.calculateStatistics(results.data);
// Identify alerts
results.alerts = this.identifyAlerts(results.data);
return results;
}
async scanMarket(market, timeframe, filters) {
const cacheKey = `${market}_${timeframe}`;
// Check cache
if (this.scanCache.has(cacheKey)) {
const cached = this.scanCache.get(cacheKey);
if (Date.now() - cached.timestamp < this.updateInterval) {
return cached.data;
}
}
// Fetch fresh data
let marketData;
switch (market) {
case 'crypto':
marketData = await this.scanCrypto(timeframe, filters);
break;
case 'stocks':
marketData = await this.scanStocks(timeframe, filters);
break;
case 'forex':
marketData = await this.scanForex(timeframe, filters);
break;
default:
throw new Error(`Unsupported market: ${market}`);
}
// Update cache
this.scanCache.set(cacheKey, {
timestamp: Date.now(),
data: marketData
});
return marketData;
}
async scanCrypto(timeframe, filters) {
const assets = [];
try {
// Fetch from CoinGecko
const cgData = await this.fetchCoinGeckoData(timeframe);
for (const coin of cgData) {
if (this.applyFilters(coin, filters)) {
assets.push({
symbol: coin.symbol.toUpperCase(),
name: coin.name,
market: 'crypto',
price: coin.current_price,
change: this.getChangeForTimeframe(coin, timeframe),
volume: coin.total_volume,
marketCap: coin.market_cap,
high24h: coin.high_24h,
low24h: coin.low_24h,
ath: coin.ath,
athDate: coin.ath_date,
circulatingSupply: coin.circulating_supply,
rank: coin.market_cap_rank,
sparkline: coin.sparkline_in_7d?.price || [],
metrics: {
volatility: this.calculateVolatility(coin),
momentum: this.calculateMomentum(coin),
relativeVolume: coin.total_volume / coin.market_cap,
priceScore: this.calculatePriceScore(coin)
}
});
}
}
// Fetch from Binance for real-time data
const binanceData = await this.fetchBinanceData();
this.enrichWithBinanceData(assets, binanceData);
} catch (error) {
console.error('Error scanning crypto:', error);
}
return assets;
}
async fetchCoinGeckoData(timeframe) {
const periods = {
'1h': '1h',
'24h': '24h',
'7d': '7d',
'30d': '30d'
};
const response = await fetch(
`${this.dataSources.crypto.coingecko}/coins/markets?` +
`vs_currency=usd&order=market_cap_desc&per_page=500&` +
`price_change_percentage=${periods[timeframe] || '24h'},7d,30d&` +
`sparkline=true`
);
return response.json();
}
async fetchBinanceData() {
const response = await fetch(
`${this.dataSources.crypto.binance}/ticker/24hr`
);
const data = await response.json();
const processed = {};
for (const ticker of data) {
if (ticker.symbol.endsWith('USDT')) {
const symbol = ticker.symbol.replace('USDT', '');
processed[symbol] = {
price: parseFloat(ticker.lastPrice),
change24h: parseFloat(ticker.priceChangePercent),
volume: parseFloat(ticker.volume),
quoteVolume: parseFloat(ticker.quoteVolume),
count: parseInt(ticker.count),
weightedAvgPrice: parseFloat(ticker.weightedAvgPrice)
};
}
}
return processed;
}
getChangeForTimeframe(coin, timeframe) {
const changeMap = {
'1h': coin.price_change_percentage_1h_in_currency,
'24h': coin.price_change_percentage_24h,
'7d': coin.price_change_percentage_7d_in_currency,
'30d': coin.price_change_percentage_30d_in_currency
};
return changeMap[timeframe] || coin.price_change_percentage_24h || 0;
}
calculateVolatility(asset) {
if (!asset.sparkline_in_7d?.price || asset.sparkline_in_7d.price.length < 2) {
return 0;
}
const prices = asset.sparkline_in_7d.price;
const returns = [];
for (let i = 1; i < prices.length; i++) {
returns.push((prices[i] - prices[i-1]) / prices[i-1]);
}
const mean = returns.reduce((a, b) => a + b) / returns.length;
const variance = returns.reduce((sum, r) => sum + Math.pow(r - mean, 2), 0) / returns.length;
return Math.sqrt(variance) * 100; // Percentage volatility
}
calculateMomentum(asset) {
const weights = {
'24h': 0.4,
'7d': 0.3,
'30d': 0.3
};
const momentum =
(asset.price_change_percentage_24h || 0) * weights['24h'] +
(asset.price_change_percentage_7d_in_currency || 0) * weights['7d'] +
(asset.price_change_percentage_30d_in_currency || 0) * weights['30d'];
return momentum;
}
calculatePriceScore(asset) {
// Score based on price position relative to range
const range = asset.high_24h - asset.low_24h;
if (range === 0) return 50;
const position = (asset.current_price - asset.low_24h) / range;
return position * 100;
}
async scanStocks(timeframe, filters) {
const assets = [];
try {
// Fetch major indices components
const indices = ['SPY', 'QQQ', 'DIA']; // S&P 500, NASDAQ, Dow ETFs
const stockList = await this.fetchStockList(indices);
for (const symbol of stockList) {
const stockData = await this.fetchStockData(symbol, timeframe);
if (stockData && this.applyFilters(stockData, filters)) {
assets.push({
symbol: stockData.symbol,
name: stockData.name,
market: 'stocks',
price: stockData.price,
change: stockData.changePercent,
volume: stockData.volume,
marketCap: stockData.marketCap,
high52w: stockData.week52High,
low52w: stockData.week52Low,
pe: stockData.peRatio,
eps: stockData.eps,
dividend: stockData.dividendYield,
beta: stockData.beta,
metrics: {
rsi: stockData.rsi,
volumeRatio: stockData.volume / stockData.avgVolume,
priceToHigh: stockData.price / stockData.week52High,
earningsGrowth: stockData.earningsGrowth
}
});
}
}
} catch (error) {
console.error('Error scanning stocks:', error);
}
return assets;
}
async processCategory(category, data, limit, sortBy) {
let categoryData = [];
switch (category) {
case 'gainers':
categoryData = this.findTopGainers(data, limit);
break;
case 'losers':
categoryData = this.findTopLosers(data, limit);
break;
case 'volume':
categoryData = this.findVolumeLeaders(data, limit);
break;
case 'volatility':
categoryData = this.findVolatilityLeaders(data, limit);
break;
case 'unusual':
categoryData = this.findUnusualActivity(data, limit);
break;
case 'breakouts':
categoryData = this.findBreakouts(data, limit);
break;
case 'momentum':
categoryData = this.findMomentumPlays(data, limit);
break;
}
return this.sortResults(categoryData, sortBy);
}
findTopGainers(data, limit) {
const allAssets = [...data.gainers, ...data.losers, ...data.volumeLeaders];
const uniqueAssets = this.removeDuplicates(allAssets);
return uniqueAssets
.filter(asset => asset.change > 0)
.sort((a, b) => b.change - a.change)
.slice(0, limit)
.map(asset => ({
...asset,
category: 'GAINER',
signal: this.generateSignal(asset, 'GAINER')
}));
}
findTopLosers(data, limit) {
const allAssets = [...data.gainers, ...data.losers, ...data.volumeLeaders];
const uniqueAssets = this.removeDuplicates(allAssets);
return uniqueAssets
.filter(asset => asset.change < 0)
.sort((a, b) => a.change - b.change)
.slice(0, limit)
.map(asset => ({
...asset,
category: 'LOSER',
signal: this.generateSignal(asset, 'LOSER')
}));
}
findVolumeLeaders(data, limit) {
const allAssets = this.getAllAssets(data);
return allAssets
.filter(asset => asset.metrics?.volumeRatio > 2)
.sort((a, b) => b.metrics.volumeRatio - a.metrics.volumeRatio)
.slice(0, limit)
.map(asset => ({
...asset,
category: 'VOLUME_LEADER',
volumeMultiple: asset.metrics.volumeRatio.toFixed(2) + 'x',
signal: this.generateSignal(asset, 'VOLUME')
}));
}
findUnusualActivity(data, limit) {
const allAssets = this.getAllAssets(data);
const unusual = [];
for (const asset of allAssets) {
const signals = [];
// Check for unusual volume
if (asset.metrics?.volumeRatio > 5) {
signals.push('EXTREME_VOLUME');
}
// Check for large price movement
if (Math.abs(asset.change) > 20) {
signals.push('LARGE_MOVE');
}
// Check for volatility spike
if (asset.metrics?.volatility > 10) {
signals.push('HIGH_VOLATILITY');
}
// Check for new highs/lows
if (asset.price >= asset.high52w * 0.95) {
signals.push('NEAR_52W_HIGH');
}
if (asset.price <= asset.low52w * 1.05) {
signals.push('NEAR_52W_LOW');
}
if (signals.length > 0) {
unusual.push({
...asset,
category: 'UNUSUAL',
signals,
unusualScore: signals.length * 25
});
}
}
return unusual
.sort((a, b) => b.unusualScore - a.unusualScore)
.slice(0, limit);
}
findBreakouts(data, limit) {
const allAssets = this.getAllAssets(data);
const breakouts = [];
for (const asset of allAssets) {
const breakoutSignals = [];
// Volume breakout
if (asset.metrics?.volumeRatio > 3 && asset.change > 5) {
breakoutSignals.push({
type: 'VOLUME_BREAKOUT',
strength: 'HIGH'
});
}
// Price breakout (near 52-week high)
if (asset.high52w && asset.price > asset.high52w * 0.98) {
breakoutSignals.push({
type: 'PRICE_BREAKOUT',
strength: 'VERY_HIGH',
target: asset.high52w * 1.1
});
}
// Momentum breakout
if (asset.metrics?.momentum > 15) {
breakoutSignals.push({
type: 'MOMENTUM_BREAKOUT',
strength: 'MEDIUM'
});
}
if (breakoutSignals.length > 0) {
breakouts.push({
...asset,
category: 'BREAKOUT',
breakoutSignals,
breakoutScore: this.calculateBreakoutScore(breakoutSignals)
});
}
}
return breakouts
.sort((a, b) => b.breakoutScore - a.breakoutScore)
.slice(0, limit);
}
generateSignal(asset, category) {
const signals = {
strength: 'MEDIUM',
action: 'WATCH',
confidence: 50,
reasons: []
};
// Analyze based on category
if (category === 'GAINER') {
if (asset.change > 20) {
signals.strength = 'STRONG';
signals.action = 'MOMENTUM_PLAY';
signals.confidence = 75;
signals.reasons.push('Strong upward momentum');
}
if (asset.metrics?.volumeRatio > 3) {
signals.confidence += 10;
signals.reasons.push('High volume confirmation');
}
} else if (category === 'LOSER') {
if (asset.change < -20) {
signals.strength = 'STRONG';
signals.action = 'OVERSOLD_BOUNCE';
signals.confidence = 60;
signals.reasons.push('Potential oversold bounce');
}
} else if (category === 'VOLUME') {
signals.strength = 'HIGH';
signals.action = 'INVESTIGATE';
signals.confidence = 70;
signals.reasons.push('Unusual volume activity');
}
return signals;
}
identifyAlerts(data) {
const alerts = [];
// Market-wide alerts
const gainersCount = data.gainers?.filter(a => a.change > 10).length || 0;
const losersCount = data.losers?.filter(a => a.change < -10).length || 0;
if (gainersCount > 50) {
alerts.push({
type: 'MARKET_RALLY',
message: `Strong market rally detected: ${gainersCount} assets up >10%`,
severity: 'INFO'
});
}
if (losersCount > 50) {
alerts.push({
type: 'MARKET_SELLOFF',
message: `Market selloff detected: ${losersCount} assets down >10%`,
severity: 'WARNING'
});
}
// Individual asset alerts
for (const category of Object.values(data)) {
if (!Array.isArray(category)) continue;
for (const asset of category) {
if (asset.change > 50) {
alerts.push({
type: 'EXTREME_GAIN',
symbol: asset.symbol,
message: `${asset.symbol} up ${asset.change.toFixed(2)}% - extreme movement`,
severity: 'HIGH'
});
}
if (asset.change < -30) {
alerts.push({
type: 'EXTREME_LOSS',
symbol: asset.symbol,
message: `${asset.symbol} down ${Math.abs(asset.change).toFixed(2)}% - potential crash`,
severity: 'CRITICAL'
});
}
if (asset.metrics?.volumeRatio > 10) {
alerts.push({
type: 'VOLUME_EXPLOSION',
symbol: asset.symbol,
message: `${asset.symbol} volume ${asset.metrics.volumeRatio.toFixed(1)}x average`,
severity: 'HIGH'
});
}
}
}
return alerts;
}
}
```
### 2. Display Interface
```javascript
class MoversDisplay {
displayResults(results) {
const output = `
╔════════════════════════════════════════════════════════════════╗
║ MARKET MOVERS SCANNER ║
╠════════════════════════════════════════════════════════════════╣
║ Timeframe: ${results.timeframe.padEnd(48)}
║ Markets: ${results.markets.join(', ').padEnd(48)}
║ Last Update: ${new Date(results.timestamp).toLocaleString().padEnd(48)}
╠════════════════════════════════════════════════════════════════╣
║ TOP GAINERS ║
╠════════════════════════════════════════════════════════════════╣
${this.formatMovers(results.data.gainers, 'gain')}
╠════════════════════════════════════════════════════════════════╣
║ TOP LOSERS ║
╠════════════════════════════════════════════════════════════════╣
${this.formatMovers(results.data.losers, 'loss')}
╠════════════════════════════════════════════════════════════════╣
║ VOLUME LEADERS ║
╠════════════════════════════════════════════════════════════════╣
${this.formatVolumeLeaders(results.data.volumeLeaders)}
╠════════════════════════════════════════════════════════════════╣
║ UNUSUAL ACTIVITY ║
╠════════════════════════════════════════════════════════════════╣
${this.formatUnusual(results.data.unusual)}
╠════════════════════════════════════════════════════════════════╣
║ ALERTS ║
╠════════════════════════════════════════════════════════════════╣
${this.formatAlerts(results.alerts)}
╚════════════════════════════════════════════════════════════════╝
`;
return output;
}
formatMovers(movers, type) {
if (!movers || movers.length === 0) {
return '║ No significant movers found ║';
}
const lines = [];
for (const mover of movers.slice(0, 5)) {
const changeStr = type === 'gain'
? `+${mover.change.toFixed(2)}%`
: `${mover.change.toFixed(2)}%`;
const emoji = type === 'gain' ? '' : '';
lines.push(
`${emoji} ${mover.symbol.padEnd(8)} ${changeStr.padEnd(10)} ` +
`$${this.formatPrice(mover.price).padEnd(12)} ${this.formatVolume(mover.volume).padEnd(12)}`
);
}
return lines.join('\n');
}
formatVolumeLeaders(leaders) {
if (!leaders || leaders.length === 0) {
return '║ No volume leaders found ║';
}
const lines = [];
for (const leader of leaders.slice(0, 5)) {
lines.push(
`${leader.symbol.padEnd(8)} ${leader.volumeMultiple.padEnd(6)} ` +
`${this.formatChange(leader.change).padEnd(10)} Signal: ${leader.signal.action.padEnd(15)}`
);
}
return lines.join('\n');
}
formatUnusual(unusual) {
if (!unusual || unusual.length === 0) {
return '║ No unusual activity detected ║';
}
const lines = [];
for (const item of unusual.slice(0, 3)) {
const signals = item.signals.join(', ');
lines.push(
` ${item.symbol.padEnd(8)} ${signals.padEnd(45)}`
);
}
return lines.join('\n');
}
formatAlerts(alerts) {
if (!alerts || alerts.length === 0) {
return '║ No alerts at this time ║';
}
const lines = [];
const severityEmoji = {
'INFO': '',
'WARNING': '',
'HIGH': '',
'CRITICAL': ''
};
for (const alert of alerts.slice(0, 3)) {
const emoji = severityEmoji[alert.severity] || '';
lines.push(
`${emoji} ${alert.message.padEnd(55)}`
);
}
return lines.join('\n');
}
formatPrice(price) {
if (price > 10000) return price.toFixed(0);
if (price > 100) return price.toFixed(2);
if (price > 1) return price.toFixed(4);
return price.toFixed(8);
}
formatVolume(volume) {
if (volume > 1e9) return `${(volume / 1e9).toFixed(2)}B`;
if (volume > 1e6) return `${(volume / 1e6).toFixed(2)}M`;
if (volume > 1e3) return `${(volume / 1e3).toFixed(2)}K`;
return volume.toFixed(0);
}
formatChange(change) {
const formatted = change.toFixed(2);
if (change > 0) return `+${formatted}%`;
return `${formatted}%`;
}
}
```
### 3. Real-Time Updates
```javascript
class RealTimeScanner {
constructor() {
this.scanner = new MarketMoversScanner();
this.display = new MoversDisplay();
this.updateInterval = 30000; // 30 seconds
this.isRunning = false;
}
async start(params) {
this.isRunning = true;
console.log('Starting real-time market scanner...');
while (this.isRunning) {
try {
// Scan markets
const results = await this.scanner.scanMarkets(params);
// Clear console and display
console.clear();
console.log(this.display.displayResults(results));
// Check for critical alerts
this.checkCriticalAlerts(results.alerts);
// Wait for next update
await this.sleep(this.updateInterval);
} catch (error) {
console.error('Scanner error:', error);
await this.sleep(5000); // Retry after 5 seconds
}
}
}
checkCriticalAlerts(alerts) {
const critical = alerts.filter(a => a.severity === 'CRITICAL' || a.severity === 'HIGH');
if (critical.length > 0) {
console.log('\n CRITICAL ALERTS:');
for (const alert of critical) {
console.log(`- ${alert.message}`);
}
// Could trigger notifications here
}
}
stop() {
this.isRunning = false;
console.log('Scanner stopped.');
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
```
### 4. Advanced Filtering
```javascript
class ScannerFilters {
applyFilters(asset, filters) {
// Market cap filter
if (filters.minMarketCap && asset.marketCap < filters.minMarketCap) {
return false;
}
if (filters.maxMarketCap && asset.marketCap > filters.maxMarketCap) {
return false;
}
// Volume filter
if (filters.minVolume && asset.volume < filters.minVolume) {
return false;
}
// Price filter
if (filters.minPrice && asset.price < filters.minPrice) {
return false;
}
if (filters.maxPrice && asset.price > filters.maxPrice) {
return false;
}
// Change filter
if (filters.minChange && asset.change < filters.minChange) {
return false;
}
if (filters.maxChange && asset.change > filters.maxChange) {
return false;
}
// Custom filters
if (filters.excludeStablecoins && this.isStablecoin(asset.symbol)) {
return false;
}
if (filters.onlyTop100 && asset.rank > 100) {
return false;
}
return true;
}
isStablecoin(symbol) {
const stablecoins = ['USDT', 'USDC', 'BUSD', 'DAI', 'TUSD', 'USDP', 'USDD'];
return stablecoins.includes(symbol.toUpperCase());
}
createSmartFilters(scanType) {
const filters = {
dayTrading: {
minVolume: 10000000,
minPrice: 0.01,
maxPrice: 100000,
minChange: 2,
excludeStablecoins: true
},
swingTrading: {
minMarketCap: 100000000,
minVolume: 5000000,
minChange: 5,
onlyTop100: true
},
pennyStocks: {
maxPrice: 5,
minVolume: 1000000,
minChange: 10
},
blueChips: {
minMarketCap: 10000000000,
minVolume: 100000000
}
};
return filters[scanType] || {};
}
}
```
## Error Handling
```javascript
try {
const scanner = new RealTimeScanner();
await scanner.start({
markets: 'all',
timeframe: '24h',
categories: ['gainers', 'losers', 'volume', 'unusual'],
limit: 20,
filters: {
minVolume: 1000000,
excludeStablecoins: true
},
sortBy: 'percentage'
});
// Graceful shutdown
process.on('SIGINT', () => {
scanner.stop();
process.exit(0);
});
} catch (error) {
console.error('Failed to start scanner:', error);
process.exit(1);
}
```
This command provides comprehensive market scanning with real-time updates, advanced filtering, and alert detection across multiple asset classes.

85
plugin.lock.json Normal file
View File

@@ -0,0 +1,85 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:jeremylongshore/claude-code-plugins-plus:plugins/crypto/market-movers-scanner",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "814f8034a2dccd664d5aa222ec5d2332a047eceb",
"treeHash": "a5164506e2680193c85244d6fea07667ca7673949ca47d82074344b297662ff9",
"generatedAt": "2025-11-28T10:18:33.223596Z",
"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-movers-scanner",
"description": "Scan for top market movers - gainers, losers, volume spikes, and unusual activity",
"version": "1.0.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "e93a83e44812b0136c8d16d735637b7b1bd62528de7e29bbcab7a66afc7cb6c8"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "bda9b847b7bebba99374bf52f2d578ff52e8f3f4daeef6829fbdfe2a696cee9f"
},
{
"path": "commands/scan-movers.md",
"sha256": "a4961527b08bcd4c2fe0103c0f233bef3ff0fdd79742aa36ce8f67e48cb15e54"
},
{
"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": "25b8ed650dc743ee9fa66a86b867cd2a10c53811d2237c4226080c4b6e98add9"
},
{
"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": "1d488cc92b8d86764ce598c4f70814f840c905310738e50d96b63da942aa298c"
},
{
"path": "skills/skill-adapter/assets/test-data.json",
"sha256": "ac17dca3d6e253a5f39f2a2f1b388e5146043756b05d9ce7ac53a0042eee139d"
},
{
"path": "skills/skill-adapter/assets/README.md",
"sha256": "d3c725146e5bc2372dba3e3cf2c957157ca66821f1a881626ebc608a3783da9e"
},
{
"path": "skills/skill-adapter/assets/skill-schema.json",
"sha256": "f5639ba823a24c9ac4fb21444c0717b7aefde1a4993682897f5bf544f863c2cd"
},
{
"path": "skills/skill-adapter/assets/config-template.json",
"sha256": "0c2ba33d2d3c5ccb266c0848fc43caa68a2aa6a80ff315d4b378352711f83e1c"
}
],
"dirSha256": "a5164506e2680193c85244d6fea07667ca7673949ca47d82074344b297662ff9"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,7 @@
# Assets
Bundled resources for market-movers-scanner skill
- [ ] alert_templates/: Templates for alert notifications, including email, SMS, and push notifications.
- [ ] configuration_examples/: Example configuration files for different use cases and market conditions.
- [ ] sample_data/: Sample market data for testing and demonstration purposes.

View 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": []
}
}

View 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)"
}
}
}

View 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"
}
}

View File

@@ -0,0 +1,8 @@
# References
Bundled resources for market-movers-scanner skill
- [ ] market_data_api.md: Detailed documentation of the market data APIs used by the plugin, including endpoints, parameters, and response formats.
- [ ] alert_configuration.md: Comprehensive guide to configuring alerts, including available options, thresholds, and notification methods.
- [ ] supported_exchanges.md: List of supported cryptocurrency exchanges, stock exchanges, and forex brokers.
- [ ] data_aggregation_methods.md: Explanation of the data aggregation methods used by the plugin to ensure data reliability.

View 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

View 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

View File

@@ -0,0 +1,8 @@
# Scripts
Bundled resources for market-movers-scanner skill
- [ ] alert_manager.py: Manages and triggers alerts based on market movements, allowing users to configure thresholds and notification methods.
- [ ] data_aggregator.py: Aggregates data from multiple sources to ensure data reliability and accuracy.
- [ ] cache_optimizer.py: Optimizes data caching to improve performance and reduce latency.
- [ ] websocket_manager.py: Manages WebSocket connections for real-time data updates.

View 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"

View 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"