ARD: Market Price Tracker
Version: 2.0.0 Author: Jeremy Longshore jeremy@intentsolutions.io Status: In Development Last Updated: 2025-01-14
Document Control
| Field | Value |
|---|---|
| Skill Name | tracking-crypto-prices |
| Architectural Pattern | Read-Process-Write with Caching |
| Complexity Level | Medium (4 steps) |
| API Integrations | 2 (CoinGecko, yfinance) |
| Token Budget | ~2,500 tokens / 5,000 max |
| Status | In Development |
| Owner | Jeremy Longshore |
1. Architectural Overview
1.1 Skill Purpose
One-Sentence Summary: Fetch, cache, and present cryptocurrency price data from multiple sources with standardized output for both human consumption and programmatic use by dependent skills.
Architectural Pattern: Read-Process-Write with Caching
Why This Pattern:
- Read: Fetch price data from external APIs
- Cache: Store recently fetched data to reduce API calls
- Process: Normalize data from different sources into standard format
- Write: Output to terminal (human) or files (programmatic)
This pattern suits the foundation skill nature - it must be fast, reliable, and provide a consistent interface for 10+ dependent skills.
1.2 High-Level Architecture Diagram
┌─────────────────────────────────────────────────────────────────────┐
│ MARKET PRICE TRACKER │
│ Foundation Skill Architecture │
└─────────────────────────────────────────────────────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ USER INPUT │ │ CACHE │ │ DEPENDENT │
│ - Symbol │ │ LAYER │ │ SKILLS │
│ - Watchlist │ │ (30s TTL) │ │ (via import) │
│ - Period │ │ │ │ │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
└──────────────────────────┼──────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Step 1: VALIDATE INPUT │
│ ├─ Parse symbol/name │
│ ├─ Resolve aliases (BTC → bitcoin) │
│ └─ Output: Normalized symbol list │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Step 2: CHECK CACHE │
│ ├─ Load cache from data/cache.json │
│ ├─ Check TTL (30s for spot, 1h for OHLCV) │
│ └─ Output: Cached data OR cache miss │
└─────────────────────────────────────────────┘
│
┌──────────────┴──────────────┐
│ Cache Hit? │
├─────────────────────────────┤
│ YES: Skip to Step 4 │
│ NO: Continue to Step 3 │
└──────────────┬──────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Step 3: FETCH FROM API │
│ ├─ Primary: CoinGecko /simple/price │
│ ├─ Fallback: yfinance (if CoinGecko fails) │
│ ├─ Retry with exponential backoff │
│ └─ Output: Raw price data (JSON) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Step 4: PROCESS & OUTPUT │
│ ├─ Normalize to standard schema │
│ ├─ Update cache │
│ ├─ Format for human (table) or machine │
│ └─ Output: Formatted response OR JSON file │
└─────────────────────────────────────────────┘
1.3 Workflow Summary
Total Steps: 4
| Step | Action | Type | Dependencies | Output |
|---|---|---|---|---|
| 1 | Validate Input | Code | None | Normalized symbols |
| 2 | Check Cache | Code | data/cache.json | Cached data or miss |
| 3 | Fetch from API | API Call | CoinGecko/yfinance | Raw JSON |
| 4 | Process & Output | Code | Step 2 or 3 output | Formatted response |
2. Progressive Disclosure Strategy
2.1 Level 1: Frontmatter (Metadata)
What Goes Here: ONLY name and description
---
name: tracking-crypto-prices
description: |
Track real-time cryptocurrency prices across exchanges with historical data and alerts.
Provides price data infrastructure for dependent skills (portfolio, tax, DeFi, arbitrage).
Use when checking crypto prices, monitoring markets, or fetching historical data.
Trigger with phrases like "check price", "BTC price", "crypto prices", "price history",
"get quote for", "what's ETH trading at", or "show me the top 10 prices".
allowed-tools: Read, Write, Edit, Grep, Glob, Bash(python:*)
version: 2.0.0
author: Jeremy Longshore <jeremy@intentsolutions.io>
license: MIT
---
Description Quality Target: 85%+ Character Count: 445 characters (within 500 limit for extended description)
2.2 Level 2: SKILL.md (Core Instructions)
Token Budget: ~2,500 tokens (target <500 lines)
Required Sections:
- Overview (what + who uses this)
- Prerequisites (pip install)
- Instructions (4 numbered steps with code)
- Output (example formats)
- Configuration (settings.yaml reference)
- Error Handling (common errors + solutions)
- Composability (how to use with other skills)
- Examples (3 concrete use cases)
2.3 Level 3: Resources (Extended Context)
scripts/ Directory:
scripts/
├── price_tracker.py # Main entry point (CLI)
├── api_client.py # CoinGecko/yfinance abstraction
├── cache_manager.py # Cache read/write/invalidation
└── formatters.py # Human-readable output formatting
references/ Directory:
references/
├── errors.md # Common errors and solutions
├── examples.md # Extended use cases
└── implementation.md # Technical deep-dive
config/ Directory:
config/
└── settings.yaml # API keys, cache duration, watchlists
3. Tool Permission Strategy
3.1 Required Tools
Minimal Necessary Set:
Read- Load cache, read config filesWrite- Save cache, export CSV/JSONBash(python:*)- Execute Python scripts
3.2 Tool Usage Justification
| Tool | Why Needed | Usage Pattern |
|---|---|---|
| Read | Load cached prices, read settings | Steps 2, 4 |
| Write | Save cache, export historical data | Steps 3, 4 |
| Bash(python:*) | Execute price fetching scripts | All steps |
3.3 Tools Explicitly NOT Needed
Excluded Tools:
Edit- Scripts generate fresh output, no editing requiredWebFetch- Python scripts handle HTTP directly via requestsGrep- No code search needed for price queriesGlob- No file pattern matching needed
4. Directory Structure & File Organization
4.1 Complete Skill Structure
plugins/crypto/market-price-tracker/skills/tracking-crypto-prices/
├── PRD.md # Product Requirements Document
├── ARD.md # Architecture Requirements Document (this file)
├── SKILL.md # Core instructions (<500 lines)
│
├── scripts/ # Executable code
│ ├── price_tracker.py # Main CLI entry point
│ ├── api_client.py # API abstraction layer
│ ├── cache_manager.py # Caching logic
│ └── formatters.py # Output formatting
│
├── references/ # Documentation
│ ├── errors.md # Error handling guide
│ ├── examples.md # Extended examples
│ └── implementation.md # Technical details
│
├── config/ # Configuration
│ └── settings.yaml # User-configurable settings
│
└── data/ # Runtime data (gitignored)
├── cache.json # Price cache
└── *.csv # Exported historical data
4.2 File Naming Conventions
Scripts: [noun]_[purpose].py
- ✅
price_tracker.py- Main price tracking logic - ✅
api_client.py- API communication - ✅
cache_manager.py- Cache operations
References: [purpose].md (lowercase)
- ✅
errors.md- Error documentation - ✅
examples.md- Usage examples
4.3 Path Referencing Standard
Always Use: {baseDir} for all file paths in SKILL.md
# Correct
python {baseDir}/scripts/price_tracker.py --symbol BTC
# Incorrect
python scripts/price_tracker.py --symbol BTC # Missing {baseDir}
5. API Integration Architecture
5.1 External API Integrations
API 1: CoinGecko (Primary)
Purpose: Real-time price data for 10,000+ cryptocurrencies
Integration Details:
- Base URL:
https://api.coingecko.com/api/v3 - Authentication: Optional API key (header:
x-cg-demo-api-keyorx-cg-pro-api-key) - Rate Limits: 10-30 calls/minute (free), 500/minute (Pro)
- Response Format: JSON
Endpoints Used:
| Endpoint | Purpose | Rate Impact |
|---|---|---|
/simple/price |
Current prices (batch) | 1 call per request |
/coins/{id} |
Detailed coin data | 1 call per coin |
/coins/{id}/market_chart |
Historical OHLCV | 1 call per coin/range |
/coins/markets |
Top coins by market cap | 1 call per page |
Example Request:
import requests
def get_prices(symbols: list, vs_currency: str = "usd") -> dict:
"""Fetch current prices for multiple symbols."""
ids = ",".join(symbols)
url = f"https://api.coingecko.com/api/v3/simple/price"
params = {
"ids": ids,
"vs_currencies": vs_currency,
"include_24hr_change": "true",
"include_24hr_vol": "true",
"include_market_cap": "true"
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
return response.json()
Example Response:
{
"bitcoin": {
"usd": 97234.56,
"usd_24h_change": 2.34,
"usd_24h_vol": 28500000000,
"usd_market_cap": 1920000000000
},
"ethereum": {
"usd": 3456.78,
"usd_24h_change": 1.87,
"usd_24h_vol": 12300000000,
"usd_market_cap": 415200000000
}
}
Error Handling:
| Code | Cause | Solution |
|---|---|---|
| 429 | Rate limit exceeded | Exponential backoff (1s, 2s, 4s, 8s) |
| 404 | Unknown coin ID | Return error with suggestion |
| 500 | Server error | Retry 3x, then fallback to yfinance |
API 2: yfinance (Fallback)
Purpose: Backup price source, primary for historical OHLCV data
Integration Details:
- Library:
yfinancePython package - Authentication: None required
- Rate Limits: Implicit (respectful usage)
- Response Format: pandas DataFrame
Example Usage:
import yfinance as yf
def get_historical(symbol: str, period: str = "30d") -> pd.DataFrame:
"""Fetch historical OHLCV data."""
ticker = yf.Ticker(f"{symbol}-USD")
df = ticker.history(period=period, interval="1d")
df.columns = [c.lower() for c in df.columns]
return df
Symbol Mapping:
- CoinGecko uses full names:
bitcoin,ethereum - yfinance uses tickers:
BTC-USD,ETH-USD - api_client.py handles translation
5.2 API Call Sequencing
User Request
│
▼
Check Cache (local, fast)
│
├── Cache HIT ────────────────────────────────────────┐
│ │
▼ Cache MISS │
│ │
Try CoinGecko API │
│ │
├── Success ──────────────────────────┐ │
│ │ │
▼ Failure (429/500) │ │
│ │ │
Fallback to yfinance │ │
│ │ │
├── Success ─────────────────┐ │ │
│ │ │ │
▼ Failure │ │ │
│ │ │ │
Return Cached (stale) + Warning │ │ │
│ │ │ │
└─────────────────────────────┴────────┴───────────────┘
│
▼
Update Cache
│
▼
Format & Return
Fallback Strategy:
- CoinGecko (primary) → yfinance (fallback) → Cache (stale, last resort)
- Always return something - stale data with warning beats error
6. Data Flow Architecture
6.1 Input → Processing → Output Pipeline
INPUT (User Request: "BTC price")
│
▼
Step 1: Parse & Validate
│ Input: "BTC" (string)
│ Processing: Resolve to CoinGecko ID "bitcoin"
│ Output: {"id": "bitcoin", "symbol": "BTC", "name": "Bitcoin"}
│
▼
Step 2: Check Cache
│ Input: Cache key "bitcoin_usd_spot"
│ Processing: Load data/cache.json, check TTL
│ Output: Cached price data OR cache miss flag
│
▼
Step 3: Fetch (if cache miss)
│ Input: Symbol ID "bitcoin"
│ API Call: CoinGecko /simple/price
│ Processing: Parse JSON, handle errors
│ Output: {"price": 97234.56, "change_24h": 2.34, ...}
│
▼
Step 4: Format & Return
│ Input: Price data dict
│ Processing: Update cache, format output
│ Output: Human-readable table OR JSON file
│
▼
FINAL OUTPUT
6.2 Data Format Specifications
Format 1: Cache Entry (data/cache.json)
{
"bitcoin_usd_spot": {
"symbol": "BTC",
"name": "Bitcoin",
"price": 97234.56,
"change_24h": 2.34,
"volume_24h": 28500000000,
"market_cap": 1920000000000,
"currency": "usd",
"fetched_at": "2025-01-14T15:30:00Z",
"ttl_seconds": 30
}
}
Format 2: Standardized Price Output (returned to dependent skills)
{
"symbol": "BTC",
"name": "Bitcoin",
"price": 97234.56,
"currency": "USD",
"change_24h_percent": 2.34,
"volume_24h": 28500000000,
"market_cap": 1920000000000,
"timestamp": "2025-01-14T15:30:00Z",
"source": "coingecko",
"cached": false
}
Format 3: Historical OHLCV (data/BTC_30d.csv)
date,open,high,low,close,volume
2024-12-15,95000.00,96500.00,94200.00,96100.00,25000000000
2024-12-16,96100.00,97800.00,95800.00,97500.00,27000000000
...
6.3 Data Validation Rules
Validation Checkpoints:
Input Validation (Step 1):
- ✅ Symbol is string, 1-10 characters
- ✅ Symbol resolves to known cryptocurrency
- ✅ Currency is supported (USD, EUR, GBP, etc.)
Cache Validation (Step 2):
- ✅ Cache file exists and is valid JSON
- ✅ Entry TTL not exceeded
- ✅ Required fields present
API Response Validation (Step 3):
- ✅ HTTP 200 status
- ✅ JSON parseable
- ✅ Price is positive number
- ✅ Required fields present
7. Error Handling Strategy
7.1 Error Categories & Responses
Category 1: Input Errors
| Error | Cause | Detection | Solution |
|---|---|---|---|
| Unknown symbol | User typed invalid ticker | Symbol lookup fails | Suggest similar symbols |
| Invalid currency | Unsupported fiat currency | Currency not in list | Show supported currencies |
| Empty input | No symbols provided | Input validation | Show usage example |
Category 2: API Errors
| Error | Cause | Detection | Solution |
|---|---|---|---|
| Rate limited (429) | Too many requests | HTTP status | Exponential backoff + retry |
| Server error (500) | CoinGecko down | HTTP status | Fallback to yfinance |
| Timeout | Slow network | Exception | Retry with longer timeout |
| Auth failed (401) | Invalid API key | HTTP status | Check config, use free tier |
Category 3: Cache Errors
| Error | Cause | Detection | Solution |
|---|---|---|---|
| Cache corrupted | Invalid JSON | Parse exception | Delete cache, refetch |
| Cache missing | First run or deleted | File not found | Create empty cache |
| Cache stale | TTL exceeded | Timestamp check | Refetch from API |
7.2 Graceful Degradation
Primary Path:
CoinGecko API → Cache → Format → User
↓ (if API fails)
Fallback Path 1:
yfinance → Cache → Format → User
↓ (if yfinance fails)
Fallback Path 2:
Stale Cache → Format → User (with warning)
↓ (if no cache)
Error Path:
Clear error message + suggested action
7.3 Logging Format
[YYYY-MM-DD HH:MM:SS] [LEVEL] [Component] Message
[2025-01-14 15:30:00] [INFO] [API] Fetching BTC price from CoinGecko
[2025-01-14 15:30:01] [INFO] [API] ✓ Got price: $97,234.56
[2025-01-14 15:30:01] [INFO] [Cache] Updated bitcoin_usd_spot (TTL: 30s)
[2025-01-14 15:30:45] [WARN] [API] Rate limited (429), backing off 2s
[2025-01-14 15:30:47] [INFO] [API] Retry successful
8. Composability & Stacking Architecture
8.1 Standalone Execution
This skill can run independently for direct user queries:
# Single price
python {baseDir}/scripts/price_tracker.py --symbol BTC
# Multiple prices
python {baseDir}/scripts/price_tracker.py --symbols BTC,ETH,SOL
# Historical data
python {baseDir}/scripts/price_tracker.py --symbol BTC --period 30d --output csv
8.2 Skill Stacking Patterns
Pattern 1: Direct Import (Preferred for Python skills)
Other skills import price_tracker functions directly:
# In crypto-portfolio-tracker/scripts/portfolio.py
import sys
sys.path.insert(0, "{baseDir}/../market-price-tracker/skills/tracking-crypto-prices/scripts")
from price_tracker import get_current_prices
def calculate_portfolio_value(holdings: dict) -> float:
"""Value portfolio using price tracker."""
prices = get_current_prices(list(holdings.keys()))
total = sum(holdings[sym] * prices[sym]["price"] for sym in holdings)
return total
Pattern 2: CLI Subprocess (Cross-language or isolation)
# In another skill's script
PRICES=$(python {baseDir}/../market-price-tracker/scripts/price_tracker.py \
--symbols BTC,ETH \
--format json)
Pattern 3: Shared Cache (Efficient for batch operations)
Multiple skills read from the same cache file:
- price-tracker updates
data/cache.json - portfolio-tracker reads from same cache
- Reduces redundant API calls
8.3 Skills That Depend on This
| Skill | Integration Pattern | Data Needed |
|---|---|---|
| market-movers-scanner | Direct import | Batch prices + 24h change |
| crypto-portfolio-tracker | Direct import | Current prices for holdings |
| crypto-tax-calculator | Direct import | Historical prices for cost basis |
| defi-yield-optimizer | CLI subprocess | USD prices for APY calculation |
| liquidity-pool-analyzer | Direct import | Token prices for LP valuation |
| staking-rewards-optimizer | CLI subprocess | Token prices for rewards calc |
| crypto-derivatives-tracker | Direct import | Underlying asset prices |
| dex-aggregator-router | Direct import | CEX prices for comparison |
| options-flow-analyzer | Direct import | Underlying prices |
| arbitrage-opportunity-finder | Direct import | Multi-exchange prices |
8.4 Input/Output Contracts
Input Contract (what this skill expects):
# Function signature for get_current_prices()
def get_current_prices(
symbols: list[str], # Required: ["BTC", "ETH"]
currency: str = "usd", # Optional: Default USD
use_cache: bool = True, # Optional: Default True
cache_ttl: int = 30 # Optional: Seconds
) -> dict[str, PriceData]:
...
Output Contract (what this skill guarantees):
@dataclass
class PriceData:
symbol: str # "BTC"
name: str # "Bitcoin"
price: float # 97234.56
currency: str # "USD"
change_24h: float # 2.34 (percent)
volume_24h: float # 28500000000
market_cap: float # 1920000000000
timestamp: str # ISO 8601
source: str # "coingecko" or "yfinance"
cached: bool # True if from cache
9. Performance & Scalability
9.1 Performance Targets
| Metric | Target | Max Acceptable | Notes |
|---|---|---|---|
| Single price (cached) | < 100ms | < 500ms | Local file read only |
| Single price (API) | < 2s | < 5s | Network dependent |
| Batch 10 prices (API) | < 3s | < 8s | Single API call |
| Batch 50 prices (API) | < 5s | < 15s | May require pagination |
| Historical 30d OHLCV | < 3s | < 10s | yfinance call |
9.2 Scalability Considerations
Cache Strategy:
- Spot prices: 30s TTL (balance freshness vs rate limits)
- Historical data: 1h TTL (rarely changes)
- Cache file: Single JSON file (sufficient for <1000 entries)
Batch Optimization:
- CoinGecko supports 100+ coins per request
- Always batch multiple symbol requests
- Single API call vs N calls = 100x reduction
9.3 Resource Usage
Disk: ~1MB for cache + historical exports Memory: ~50MB during execution Network: ~10KB per API request
10. Testing Strategy
10.1 Unit Tests
Test Input Validation:
def test_symbol_resolution():
assert resolve_symbol("BTC") == "bitcoin"
assert resolve_symbol("btc") == "bitcoin"
assert resolve_symbol("Bitcoin") == "bitcoin"
assert resolve_symbol("INVALID") is None
Test Cache:
def test_cache_hit():
cache.set("bitcoin", price_data, ttl=30)
result = cache.get("bitcoin")
assert result is not None
assert result["cached"] is True
def test_cache_miss():
cache.clear()
result = cache.get("bitcoin")
assert result is None
10.2 Integration Tests
# Test full workflow
python {baseDir}/scripts/price_tracker.py --symbol BTC --test
# Expected: Fetches real data, validates response format
10.3 Acceptance Criteria
- Single price returns in < 3s
- Batch 10 prices returns in < 5s
- Cache reduces repeat queries to < 100ms
- Fallback to yfinance works when CoinGecko fails
- Historical data exports valid CSV
- All error cases return helpful messages
11. Security & Compliance
11.1 API Key Management
Storage: Environment variables or config/settings.yaml
# config/settings.yaml
api:
coingecko:
api_key: ${COINGECKO_API_KEY} # From environment
use_pro: false
Never:
- Hardcode API keys in scripts
- Commit API keys to git
- Log API keys
11.2 Data Privacy
User Data: No PII collected Market Data: Public information, no privacy concerns Cache: Local only, user can delete anytime
11.3 Rate Limit Compliance
- Respect CoinGecko rate limits (10-50/min free tier)
- Implement exponential backoff
- Use caching aggressively
12. Version History
| Version | Date | Changes | Author |
|---|---|---|---|
| 1.0.0 | 2025-01-01 | Initial stub | Jeremy Longshore |
| 2.0.0 | 2025-01-14 | Full ARD per nixtla standard | Jeremy Longshore |
13. Approval
| Role | Name | Approval Date |
|---|---|---|
| Architect | Claude (Opus 4.5) | 2025-01-14 |
| Owner | Jeremy Longshore | 2025-01-14 |
Document maintained by: Intent Solutions Standard: Nixtla Enterprise Skill ARD Template v1.0