| Field | Value | |-------|-------| | **Skill Name** | analyzing-market-sentiment | | **Architecture Pattern** | Multi-Source Aggregation + Scoring | | **Version** | 2.0.0 | | **Author** | Jeremy Longshore <jeremy@intentsolutions.io> |
Scanned 5/31/2026
Install via CLI
openskills install tools-only/X-Skills# ARD: Analyzing Market Sentiment
## Document Control
| Field | Value |
|-------|-------|
| **Skill Name** | analyzing-market-sentiment |
| **Architecture Pattern** | Multi-Source Aggregation + Scoring |
| **Version** | 2.0.0 |
| **Author** | Jeremy Longshore <jeremy@intentsolutions.io> |
---
## Architectural Overview
### Pattern: Composite Scoring Pipeline
This skill implements a multi-source data aggregation pattern with weighted composite scoring.
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ MARKET SENTIMENT ANALYZER ARCHITECTURE │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Fear & Greed │ │ News Articles │ │ Market Data │
│ Index │ │ (RSS/Aggregator)│ │ (CoinGecko) │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ F&G FETCHER │ │ NEWS FETCHER │ │ MARKET FETCHER │
│ - API call │ │ - RSS parsing │ │ - Price data │
│ - Caching │ │ - Deduplication │ │ - Volume data │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ NEWS SCORER │ │
│ │ - Keyword match │ │
│ │ - Sentiment │ │
│ │ - Aggregation │ │
│ └────────┬─────────┘ │
│ │ │
└────────────────────────┼────────────────────────┘
│
▼
┌─────────────────────────┐
│ COMPOSITE CALCULATOR │
│ - Weight application │
│ - Score normalization │
│ - Classification │
└────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ FORMATTER │
│ - Dashboard view │
│ - JSON export │
│ - CSV export │
└─────────────────────────┘
```
### Workflow
1. **Fetch**: Parallel data retrieval from multiple sources
2. **Score**: Analyze news sentiment using keyword matching
3. **Calculate**: Compute weighted composite score
4. **Classify**: Map score to sentiment classification
5. **Format**: Output in requested format
---
## Progressive Disclosure Strategy
### Level 1: Quick Sentiment Check (Default)
```bash
python sentiment_analyzer.py
```
Returns overall sentiment score and classification.
### Level 2: Coin-Specific Analysis
```bash
python sentiment_analyzer.py --coin BTC
```
Adds coin-specific sentiment breakdown.
### Level 3: Detailed Analysis
```bash
python sentiment_analyzer.py --detailed --period 24h
```
Full breakdown with news article scores.
### Level 4: Export with Custom Weights
```bash
python sentiment_analyzer.py --format json --weights "news:0.5,fng:0.3,momentum:0.2"
```
Custom weighting and JSON export.
---
## Tool Permission Strategy
### Allowed Tools (Scoped)
```yaml
allowed-tools: Read, Bash(crypto:sentiment-*)
```
| Tool | Scope | Purpose |
|------|-------|---------|
| Read | Unrestricted | Read config, cached data |
| Bash | `crypto:sentiment-*` | Execute sentiment analysis scripts |
### Why These Tools
- **Read**: Load configuration and cached sentiment data
- **Bash(crypto:sentiment-*)**: Execute Python scripts for analysis
- **No Write**: Analysis is read-only; exports use script file output
---
## Directory Structure
```
plugins/crypto/market-sentiment-analyzer/
└── skills/
└── analyzing-market-sentiment/
├── PRD.md # Product requirements
├── ARD.md # This file
├── SKILL.md # Core instructions
├── scripts/
│ ├── sentiment_analyzer.py # Main CLI entry point
│ ├── fear_greed.py # Fear & Greed Index fetcher
│ ├── news_sentiment.py # News sentiment scoring
│ ├── market_momentum.py # Market momentum calculation
│ └── formatters.py # Output formatting
├── references/
│ ├── errors.md # Error handling guide
│ └── examples.md # Usage examples
└── config/
└── settings.yaml # Configuration options
```
---
## Data Flow Architecture
### Input
- User request with optional filters (--coin, --period, --detailed)
- External API data (Fear & Greed, news, market)
### Processing Pipeline
```
Input Request
│
├──► Fetch Fear & Greed Index
│ │
│ ▼
│ Score: 0-100, Classification
│
├──► Fetch News (RSS or aggregator)
│ │
│ ▼
│ Score each article (-1 to +1)
│ │
│ ▼
│ Aggregate: weighted average
│ │
│ ▼
│ Normalize to 0-100
│
├──► Fetch Market Data
│ │
│ ▼
│ Calculate momentum (price change, volume)
│ │
│ ▼
│ Normalize to 0-100
│
└──► Calculate Composite Score
│
▼
Weighted Sum:
- News: 40%
- Fear & Greed: 40%
- Momentum: 20%
│
▼
Classify:
- 0-20: Extreme Fear
- 21-40: Fear
- 41-60: Neutral
- 61-80: Greed
- 81-100: Extreme Greed
```
### Output Schema
```json
{
"composite_score": 65.5,
"classification": "Greed",
"components": {
"fear_greed": {
"score": 72,
"classification": "Greed",
"weight": 0.40,
"contribution": 28.8
},
"news_sentiment": {
"score": 58.5,
"articles_analyzed": 25,
"positive": 12,
"negative": 5,
"neutral": 8,
"weight": 0.40,
"contribution": 23.4
},
"market_momentum": {
"score": 66.5,
"btc_change_24h": 3.5,
"volume_ratio": 1.2,
"weight": 0.20,
"contribution": 13.3
}
},
"meta": {
"timestamp": "2026-01-14T15:30:00Z",
"period": "24h",
"coin_filter": null,
"data_freshness": {
"fear_greed": "5 min",
"news": "2 min",
"market": "1 min"
}
}
}
```
---
## Sentiment Scoring Algorithm
### News Sentiment Scoring
```python
# Per-article scoring
def score_article(title: str, summary: str) -> float:
"""Score article from -1 (bearish) to +1 (bullish)."""
text = f"{title} {summary}".lower()
score = 0.0
# Positive keywords
positive = ["bullish", "surge", "rally", "breakout", "adoption",
"partnership", "approval", "milestone", "record"]
for kw in positive:
if kw in text:
score += 0.2
# Negative keywords
negative = ["bearish", "crash", "dump", "hack", "exploit",
"ban", "lawsuit", "fraud", "bankruptcy"]
for kw in negative:
if kw in text:
score -= 0.2
return max(-1, min(1, score))
# Aggregate scoring
def aggregate_news_sentiment(articles: List[dict]) -> float:
"""Aggregate article scores to 0-100 scale."""
if not articles:
return 50 # Neutral
# Weight by recency
weighted_sum = 0
weight_total = 0
for article in articles:
age_hours = article.get("age_hours", 24)
weight = 1 / (1 + age_hours / 12) # Decay over 12 hours
weighted_sum += article["score"] * weight
weight_total += weight
avg_score = weighted_sum / weight_total # -1 to +1
return (avg_score + 1) * 50 # Convert to 0-100
```
### Composite Score Calculation
```python
def calculate_composite(
fear_greed: float, # 0-100
news_sentiment: float, # 0-100
momentum: float, # 0-100
weights: dict = None
) -> float:
"""Calculate weighted composite sentiment score."""
weights = weights or {
"fear_greed": 0.40,
"news": 0.40,
"momentum": 0.20
}
return (
fear_greed * weights["fear_greed"] +
news_sentiment * weights["news"] +
momentum * weights["momentum"]
)
```
---
## Error Handling Strategy
### Error Categories
| Category | Examples | Strategy |
|----------|----------|----------|
| API Error | Fear & Greed API down | Use cached value with stale warning |
| Network | Timeout, DNS failure | Skip component, partial analysis |
| Parse | Invalid JSON response | Log warning, use default |
| Data | No news found | Reduce weight, increase other components |
### Graceful Degradation
```
Full Analysis (all components)
│
▼
Partial Analysis (some components failed)
│ → Recalculate weights for available data
│ → Warn user about missing components
│
▼
Cached Fallback (API failures)
│ → Use recent cached values
│ → Show "stale data" warning
│
▼
Minimal Analysis (only Fear & Greed)
│ → Single source analysis
│ → Clear limitations disclosure
```
---
## Composability & Stacking
### Optional Dependencies
- **crypto-news-aggregator**: Enhanced news analysis
- If available: Uses aggregator's scored news
- If unavailable: Falls back to direct RSS fetch
### As Data Provider
Skills that can consume sentiment data:
- **crypto-signal-generator**: Sentiment as signal input
- **trading-strategy-backtester**: Historical sentiment data
### Integration Pattern
```python
# Check for news aggregator
NEWS_AGGREGATOR = None
try:
from pathlib import Path
aggregator_path = Path(__file__).parent.parent.parent.parent / \
"crypto-news-aggregator/skills/aggregating-crypto-news/scripts"
if (aggregator_path / "news_aggregator.py").exists():
NEWS_AGGREGATOR = aggregator_path
except Exception:
pass
def get_news_for_sentiment(coin: str = None, period: str = "24h"):
"""Fetch news using aggregator if available, else direct RSS."""
if NEWS_AGGREGATOR:
# Use aggregator
return fetch_via_aggregator(coin, period)
else:
# Direct RSS fallback
return fetch_direct_rss(coin, period)
```
---
## Performance & Scalability
### Performance Targets
| Metric | Target | Approach |
|--------|--------|----------|
| Full analysis | < 15s | Parallel API calls |
| Quick check | < 5s | Cached Fear & Greed only |
| News scoring | < 2s per 100 articles | Efficient keyword matching |
### Optimization Strategies
1. **Parallel Fetching**: Concurrent API calls with asyncio/threading
2. **Caching**: Cache Fear & Greed (5 min TTL), news (2 min TTL)
3. **Lazy Loading**: Only fetch detailed data if --detailed flag
4. **Early Exit**: Return cached data for repeated calls
---
## Testing Strategy
### Unit Tests
| Component | Test Cases |
|-----------|------------|
| FearGreedFetcher | API response parsing, caching, classification |
| NewsSentiment | Keyword matching, aggregation, normalization |
| CompositeCalculator | Weight application, edge cases |
| Formatters | All output formats, empty data handling |
### Integration Tests
- End-to-end with mock APIs
- Real API tests (daily CI)
- Export format validation
### Manual Testing
```bash
# Quick check
python sentiment_analyzer.py
# Coin-specific
python sentiment_analyzer.py --coin BTC
# Detailed with export
python sentiment_analyzer.py --detailed --format json --output sentiment.json
```
---
## Security & Compliance
### Security Considerations
- **No Authentication**: All APIs used are public
- **No User Data**: No personal information collected
- **Output Only**: Read-only analysis, no state modification
### Rate Limiting
- Alternative.me: Respect 10 req/min limit
- CoinGecko: Respect free tier limits
- Caching reduces API calls significantly
No comments yet. Be the first to comment!