
Tracking Crypto Derivatives
- 83 installs
- 2.6k repo stars
- Updated August 5, 2026
- jeremylongshore/claude-code-plugins-plus-skills
Tracks crypto futures, options and perpetual swaps with funding rates, open interest and liquidation data.
About
Aggregates funding rates, open interest, liquidations and options data across CEX and DEX derivatives exchanges. A trader uses it when analyzing derivatives markets or finding liquidation levels.
- Aggregates funding rate, open interest and liquidation data
- Covers CEX and DEX derivatives plus options flow
Tracking Crypto Derivatives by the numbers
- 83 all-time installs (skills.sh)
- Ranked #543 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill tracking-crypto-derivativesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 83 |
|---|---|
| repo stars | ★ 2.6k |
| Last updated | August 5, 2026 |
| Repository | jeremylongshore/claude-code-plugins-plus-skills ↗ |
What it does
Tracks crypto futures, options and perpetual swaps with funding rates, open interest and liquidation data.
Files
Tracking Crypto Derivatives
Overview
Aggregate funding rates, open interest, liquidations, and options data across CEX and DEX derivatives exchanges to produce actionable trading insights.
Supported Markets: Perpetual Swaps (Binance, Bybit, OKX, Deribit, BitMEX), Quarterly Futures, Options (Deribit, OKX, Bybit), DEX Perpetuals (dYdX, GMX, Drift Protocol).
Prerequisites
- Python 3.8+ installed
- Network access to exchange APIs
- Optional: API keys for higher rate limits
- Understanding of derivatives concepts (funding, OI, basis)
Instructions
1. Check funding rates across exchanges to identify sentiment and arbitrage opportunities:
python derivatives_tracker.py funding BTC
python derivatives_tracker.py funding BTC ETH SOL
python derivatives_tracker.py funding BTC --history 7d- Positive funding (>0.01%): Longs pay shorts, bullish sentiment
- Negative funding (<-0.01%): Shorts pay longs, bearish sentiment
- Extreme funding (>0.1%): Potential contrarian opportunity
2. Analyze open interest to gauge market positioning and trend strength:
python derivatives_tracker.py oi BTC
python derivatives_tracker.py oi BTC --changes
python derivatives_tracker.py oi BTC --divergence- Rising OI + Rising Price = strong bullish trend
- Rising OI + Falling Price = strong bearish trend
- Falling OI + Rising Price = short covering rally
- Falling OI + Falling Price = long liquidations
3. Monitor liquidations to find support/resistance clusters:
python derivatives_tracker.py liquidations BTC
python derivatives_tracker.py liquidations BTC --recent
python derivatives_tracker.py liquidations BTC --min-size 100000 # 100000 = minimum USD liquidation size filter4. Analyze options market for IV, put/call ratio, and max pain:
python derivatives_tracker.py options BTC
python derivatives_tracker.py options BTC --pcr
python derivatives_tracker.py options BTC --expiry 2025-01-31 # 2025 = target expiry year5. Calculate basis for spot-futures arbitrage opportunities:
python derivatives_tracker.py basis BTC
python derivatives_tracker.py basis BTC --quarterly
python derivatives_tracker.py basis --all6. Run full dashboard for comprehensive derivatives overview:
python derivatives_tracker.py dashboard BTC
python derivatives_tracker.py dashboard BTC ETH SOL
python derivatives_tracker.py dashboard BTC --output jsonOutput
The skill produces structured reports per market type:
- Funding Rate Report: Current, 24h avg, 7d avg rates per exchange with annualized yield and sentiment
- Open Interest Report: OI per exchange with 24h/7d changes, share %, and long/short ratio
- Liquidation Heatmap: Long/short liquidation clusters by price level with USD density
- Options Overview: Put/call ratio, IV rank, max pain, and large flow alerts
- Basis Report: Spot-perp and quarterly basis with annualized carry rates
See ${CLAUDE_SKILL_DIR}/references/implementation.md for detailed output format examples.
Error Handling
| Error | Cause | Fix |
|---|---|---|
ERR_RATE_LIMIT | Too many API requests | Reduce frequency or add API key |
ERR_EXCHANGE_DOWN | Exchange API unavailable | Try alternative exchange |
ERR_SYMBOL_INVALID | Wrong symbol format | Use BTC, ETH (not BTCUSDT) |
Examples
Morning derivatives check - Scan funding, OI, and liquidations for top assets:
python derivatives_tracker.py dashboard BTC ETH SOLFunding rate arbitrage - Alert when funding exceeds threshold for cash-and-carry:
python derivatives_tracker.py funding BTC --alert-threshold 0.08Pre-expiry options analysis - Check max pain and IV before Friday expiry:
python derivatives_tracker.py options BTC --expiry fridayBasis trading scan - Find all pairs with annualized yield above 5%:
python derivatives_tracker.py basis --all --min-yield 5 # 5 = minimum annualized yield %Resources
- Coinglass: Aggregated derivatives data
- Exchange APIs: Binance, Bybit, OKX, Deribit
- The Graph: DEX perpetuals data
${CLAUDE_SKILL_DIR}/references/implementation.md- Detailed output formats, options/basis guides, key concepts
ARD: Crypto Derivatives Tracker
Part of Tons of Skills by Intent Solutions | jeremylongshore.com
Architecture Pattern
Multi-Exchange Aggregation with Real-Time Processing
This skill aggregates derivatives data from multiple exchanges, normalizes formats, and provides unified analysis across funding rates, open interest, liquidations, and options markets.
---
Architectural Overview
┌─────────────────────────────────────────────────────────────────────┐
│ derivatives_tracker.py (CLI) │
│ funding | oi | liquidations | options | basis commands │
└─────────────────────────────────────────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ FundingTracker │ │ OIAnalyzer │ │LiquidationMonitor│
│ Multi-exchange │ │ Position data │ │ Heatmap & alerts │
│ rate aggregation│ │ trend analysis │ │ cascade risk │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└────────────────────────┼────────────────────────┘
▼
┌─────────────────────────┐
│ ExchangeClient │
│ Unified API interface │
│ Rate limit handling │
└─────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Binance │ │ Bybit │ │ Deribit │
│ API │ │ API │ │ API │
└─────────┘ └─────────┘ └─────────┘---
Workflow
Step 1: Exchange Client Initialization
Configure API connections for each supported exchange with rate limiting.
Step 2: Data Fetching
Parallel fetch from all exchanges for:
- Funding rates (perpetuals)
- Open interest (futures + perps)
- Recent liquidations
- Options data (Deribit primarily)
Step 3: Data Normalization
Standardize formats across exchanges:
- Convert funding to 8-hour basis
- Normalize OI to USD equivalent
- Unify liquidation formats
Step 4: Analysis & Aggregation
- Calculate weighted averages
- Detect divergences
- Generate signals
Step 5: Output
Present in requested format (console/JSON).
---
Data Flow
Exchange APIs Normalization Analysis Output
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────┐
│ Binance │─────────│ Funding │─────────│ Rate │─────────│Console│
│ funding │ │ Normalize │ │ Comparison│ │ JSON │
└───────────┘ └───────────┘ └───────────┘ └───────┘
│ │ │
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Bybit │─────────│ OI │─────────│ Trend │
│ OI data │ │ Normalize │ │ Analysis │
└───────────┘ └───────────┘ └───────────┘
│ │ │
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Deribit │─────────│ Options │─────────│ Flow │
│ options │ │ Normalize │ │ Analysis │
└───────────┘ └───────────┘ └───────────┘---
Progressive Disclosure Strategy
Level 1: Quick Summary
Single-line current funding rate or OI.
BTC Funding: +0.015% (Binance) | OI: $18.5B (+2.3% 24h)Level 2: Standard Report
Tabular view across exchanges with key metrics.
BTC FUNDING RATES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Exchange Current 24h Avg Annualized
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Binance +0.0150% +0.0120% +16.43%
Bybit +0.0180% +0.0140% +19.71%
...Level 3: Deep Analysis
Full derivatives dashboard with all metrics, signals, and risk assessment.
---
Tool Permission Strategy
allowed-tools: Read, Write, Edit, Grep, Glob, Bash(crypto:derivatives-*)Tool Justification
| Tool | Usage |
|---|---|
| Read | Load config, API credentials |
| Write | Save reports, cache data |
| Edit | Update configuration |
| Grep | Search historical data |
| Glob | Find data files |
| Bash(crypto:derivatives-*) | Execute data fetching scripts |
---
Directory Structure
skills/tracking-crypto-derivatives/
├── SKILL.md # Core skill instructions
├── PRD.md # Product requirements
├── ARD.md # This file
├── scripts/
│ ├── derivatives_tracker.py # Main CLI entry point
│ ├── exchange_client.py # Unified exchange interface
│ ├── funding_tracker.py # Funding rate analysis
│ ├── oi_analyzer.py # Open interest analysis
│ ├── liquidation_monitor.py # Liquidation tracking
│ ├── options_analyzer.py # Options market analysis
│ ├── basis_calculator.py # Basis/arbitrage calculations
│ └── formatters.py # Output formatting
├── config/
│ └── settings.yaml # Exchange configs, thresholds
└── references/
├── errors.md # Error handling guide
├── examples.md # Usage examples
└── implementation.md # Implementation details---
API Integration Architecture
Exchange Client Interface
class ExchangeClient:
"""Unified interface for all exchanges."""
def get_funding_rate(self, symbol: str) -> FundingRate
def get_open_interest(self, symbol: str) -> OpenInterest
def get_liquidations(self, symbol: str, limit: int) -> List[Liquidation]
def get_options_data(self, symbol: str) -> OptionsDataSupported Exchanges
| Exchange | Funding | OI | Liquidations | Options |
|---|---|---|---|---|
| Binance | ✓ | ✓ | ✓ | ✗ |
| Bybit | ✓ | ✓ | ✓ | ✓ |
| OKX | ✓ | ✓ | ✓ | ✓ |
| Deribit | ✓ | ✓ | ✗ | ✓ (primary) |
| BitMEX | ✓ | ✓ | ✓ | ✗ |
Rate Limiting Strategy
RATE_LIMITS = {
"binance": {"requests_per_minute": 1200, "weight_per_request": 1},
"bybit": {"requests_per_minute": 120, "weight_per_request": 1},
"okx": {"requests_per_minute": 60, "weight_per_request": 1},
"deribit": {"requests_per_day": 10000, "weight_per_request": 1},
}---
Data Models
FundingRate
@dataclass
class FundingRate:
exchange: str
symbol: str
rate: Decimal # Current 8-hour rate
predicted_rate: Decimal # Next predicted rate
next_payment: datetime # Time until next payment
annualized: float # Annualized yieldOpenInterest
@dataclass
class OpenInterest:
exchange: str
symbol: str
oi_usd: Decimal # Total OI in USD
oi_contracts: Decimal # Total contracts
change_24h_pct: float # 24h change
change_7d_pct: float # 7d change
long_ratio: float # Long/short ratioLiquidation
@dataclass
class Liquidation:
exchange: str
symbol: str
side: str # "long" or "short"
price: Decimal
quantity: Decimal
value_usd: Decimal
timestamp: datetimeOptionsSnapshot
@dataclass
class OptionsSnapshot:
symbol: str
expiry: date
atm_iv: float # At-the-money IV
put_call_ratio: float # By volume
put_call_oi: float # By open interest
max_pain: Decimal # Max pain price
total_oi_usd: Decimal---
Error Handling Strategy
Exchange Errors
| Error Type | Handling |
|---|---|
| API Rate Limit | Exponential backoff, queue requests |
| API Timeout | Retry with fallback exchange |
| Invalid Symbol | Skip exchange, continue others |
| Auth Failed | Log warning, use public endpoints |
Data Quality
| Issue | Handling |
|---|---|
| Stale Data | Flag staleness, show warning |
| Missing Exchange | Exclude from aggregation |
| Inconsistent Units | Normalize to standard format |
---
Composability & Stacking
Works With
| Skill | Integration |
|---|---|
| market-price-tracker | Spot price for basis calculations |
| arbitrage-finder | Cross-exchange funding arbitrage |
| options-flow-analyzer | Deep options analysis |
| whale-alert-monitor | Large liquidation correlation |
Output Formats
- Console: Formatted tables and reports
- JSON: Machine-readable for pipelines
- CSV: Export for spreadsheet analysis
---
Performance & Scalability
Caching Strategy
CACHE_TTL = {
"funding_rates": 60, # 1 minute
"open_interest": 30, # 30 seconds
"liquidations": 10, # 10 seconds
"options_data": 300, # 5 minutes
}Parallel Fetching
async def fetch_all_funding(symbols: List[str]) -> Dict[str, FundingRate]:
"""Fetch funding from all exchanges in parallel."""
tasks = [
fetch_funding(exchange, symbol)
for exchange in EXCHANGES
for symbol in symbols
]
return await asyncio.gather(*tasks)---
Testing Strategy
Unit Tests
- Funding rate calculations
- OI normalization
- Liquidation aggregation
- Basis calculations
Integration Tests
- Exchange API connectivity
- Rate limit handling
- Error recovery
Mock Data
- Simulated exchange responses
- Historical liquidation data
- Options chain snapshots
---
Security & Compliance
API Key Handling
- Keys stored in environment variables or config
- Read-only permissions only (no trading)
- No key logging in outputs
Data Privacy
- No personal data collected
- No trading history stored
- Analysis only, no execution
---
Monitoring & Alerts
Alert Thresholds (Configurable)
alerts:
funding_extreme: 0.1 # 0.1% 8-hour funding
oi_change_large: 15 # 15% OI change
liquidation_large: 1000000 # $1M liquidation
iv_extreme: 100 # 100% IVAlert Outputs
- Console warnings with emoji indicators
- JSON alerts for webhook integration
- Summary at end of report
# Crypto Derivatives Tracker Configuration
# ==========================================
# General settings
general:
# Default output format: console or json
default_format: console
# Default symbols to track
default_symbols:
- BTC
- ETH
# Cache TTL in seconds
cache_ttl: 300
# Request timeout in seconds
request_timeout: 30
# Exchange configuration
exchanges:
# Enabled exchanges for data collection
enabled:
- binance
- bybit
- okx
- deribit
- bitmex
# Primary exchange for each data type
primary:
funding: binance
open_interest: binance
liquidations: binance
options: deribit
basis: binance
# Rate limits (requests per minute)
rate_limits:
binance: 1200
bybit: 120
okx: 60
deribit: 100
bitmex: 30
# Funding rate settings
funding:
# Interpretation thresholds (8-hour rate as percentage)
thresholds:
extreme: 0.08 # Above this is extreme
strong: 0.03 # Above this is strong
neutral: 0.005 # Below this is neutral
# Minimum spread for arbitrage alerts (percentage)
min_arb_spread: 0.02
# Alert on extreme funding
alert_extreme: true
# Open interest settings
open_interest:
# Trend detection thresholds (24h change percentage)
thresholds:
strong_change: 10.0 # >10% is strong move
moderate_change: 5.0 # >5% is moderate
# Divergence detection minimum change
divergence_min_change: 2.0
# Liquidation settings
liquidations:
# Cascade risk thresholds (USD within 5% of price)
cascade_thresholds:
critical: 500000000 # $500M
high: 200000000 # $200M
medium: 100000000 # $100M
# Minimum liquidation size to track (USD)
min_liquidation_size: 100000
# Large liquidation threshold (USD)
large_liquidation_threshold: 1000000
# Options settings
options:
# IV interpretation thresholds (percentage)
iv_thresholds:
high: 70.0
low: 40.0
# Put/call ratio interpretation
pcr_thresholds:
bearish: 1.2 # Above this is bearish
bullish: 0.7 # Below this is bullish
# Days until expiry for pressure levels
expiry_pressure:
high: 2 # <= 2 days
medium: 7 # <= 7 days
# Basis settings
basis:
# Structure interpretation thresholds (annualized percentage)
structure_thresholds:
strong: 5.0 # >5% annualized is strong
moderate: 2.0 # >2% is moderate
# Minimum yield for carry trade alerts
min_carry_yield: 5.0
# Output formatting
formatting:
# Console width
console_width: 70
# Number of decimal places
decimals:
rate: 4
percentage: 2
currency: 0
# Currency formatting
currency:
symbol: "$"
thousands_separator: ","
decimal_separator: "."
# Alerts and notifications
alerts:
# Enable alerts
enabled: false
# Alert conditions
conditions:
extreme_funding: true
high_cascade_risk: true
large_liquidation: true
oi_divergence: true
# Webhook URL for alerts (optional)
webhook_url: ""
# Logging
logging:
# Log level: DEBUG, INFO, WARNING, ERROR
level: INFO
# Log file path (optional)
file: ""
# Log format
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
PRD: Crypto Derivatives Tracker
Summary
One-liner: Track cryptocurrency futures, options, and perpetual swaps with comprehensive market analysis Domain: Cryptocurrency / Derivatives Trading Users: Derivatives Traders, Arbitrage Specialists, Risk Managers
---
Problem Statement
Crypto derivatives markets generate massive amounts of data across multiple exchanges - funding rates, open interest, liquidations, options flow, and basis spreads. Traders need to:
1. Monitor funding rates across 5+ exchanges simultaneously 2. Track open interest changes to gauge market positioning 3. Identify liquidation clusters and cascade risks 4. Analyze options flow for smart money signals 5. Find basis trading and funding arbitrage opportunities
Manual monitoring is impractical given the 24/7 nature of crypto markets and the speed at which conditions change. A unified tool that aggregates derivatives data and generates actionable insights is essential.
---
Target Users
Persona 1: Derivatives Day Trader
- Background: Full-time crypto trader focusing on perpetual swaps
- Goals: Profit from funding rate extremes, OI divergences, and liquidation cascades
- Pain Points: Data fragmented across exchanges, misses funding changes
- Success Criteria: Consistent funding capture, early entry before liquidation cascades
Persona 2: Basis Arbitrageur
- Background: Market-neutral trader running cash-and-carry strategies
- Goals: Lock in risk-free returns via spot-futures basis trades
- Pain Points: Manual basis calculations, timing entry/exit around funding
- Success Criteria: Captures basis premium with minimal directional risk
Persona 3: Options Flow Analyst
- Background: Institutional researcher tracking smart money via options
- Goals: Identify unusual options activity and positioning before moves
- Pain Points: Options data scattered, hard to interpret Greeks at scale
- Success Criteria: Detects smart money positioning ahead of price moves
---
User Stories
US-1: Funding Rate Monitoring (Critical)
As a derivatives trader I want to see funding rates across all major exchanges in one view So that I can identify arbitrage opportunities and sentiment extremes
Acceptance Criteria:
- Display funding rates for BTC, ETH, SOL across Binance, Bybit, OKX, Deribit
- Show current, 24h average, and 7d average rates
- Calculate annualized funding yield
- Alert when funding exceeds configurable threshold (default: 0.1%)
US-2: Open Interest Analysis (Critical)
As a derivatives trader I want to track open interest changes by exchange and contract type So that I can gauge market positioning and trend strength
Acceptance Criteria:
- Show total OI in USD and BTC/ETH equivalent
- Display 24h, 7d, 30d OI changes
- Compare OI across exchanges (market share)
- Analyze OI vs price divergences
US-3: Liquidation Monitoring (Critical)
As a derivatives trader I want to see liquidation levels and recent liquidation events So that I can avoid cascade zones and position for liquidation-driven moves
Acceptance Criteria:
- Display liquidation heatmap with price levels
- Show recent large liquidations (>$100K)
- Calculate long/short liquidation zones
- Estimate cascade risk at key levels
US-4: Basis Tracking (High)
As a basis arbitrageur I want to see spot-futures basis across all expiries So that I can identify cash-and-carry opportunities
Acceptance Criteria:
- Calculate perpetual-spot basis (real-time)
- Calculate quarterly-spot basis with annualized yield
- Compare basis across exchanges
- Signal when basis exceeds profitability threshold
US-5: Options Flow Analysis (High)
As an options analyst I want to track unusual options activity and positioning So that I can identify smart money moves
Acceptance Criteria:
- Show large options trades (premium > $100K)
- Display put/call ratio by volume and OI
- Calculate max pain for upcoming expiries
- Analyze implied volatility levels and skew
US-6: Multi-Asset Dashboard (Medium)
As a portfolio manager I want to see derivatives metrics for multiple assets So that I can monitor my entire derivatives exposure
Acceptance Criteria:
- Support BTC, ETH, SOL, and major altcoins
- Display comparative funding rates
- Show aggregate OI across assets
- Highlight assets with extreme metrics
---
Functional Requirements
REQ-1: Multi-Exchange Data Aggregation
- Fetch funding rates from Binance, Bybit, OKX, Deribit, BitMEX
- Aggregate open interest across exchanges
- Support both USDT-margined and coin-margined contracts
REQ-2: Funding Rate Analysis
- Current funding rate with countdown to next payment
- Historical funding (24h, 7d, 30d averages)
- Funding arbitrage opportunities between exchanges
- Annualized funding yield calculation
REQ-3: Open Interest Analytics
- Total OI by asset and exchange
- OI change tracking (1h, 24h, 7d)
- Long/short ratio by exchange
- OI vs price divergence detection
REQ-4: Liquidation Intelligence
- Real-time liquidation tracking
- Liquidation heatmap generation
- Cascade risk estimation
- Historical liquidation analysis
REQ-5: Options Market Data
- Implied volatility by strike and expiry
- Put/call ratio tracking
- Max pain calculation
- Options flow for large trades
REQ-6: Basis Calculations
- Perpetual basis (funding-implied)
- Quarterly futures basis
- Annualized yield calculation
- Basis convergence alerts
---
API Integrations
| Source | Data Provided | Rate Limits |
|---|---|---|
| Binance Futures | Funding, OI, liquidations | 1200/min |
| Bybit | Funding, OI, positions | 120/min |
| OKX | Funding, OI, options | 60/min |
| Deribit | Options, funding, OI | 10K/day |
| Coinglass | Aggregated derivatives | API key required |
---
Success Metrics
1. Data Freshness: All metrics updated within 5 seconds 2. Exchange Coverage: 5+ CEX, 3+ DEX protocols supported 3. Alert Accuracy: 90%+ of funding extremes detected 4. User Satisfaction: Clear, actionable output format
---
Non-Goals
- Not executing trades or managing positions
- Not providing financial advice or guaranteed signals
- Not real-time order book depth analysis
- Not custom strategy backtesting
- Not portfolio accounting or tax reporting
---
Risk Considerations
Market Risks
- Funding rates can flip rapidly during volatility
- Liquidation cascades can gap through levels
- Options pricing models have limitations
Data Risks
- Exchange API outages or rate limits
- Delayed or stale data during high volatility
- Inconsistent data formats between exchanges
User Risks
- Over-reliance on signals without risk management
- Misinterpretation of complex derivatives metrics
- Leverage amplifies both gains and losses
---
Examples
Example 1: Funding Rate Alert
User: "What's the funding rate for BTC?"
Output:
BTC PERPETUAL FUNDING RATES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Exchange Current 24h Avg 7d Avg Next Payment
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Binance +0.0150% +0.0120% +0.0080% 2h 15m
Bybit +0.0180% +0.0140% +0.0100% 2h 15m
OKX +0.0130% +0.0110% +0.0090% 2h 15m
Deribit +0.0200% +0.0150% +0.0120% 2h 15m
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Annualized: +15.77% (based on current rates)
Sentiment: Moderately Bullish
Arbitrage: None (rates aligned)Example 2: Liquidation Analysis
User: "Where are the BTC liquidation levels?"
Output:
BTC LIQUIDATION HEATMAP
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Current Price: $67,500
LONG LIQUIDATIONS (below current):
$65,000: $125M at risk (HIGH DENSITY)
$62,500: $85M at risk
$60,000: $210M at risk (CRITICAL CLUSTER)
SHORT LIQUIDATIONS (above current):
$70,000: $95M at risk
$72,500: $145M at risk (HIGH DENSITY)
$75,000: $180M at risk
Last 24h Liquidations:
Longs: $45.2M | Shorts: $32.8M
Largest: $5.2M long at $66,800
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━---
Version History
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0.0 | 2025-01-15 | Jeremy Longshore | Initial PRD |
Error Handling Reference
Exchange API Errors
Authentication Failures
API Key Invalid
- Error:
Invalid API keyorSignature mismatch - Causes: Expired key, wrong permissions, clock drift
- Solution:
1. Regenerate API keys on exchange 2. Ensure read-only permissions enabled 3. Sync system clock: sudo ntpdate pool.ntp.org 4. Check key has futures/derivatives permissions
IP Whitelist Rejected
- Error:
IP not in whitelist - Solution: Add current IP to exchange API settings or remove whitelist restriction
Rate Limiting
Too Many Requests
- Error:
429 Too Many RequestsorRate limit exceeded - Threshold varies by exchange:
- Binance: 1200 requests/minute (weighted)
- Bybit: 120 requests/minute
- OKX: 60 requests/2 seconds
- Deribit: 100 requests/second
- Solution:
1. Implement exponential backoff 2. Use WebSocket for real-time data 3. Cache static data (max pain, OI levels) 4. Batch requests where possible
Weight Exceeded
- Error:
Request weight exceeded - Solution: Some endpoints cost more weight; use lightweight endpoints or wait
Data Quality Errors
Missing or Stale Data
No Data Available
- Error:
No funding data available for {symbol} - Causes: Symbol not listed, exchange down, maintenance
- Solution:
1. Verify symbol exists on exchange 2. Check exchange status page 3. Fall back to alternative exchange 4. Use mock data for testing
Stale Timestamp
- Error: Data timestamp older than expected
- Solution:
1. Check WebSocket connection alive 2. Verify exchange API operational 3. Increase polling frequency 4. Implement freshness checks
Invalid Values
Negative Funding Rate
- Not an error - negative funding is valid (shorts pay longs)
- Just ensure your calculations handle negative correctly
Zero Open Interest
- May indicate:
- New symbol with no positions
- Data not yet populated
- Exchange maintenance
- Solution: Filter out or flag as incomplete
Implausible Values
- Funding rate > 10% per 8h → likely data error
- IV > 500% → verify or exclude
- Solution: Implement sanity checks and outlier filtering
Calculation Errors
Division by Zero
Empty Exchange List
- Error:
Division by zeroin weighted average - Cause: No exchanges returned data
- Solution:
if not exchanges:
raise ValueError("No exchange data available")
total = sum(oi.value for oi in exchanges)
if total == 0:
raise ValueError("Total OI is zero")Decimal Precision
Precision Loss
- Error: Incorrect basis calculations due to floating point
- Solution: Use
Decimalfor all price/rate calculations
from decimal import Decimal, ROUND_HALF_UP
basis = (futures - spot) / spot
basis_pct = float(basis.quantize(Decimal('0.0001')))Date Handling
Invalid Expiry Format
- Error:
strptimefails on expiry string - Cause: Different exchange formats (YYYYMMDD vs YYYY-MM-DD)
- Solution:
formats = ['%Y-%m-%d', '%Y%m%d', '%d%b%y']
for fmt in formats:
try:
return datetime.strptime(expiry, fmt)
except ValueError:
continue
raise ValueError(f"Unknown expiry format: {expiry}")Expiry Already Passed
- Warning: Analyzing expired contract
- Solution: Filter to active expiries only
Network Errors
Connection Failures
Connection Timeout
- Error:
Connection timed out - Solution:
1. Increase timeout: timeout=30 2. Use retry with backoff 3. Switch to backup endpoint 4. Check network connectivity
SSL Certificate Error
- Error:
SSL: CERTIFICATE_VERIFY_FAILED - Solution:
1. Update CA certificates 2. For testing only: verify=False (not recommended for production)
WebSocket Issues
Disconnected
- Error: WebSocket connection closed unexpectedly
- Solution:
1. Implement reconnection logic 2. Use heartbeat/ping-pong 3. Handle partial messages
Recovery Strategies
Graceful Degradation
1. Exchange Fallback: If primary exchange fails, try alternatives 2. Cached Data: Use last known good value with timestamp warning 3. Partial Results: Return available data, flag missing exchanges
Retry Logic
import time
def fetch_with_retry(func, max_retries=3, base_delay=1):
for attempt in range(max_retries):
try:
return func()
except RateLimitError:
delay = base_delay * (2 ** attempt)
time.sleep(delay)
except ConnectionError:
if attempt < max_retries - 1:
time.sleep(base_delay)
else:
raise
raise RetryExhaustedError()Circuit Breaker
Track failures per exchange and temporarily disable problematic sources:
failures = defaultdict(int)
disabled_until = {}
def check_exchange_health(exchange):
if exchange in disabled_until:
if datetime.now() < disabled_until[exchange]:
return False
del disabled_until[exchange]
return True
def record_failure(exchange):
failures[exchange] += 1
if failures[exchange] >= 3:
disabled_until[exchange] = datetime.now() + timedelta(minutes=5)Common Issues by Exchange
Binance
- Issue: Weight limits are complex (different endpoints cost different)
- Solution: Track weight counter from response headers
Bybit
- Issue: V5 API has different structure than V3
- Solution: Use unified V5 endpoints consistently
OKX
- Issue: Requires specific headers for authentication
- Solution: Include
OK-ACCESS-*headers correctly
Deribit
- Issue: Options data requires authentication
- Solution: Use API key even for read-only data
BitMEX
- Issue: Rate limits are very strict
- Solution: Aggressive caching, minimal polling
--- [Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)
Usage Examples
CLI Examples
Funding Rate Analysis
Basic funding rate check:
python derivatives_tracker.py funding BTCOutput:
======================================================================
BTC FUNDING RATE ANALYSIS
======================================================================
Exchange Current Annualized Next Payment
--------------------------------------------------
Binance +0.0100% +10.95% 4h 23m
Bybit +0.0095% +10.40% 4h 23m
OKX +0.0088% +9.64% 4h 23m
Deribit +0.0082% +8.98% 4h 23m
BitMEX +0.0078% +8.54% 4h 23m
--------------------------------------------------
Weighted Average: +0.0089%
Annualized: +9.70%
Spread (max-min): 0.0022%
Sentiment: 🟢 Moderate BullishJSON export:
python derivatives_tracker.py funding BTC --format jsonOpen Interest Analysis
Basic OI check:
python derivatives_tracker.py oi BTCOutput:
======================================================================
BTC OPEN INTEREST ANALYSIS
======================================================================
Exchange OI (USD) 24h Chg 7d Chg Share
------------------------------------------------------------
Binance $6.20B +3.2% +8.5% 41.3%
Bybit $3.85B +2.8% +6.2% 25.7%
OKX $2.40B +1.5% +4.8% 16.0%
Deribit $1.50B +4.2% +12.1% 10.0%
BitMEX $1.05B +0.8% +2.4% 7.0%
------------------------------------------------------------
Total OI: $15.00B
24h Change: +2.9%
7d Change: +7.8%
Long/Short Ratio: 1.05 (51.2% long)
Trend: Moderate Increasing
Dominant Exchange: Binance (41.3%)With divergence analysis:
python derivatives_tracker.py oi BTC --price-change 3.5Output includes:
────────────────────────────────────────────────────────────────────────
DIVERGENCE ANALYSIS
────────────────────────────────────────────────────────────────────────
🔍 Divergence Detected!
OI: up (+2.9%)
Price: up (+3.5%)
Signal: BULLISH
Rising OI confirms bullish trend - new longs entering
Confidence: mediumLiquidation Monitoring
Basic liquidation summary:
python derivatives_tracker.py liquidations BTCOutput:
======================================================================
BTC LIQUIDATION MONITOR
======================================================================
Current Price: $67,500
------------------------------------------------------------
24h Liquidations:
Total: $125.5M
Longs: $75.3M
Shorts: $50.2M
Cascade Risk: 🟡 MEDIUM
────────────────────────────────────────────────────────────────────────
LIQUIDATION HEATMAP
────────────────────────────────────────────────────────────────────────
LONG LIQUIDATIONS (below $67,500):
$ 65,000 ████████████ $120M ⚠️ HIGH
$ 63,000 ████████ $80M MEDIUM
$ 60,000 ██████ $60M MEDIUM
$ 58,000 ██ $20M LOW
SHORT LIQUIDATIONS (above $67,500):
$ 70,000 ██████████ $100M HIGH
$ 72,000 ████████ $80M MEDIUM
$ 75,000 ██████ $60M MEDIUM
$ 78,000 ██ $20M LOWWith large liquidation history:
python derivatives_tracker.py liquidations BTC --largeAdds:
────────────────────────────────────────────────────────────────────────
RECENT LARGE LIQUIDATIONS (>$1M)
────────────────────────────────────────────────────────────────────────
Exchange Side Price Value When
------------------------------------------------------------
Binance long $67,200 $5.2M 23m ago
Bybit long $66,850 $3.8M 1h ago
OKX short $68,100 $2.9M 2h agoOptions Analysis
Basic options summary:
python derivatives_tracker.py options BTCOutput:
======================================================================
BTC OPTIONS ANALYSIS
======================================================================
Expiry: 2025-01-31
Exchange: Deribit
Implied Volatility:
ATM IV: 55.5%
Interpretation: NORMAL
IV Rank: 52nd percentile
Put/Call Analysis:
PCR (Volume): 0.85
PCR (OI): 0.92
Sentiment: 🟢 BULLISH
Max Pain:
Price: $66,000
Distance: -2.2% from current
Open Interest:
Calls: $2.80B
Puts: $2.58B
Overall Sentiment: 🟢 BULLISH
Expiry Pressure: LOWWith max pain levels and options flow:
python derivatives_tracker.py options BTC --max-pain --flowBasis Analysis
Basic basis/spread check:
python derivatives_tracker.py basis BTCOutput:
======================================================================
BTC BASIS ANALYSIS
======================================================================
Spot Price: $67,500
------------------------------------------------------------
Expiry Futures Basis Annual Days
------------------------------------------------------------
2025-01-31 $68,175 +1.00% +13.0% 28
2025-02-28 $68,850 +2.00% +13.1% 56
2025-03-28 $69,863 +3.50% +15.2% 84
2025-06-27 $71,550 +6.00% +13.1% 168
------------------------------------------------------------
Market Structure: Moderate Contango
Average Basis: +3.13%
Average Annualized: +13.6%
Best Carry: 2025-03-28 (+15.2% annualized)
────────────────────────────────────────────────────────────────────────
TERM STRUCTURE
────────────────────────────────────────────────────────────────────────
2025-01-31 ▲ ++++++ +13.0%
2025-02-28 ▲ ++++++ +13.1%
2025-03-28 ▲ +++++++ +15.2%
2025-06-27 ▲ ++++++ +13.1%With carry trade scanner:
python derivatives_tracker.py basis BTC --carryMulti-Asset Dashboard
Quick market overview:
python derivatives_tracker.py dashboard BTC ETH SOLOutput:
======================================================================
CRYPTO DERIVATIVES DASHBOARD
======================================================================
======================================================================
BTC
======================================================================
📊 FUNDING
Rate: +0.0089% (+9.70% annual)
Sentiment: 🟢 Bullish
📈 OPEN INTEREST
Total: $15.0B (+2.9% 24h)
Long/Short: 1.05 (51% long)
Trend: Moderate Increasing
💥 LIQUIDATIONS (24h)
Total: $125.5M
Longs: $75.3M | Shorts: $50.2M
Cascade Risk: 🟡 MEDIUM
======================================================================
ETH
======================================================================
📊 FUNDING
Rate: +0.0072% (+7.88% annual)
Sentiment: 🟢 Bullish
📈 OPEN INTEREST
Total: $8.2B (+1.8% 24h)
Long/Short: 1.02 (50.5% long)
Trend: Weak Increasing
💥 LIQUIDATIONS (24h)
Total: $45.2M
Longs: $28.1M | Shorts: $17.1M
Cascade Risk: 🟢 LOW
======================================================================
SOL
======================================================================
📊 FUNDING
Rate: +0.0156% (+17.08% annual)
Sentiment: 🟢 Strong Bullish
📈 OPEN INTEREST
Total: $2.1B (+5.2% 24h)
Long/Short: 1.15 (53.5% long)
Trend: Strong Increasing
💥 LIQUIDATIONS (24h)
Total: $32.8M
Longs: $8.2M | Shorts: $24.6M
Cascade Risk: 🟢 LOWProgrammatic Usage
Funding Rate Arbitrage Detection
from funding_tracker import FundingTracker
tracker = FundingTracker()
# Find arbitrage opportunities
opportunities = tracker.get_arbitrage_opportunities(
symbols=["BTC", "ETH", "SOL"],
min_spread=0.02
)
for opp in opportunities:
print(f"{opp['symbol']}: Long {opp['long_exchange']} "
f"({opp['long_rate']:+.4%}), "
f"Short {opp['short_exchange']} "
f"({opp['short_rate']:+.4%})")
print(f" Spread: {opp['spread']:.4%} per 8h")
print(f" Annualized: {opp['profit_annual_pct']:.1f}%")OI Divergence Trading Signals
from oi_analyzer import OIAnalyzer
analyzer = OIAnalyzer()
# Check for OI/price divergence
price_change_24h = 3.5 # From your data source
divergence = analyzer.detect_divergence("BTC", price_change_24h)
if divergence:
if divergence.signal == "bullish":
print("Strong bullish trend confirmed by OI")
elif divergence.signal == "short_squeeze":
print("Rally may be weak - shorts covering")
elif divergence.signal == "long_liquidation":
print("Selloff may find support - longs washing out")Liquidation Level Alerts
from liquidation_monitor import LiquidationMonitor
monitor = LiquidationMonitor()
current_price = Decimal("67500")
summary = monitor.get_summary("BTC", current_price)
# Alert on high cascade risk
if summary.cascade_risk in ["high", "critical"]:
print(f"⚠️ High liquidation risk!")
print(f" ${float(summary.total_24h_usd)/1e6:.0f}M liquidated in 24h")
# Find nearest levels
if summary.nearest_long_level:
lvl = summary.nearest_long_level
distance = (float(current_price) - float(lvl.price)) / float(current_price) * 100
print(f"Nearest long liquidations: ${lvl.price:,.0f} ({distance:.1f}% below)")Options IV Percentile Tracking
from options_analyzer import OptionsAnalyzer
analyzer = OptionsAnalyzer()
analysis = analyzer.analyze("BTC", current_price=Decimal("67500"))
if analysis.iv_interpretation == "high":
print(f"IV elevated at {analysis.snapshot.atm_iv:.1f}%")
print("Consider premium selling strategies")
elif analysis.iv_interpretation == "low":
print(f"IV compressed at {analysis.snapshot.atm_iv:.1f}%")
print("Consider premium buying strategies")
# Check put/call sentiment
if analysis.overall_sentiment == "bullish":
print("Options flow indicates bullish positioning")Basis Carry Trade Scanner
from basis_calculator import BasisCalculator
calc = BasisCalculator()
# Find carry opportunities across assets
opportunities = calc.find_carry_opportunities(
symbols=["BTC", "ETH"],
min_yield=5.0 # Minimum 5% annualized
)
for opp in opportunities:
print(f"\n{opp.symbol} {opp.expiry}")
print(f" Strategy: {opp.strategy}")
print(f" Yield: {opp.annualized_yield:.1f}% annualized")
print(f" Risk: {opp.risk_notes}")Integration Patterns
Combine with Price Alerts
# Pseudo-code for alert system integration
def check_derivatives_alerts(symbol, price, price_change_24h):
alerts = []
# Funding
funding = FundingTracker().analyze(symbol)
if funding.is_extreme:
alerts.append(f"Extreme funding: {funding.weighted_avg:+.4%}")
# OI divergence
oi = OIAnalyzer()
div = oi.detect_divergence(symbol, price_change_24h)
if div and div.confidence == "high":
alerts.append(f"OI divergence: {div.signal}")
# Liquidations
liq = LiquidationMonitor().get_summary(symbol, Decimal(str(price)))
if liq.cascade_risk == "critical":
alerts.append(f"Critical liquidation risk!")
return alertsJSON Export for Dashboards
from formatters import JSONFormatter
json_fmt = JSONFormatter()
# Export complete dashboard data
dashboard = json_fmt.derivatives_dashboard(
symbol="BTC",
funding=funding_data,
oi=oi_data,
liquidations=liq_data,
options=options_data,
basis=basis_data
)
# Write to file or send to API
with open("derivatives_dashboard.json", "w") as f:
f.write(dashboard)--- [Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)
Tracking Crypto Derivatives - Implementation Reference
Detailed Output Formats
Funding Rate Report
BTC PERPETUAL FUNDING RATES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Exchange Current 24h Avg 7d Avg Next Payment
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Binance +0.0150% +0.0120% +0.0080% 2h 15m
Bybit +0.0180% +0.0140% +0.0100% 2h 15m
OKX +0.0130% +0.0110% +0.0090% 2h 15m
Deribit +0.0200% +0.0150% +0.0120% 2h 15m
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Weighted Avg: +0.0158% | Annualized: +17.29%
Sentiment: Moderately BullishOpen Interest Report
BTC OPEN INTEREST ANALYSIS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Exchange OI (USD) 24h Chg 7d Chg Share
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Binance $8.2B +2.5% +8.1% 44.3%
Bybit $4.5B +1.8% +5.2% 24.3%
OKX $3.1B +3.2% +12.5% 16.8%
BitMEX $1.5B -0.5% -2.1% 8.1%
Deribit $1.2B +0.8% +3.4% 6.5%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total OI: $18.5B (+2.3% 24h)
Long/Short Ratio: 1.15 (53.5% long)Liquidation Heatmap
BTC LIQUIDATION LEVELS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Current Price: $67,500
LONG LIQUIDATIONS (below):
$65,000 ████████████ $125M (HIGH DENSITY)
$62,500 ███████ $85M
$60,000 ████████████████████ $210M (CRITICAL)
SHORT LIQUIDATIONS (above):
$70,000 █████████ $95M
$72,500 █████████████ $145M (HIGH DENSITY)
$75,000 █████████████████ $180M
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
24h Liquidations: Longs $45.2M | Shorts $32.8MOptions Analysis Deep Dive
Options Commands
# Get options overview
python derivatives_tracker.py options BTC
# Show put/call ratio
python derivatives_tracker.py options BTC --pcr
# Find max pain for expiry
python derivatives_tracker.py options BTC --expiry 2025-01-31
# Track large options trades
python derivatives_tracker.py options BTC --flowOptions Insights
- High IV rank (>80): Options expensive, consider selling
- Low IV rank (<20): Options cheap, consider buying
- Max pain: Price where most options expire worthless
Basis Trading Guide
Basis Commands
# Get spot-perp basis
python derivatives_tracker.py basis BTC
# Get quarterly futures basis
python derivatives_tracker.py basis BTC --quarterly
# Show all basis opportunities
python derivatives_tracker.py basis --allBasis Trading Interpretation
- Positive basis: Futures > Spot (contango, normal)
- Negative basis: Futures < Spot (backwardation)
- Cash-and-carry: Buy spot + sell futures when basis high
Key Concepts
- Funding Rate: Payment between longs/shorts every 8h
- Open Interest: Total outstanding contracts
- Basis: Difference between futures and spot price
- Max Pain: Strike where most options expire worthless
- IV Rank: Current IV percentile vs historical
Risk Warning
Derivatives are leveraged instruments with high risk of loss.
- Funding costs accumulate over time
- Liquidations can happen rapidly
- Options can expire worthless
- This tool provides analysis only, not financial advice
--- [Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)
#!/usr/bin/env python3
"""
Basis and spread calculator.
Calculates futures basis and spreads with:
- Spot-futures basis tracking
- Annualized basis yield
- Term structure analysis
- Contango/backwardation detection
"""
from dataclasses import dataclass
from decimal import Decimal
from typing import Dict, List, Optional
from datetime import datetime, date
from exchange_client import ExchangeClient, BasisData, Exchange
@dataclass
class BasisAnalysis:
"""Comprehensive basis analysis."""
symbol: str
spot_price: Decimal
basis_data: List[BasisData]
avg_basis_pct: float
avg_annualized: float
market_structure: str # "contango", "backwardation", "mixed"
structure_strength: str # "strong", "moderate", "weak"
best_carry_expiry: Optional[str]
best_carry_yield: float
timestamp: datetime
@dataclass
class CarryOpportunity:
"""Cash-and-carry arbitrage opportunity."""
symbol: str
exchange: str
expiry: str
spot_price: Decimal
futures_price: Decimal
basis_pct: float
days_to_expiry: int
annualized_yield: float
direction: str # "long_basis" or "short_basis"
strategy: str # Trade description
risk_notes: str
class BasisCalculator:
"""
Calculates and analyzes futures basis.
Features:
- Multi-expiry analysis
- Term structure visualization
- Carry trade identification
- Contango/backwardation detection
"""
# Structure interpretation
STRONG_BASIS = 5.0 # >5% annualized is strong
MODERATE_BASIS = 2.0 # >2% is moderate
def __init__(
self,
client: Optional[ExchangeClient] = None,
):
"""
Initialize basis calculator.
Args:
client: Exchange client for data fetching
"""
self.client = client or ExchangeClient(use_mock=True)
def analyze(
self,
symbol: str,
spot_price: Optional[Decimal] = None,
exchanges: Optional[List[Exchange]] = None,
) -> BasisAnalysis:
"""
Analyze basis for a symbol.
Args:
symbol: Trading symbol (e.g., "BTC")
spot_price: Current spot price
exchanges: Exchanges to include
Returns:
BasisAnalysis with all metrics
"""
# Set default spot price if not provided
if spot_price is None:
if symbol == "BTC":
spot_price = Decimal("67500")
elif symbol == "ETH":
spot_price = Decimal("2500")
else:
spot_price = Decimal("100")
# Fetch basis data
basis_list = self.client.get_all_basis(symbol, spot_price, exchanges)
if not basis_list:
raise ValueError(f"No basis data available for {symbol}")
# Calculate averages
avg_basis = sum(b.basis_pct for b in basis_list) / len(basis_list)
avg_annual = sum(b.annualized_pct for b in basis_list) / len(basis_list)
# Determine market structure
structure, strength = self._analyze_structure(basis_list)
# Find best carry opportunity
best_carry = max(basis_list, key=lambda b: b.annualized_pct)
return BasisAnalysis(
symbol=symbol,
spot_price=spot_price,
basis_data=basis_list,
avg_basis_pct=round(avg_basis, 3),
avg_annualized=round(avg_annual, 2),
market_structure=structure,
structure_strength=strength,
best_carry_expiry=best_carry.expiry,
best_carry_yield=best_carry.annualized_pct,
timestamp=datetime.now(),
)
def _analyze_structure(
self,
basis_list: List[BasisData],
) -> tuple:
"""
Analyze term structure from basis data.
Returns:
(structure, strength) tuple
"""
positive = sum(1 for b in basis_list if b.basis_pct > 0)
negative = sum(1 for b in basis_list if b.basis_pct < 0)
total = len(basis_list)
# Determine structure
if positive == total:
structure = "contango"
elif negative == total:
structure = "backwardation"
elif positive > negative:
structure = "contango" # Mostly contango
elif negative > positive:
structure = "backwardation"
else:
structure = "mixed"
# Determine strength from magnitude
avg_abs = sum(abs(b.annualized_pct) for b in basis_list) / total
if avg_abs >= self.STRONG_BASIS:
strength = "strong"
elif avg_abs >= self.MODERATE_BASIS:
strength = "moderate"
else:
strength = "weak"
return structure, strength
def find_carry_opportunities(
self,
symbols: List[str],
min_yield: float = 5.0,
) -> List[CarryOpportunity]:
"""
Find cash-and-carry arbitrage opportunities.
Strategy:
- Contango: Buy spot, sell futures, collect basis
- Backwardation: Sell spot (if possible), buy futures
Args:
symbols: Symbols to scan
min_yield: Minimum annualized yield (%)
Returns:
List of carry opportunities
"""
opportunities = []
for symbol in symbols:
try:
analysis = self.analyze(symbol)
for basis in analysis.basis_data:
if abs(basis.annualized_pct) >= min_yield:
if basis.basis_pct > 0:
# Contango - long basis trade
direction = "long_basis"
strategy = (
f"Buy {symbol} spot at ${float(analysis.spot_price):,.0f}, "
f"sell {basis.expiry} futures at ${float(basis.futures_price):,.0f}"
)
risk_notes = "Funding costs may reduce yield; early liquidation risk"
else:
# Backwardation - short basis trade
direction = "short_basis"
strategy = (
f"Short {symbol} spot (borrow), "
f"buy {basis.expiry} futures at ${float(basis.futures_price):,.0f}"
)
risk_notes = "Borrowing costs apply; squeeze risk in tight markets"
opportunities.append(CarryOpportunity(
symbol=symbol,
exchange=basis.exchange,
expiry=basis.expiry,
spot_price=analysis.spot_price,
futures_price=basis.futures_price,
basis_pct=basis.basis_pct,
days_to_expiry=basis.days_to_expiry,
annualized_yield=basis.annualized_pct,
direction=direction,
strategy=strategy,
risk_notes=risk_notes,
))
except Exception:
continue
# Sort by yield descending
opportunities.sort(key=lambda x: abs(x.annualized_yield), reverse=True)
return opportunities
def get_term_structure(
self,
symbol: str,
spot_price: Optional[Decimal] = None,
) -> List[Dict]:
"""
Get term structure data for visualization.
Args:
symbol: Trading symbol
spot_price: Current spot price
Returns:
List of expiry data points
"""
analysis = self.analyze(symbol, spot_price)
# Sort by days to expiry
sorted_basis = sorted(
analysis.basis_data,
key=lambda b: b.days_to_expiry
)
return [
{
"expiry": b.expiry,
"days": b.days_to_expiry,
"futures_price": float(b.futures_price),
"basis_pct": b.basis_pct,
"annualized_pct": b.annualized_pct,
"exchange": b.exchange,
}
for b in sorted_basis
]
def calculate_implied_rate(
self,
spot: Decimal,
futures: Decimal,
days: int,
) -> Dict:
"""
Calculate implied interest rate from basis.
Args:
spot: Spot price
futures: Futures price
days: Days to expiry
Returns:
Dict with rate calculations
"""
if days <= 0:
return {"error": "Days must be positive"}
basis = float(futures - spot)
basis_pct = basis / float(spot) * 100
annualized = basis_pct * 365 / days
return {
"spot": float(spot),
"futures": float(futures),
"days_to_expiry": days,
"basis_usd": round(basis, 2),
"basis_pct": round(basis_pct, 3),
"annualized_rate": round(annualized, 2),
"structure": "contango" if basis > 0 else "backwardation",
}
def demo():
"""Demonstrate basis calculator."""
calc = BasisCalculator()
print("=" * 70)
print("BASIS CALCULATOR")
print("=" * 70)
# Analyze BTC basis
analysis = calc.analyze("BTC", Decimal("67500"))
print(f"\n📈 {analysis.symbol} BASIS ANALYSIS")
print(f" Spot Price: ${analysis.spot_price:,}")
print("-" * 60)
print(f"\n{'Expiry':<12} {'Futures':>12} {'Basis':>10} {'Annual':>10} {'Days':>6}")
print("-" * 60)
for basis in sorted(analysis.basis_data, key=lambda b: b.days_to_expiry):
print(
f"{basis.expiry:<12} "
f"${float(basis.futures_price):>10,.0f} "
f"{basis.basis_pct:>+9.2f}% "
f"{basis.annualized_pct:>+9.1f}% "
f"{basis.days_to_expiry:>6}"
)
print("-" * 60)
print(f"\nMarket Structure: {analysis.structure_strength.title()} {analysis.market_structure.title()}")
print(f"Average Basis: {analysis.avg_basis_pct:+.2f}%")
print(f"Average Annualized: {analysis.avg_annualized:+.1f}%")
print(f"Best Carry: {analysis.best_carry_expiry} ({analysis.best_carry_yield:+.1f}% annualized)")
# Term structure
print("\n" + "-" * 60)
print("TERM STRUCTURE")
print("-" * 60)
structure = calc.get_term_structure("BTC", Decimal("67500"))
for point in structure:
bar = "+" * min(int(abs(point["annualized_pct"]) / 2), 20)
direction = "▲" if point["annualized_pct"] > 0 else "▼"
print(f"{point['expiry']:<12} {direction} {bar} {point['annualized_pct']:+.1f}%")
# Carry opportunities
print("\n" + "=" * 70)
print("CARRY TRADE SCANNER")
print("=" * 70)
opportunities = calc.find_carry_opportunities(["BTC", "ETH"], min_yield=5.0)
if opportunities:
print(f"\n{'Symbol':<6} {'Expiry':<12} {'Basis':>8} {'Annual':>10} {'Direction':<12}")
print("-" * 60)
for opp in opportunities[:5]:
print(
f"{opp.symbol:<6} "
f"{opp.expiry:<12} "
f"{opp.basis_pct:>+7.2f}% "
f"{opp.annualized_yield:>+9.1f}% "
f"{opp.direction:<12}"
)
print("\nTop Opportunity:")
top = opportunities[0]
print(f" Strategy: {top.strategy}")
print(f" Risk: {top.risk_notes}")
else:
print("\nNo carry opportunities found above threshold")
if __name__ == "__main__":
demo()
#!/usr/bin/env python3
"""
Crypto Derivatives Tracker - Main CLI.
Comprehensive derivatives market analysis:
- Funding rate tracking
- Open interest analysis
- Liquidation monitoring
- Options flow analysis
- Basis/spread calculations
- Multi-asset dashboard
Usage:
python derivatives_tracker.py funding BTC
python derivatives_tracker.py oi BTC --format json
python derivatives_tracker.py liquidations BTC
python derivatives_tracker.py options BTC
python derivatives_tracker.py basis BTC
python derivatives_tracker.py dashboard BTC ETH
"""
import argparse
import sys
from decimal import Decimal
from typing import List, Optional
from exchange_client import ExchangeClient
from funding_tracker import FundingTracker
from oi_analyzer import OIAnalyzer
from liquidation_monitor import LiquidationMonitor
from options_analyzer import OptionsAnalyzer
from basis_calculator import BasisCalculator
from formatters import ConsoleFormatter, JSONFormatter, ReportGenerator
def cmd_funding(args):
"""Handle funding subcommand."""
tracker = FundingTracker()
console = ConsoleFormatter()
json_fmt = JSONFormatter()
print(console.header(f"{args.symbol} FUNDING RATE ANALYSIS"))
analysis = tracker.analyze(args.symbol)
if args.format == "json":
print(json_fmt.funding_report(args.symbol, {
"weighted_avg": analysis.weighted_avg,
"annualized_avg": analysis.annualized_avg,
"spread": analysis.spread,
"sentiment": analysis.sentiment,
"sentiment_strength": analysis.sentiment_strength,
"arbitrage_opportunity": analysis.arbitrage_opportunity,
"rates": [
{
"exchange": r.exchange,
"rate": float(r.rate),
"annualized": r.annualized,
"next_payment": r.time_to_payment_str,
}
for r in analysis.rates
],
}))
return
# Console format
print(f"\n{'Exchange':<12} {'Current':>10} {'Annualized':>12} {'Next Payment':>14}")
print("-" * 50)
for rate in sorted(analysis.rates, key=lambda r: r.rate, reverse=True):
print(
f"{rate.exchange:<12} "
f"{float(rate.rate):>+9.4%} "
f"{rate.annualized:>+11.2f}% "
f"{rate.time_to_payment_str:>14}"
)
print("-" * 50)
print(f"\nWeighted Average: {analysis.weighted_avg:+.4%}")
print(f"Annualized: {analysis.annualized_avg:+.2f}%")
print(f"Spread (max-min): {analysis.spread:.4%}")
print(f"\nSentiment: {console.sentiment_icon(analysis.sentiment)} "
f"{analysis.sentiment_strength.title()} {analysis.sentiment.title()}")
if analysis.is_extreme:
print(f"\n⚠️ EXTREME FUNDING - Contrarian opportunity")
if analysis.arbitrage_opportunity:
print(f"\n💰 ARBITRAGE OPPORTUNITY")
print(f" Long on {analysis.min_rate.exchange} ({float(analysis.min_rate.rate):+.4%})")
print(f" Short on {analysis.max_rate.exchange} ({float(analysis.max_rate.rate):+.4%})")
print(f" Profit: {analysis.arbitrage_spread:.4%} per 8h")
def cmd_oi(args):
"""Handle open interest subcommand."""
analyzer = OIAnalyzer()
console = ConsoleFormatter()
json_fmt = JSONFormatter()
print(console.header(f"{args.symbol} OPEN INTEREST ANALYSIS"))
analysis = analyzer.analyze(args.symbol)
if args.format == "json":
print(json_fmt.oi_report(args.symbol, {
"total_oi_usd": float(analysis.total_oi_usd),
"total_oi_contracts": float(analysis.total_oi_contracts),
"avg_change_24h": analysis.avg_change_24h,
"avg_change_7d": analysis.avg_change_7d,
"weighted_long_ratio": analysis.weighted_long_ratio,
"long_percentage": analysis.long_percentage,
"dominant_exchange": analysis.dominant_exchange,
"dominant_share": analysis.dominant_share,
"trend": analysis.trend,
"trend_strength": analysis.trend_strength,
"exchanges": [
{
"exchange": oi.exchange,
"oi_usd": float(oi.oi_usd),
"change_24h": oi.change_24h_pct,
"change_7d": oi.change_7d_pct,
"long_ratio": oi.long_ratio,
}
for oi in analysis.exchanges
],
}))
return
# Console format
print(f"\n{'Exchange':<12} {'OI (USD)':>14} {'24h Chg':>10} {'7d Chg':>10} {'Share':>8}")
print("-" * 60)
for oi in sorted(analysis.exchanges, key=lambda x: x.oi_usd, reverse=True):
share = float(oi.oi_usd) / float(analysis.total_oi_usd) * 100
print(
f"{oi.exchange:<12} "
f"${float(oi.oi_usd)/1e9:>12.2f}B "
f"{oi.change_24h_pct:>+9.1f}% "
f"{oi.change_7d_pct:>+9.1f}% "
f"{share:>7.1f}%"
)
print("-" * 60)
print(f"\nTotal OI: ${float(analysis.total_oi_usd)/1e9:.2f}B")
print(f"24h Change: {analysis.avg_change_24h:+.1f}%")
print(f"7d Change: {analysis.avg_change_7d:+.1f}%")
print(f"\nLong/Short Ratio: {analysis.weighted_long_ratio:.2f} "
f"({analysis.long_percentage:.1f}% long)")
print(f"Trend: {analysis.trend_strength.title()} {analysis.trend.title()}")
print(f"Dominant Exchange: {analysis.dominant_exchange} ({analysis.dominant_share:.1f}%)")
# Check for divergence
if args.price_change:
print(console.section("DIVERGENCE ANALYSIS"))
divergence = analyzer.detect_divergence(args.symbol, args.price_change)
if divergence:
print(f"\n🔍 Divergence Detected!")
print(f" OI: {divergence.oi_direction} ({divergence.oi_change_pct:+.1f}%)")
print(f" Price: {divergence.price_direction} ({divergence.price_change_pct:+.1f}%)")
print(f" Signal: {divergence.signal.upper()}")
print(f" {divergence.description}")
print(f" Confidence: {divergence.confidence}")
else:
print("\nNo significant divergence detected")
def cmd_liquidations(args):
"""Handle liquidations subcommand."""
monitor = LiquidationMonitor()
console = ConsoleFormatter()
json_fmt = JSONFormatter()
price = Decimal(str(args.price)) if args.price else None
summary = monitor.get_summary(args.symbol, price)
print(console.header(f"{args.symbol} LIQUIDATION MONITOR"))
if args.format == "json":
print(json_fmt.format({
"symbol": summary.symbol,
"current_price": float(summary.current_price),
"total_24h_usd": float(summary.total_24h_usd),
"long_liquidations_usd": float(summary.long_liquidations_usd),
"short_liquidations_usd": float(summary.short_liquidations_usd),
"cascade_risk": summary.cascade_risk,
"long_levels": [
{
"price": float(l.price),
"total_value_usd": float(l.total_value_usd),
"density": l.density,
}
for l in summary.long_levels
],
"short_levels": [
{
"price": float(l.price),
"total_value_usd": float(l.total_value_usd),
"density": l.density,
}
for l in summary.short_levels
],
}))
return
print(f"\n Current Price: ${summary.current_price:,}")
print("-" * 60)
# 24h totals
print(f"\n24h Liquidations:")
print(f" Total: ${float(summary.total_24h_usd)/1e6:,.1f}M")
print(f" Longs: ${float(summary.long_liquidations_usd)/1e6:,.1f}M")
print(f" Shorts: ${float(summary.short_liquidations_usd)/1e6:,.1f}M")
# Cascade risk
print(f"\nCascade Risk: {console.risk_icon(summary.cascade_risk)} "
f"{summary.cascade_risk.upper()}")
# Heatmap
print(console.section("LIQUIDATION HEATMAP"))
print(f"\nLONG LIQUIDATIONS (below ${summary.current_price:,}):")
for level in summary.long_levels[:4]:
bar_len = min(int(float(level.total_value_usd) / 10_000_000), 20)
bar = "█" * bar_len
density_mark = "⚠️ " if level.density in ["high", "critical"] else ""
print(
f" ${float(level.price):>10,.0f} {bar} "
f"${float(level.total_value_usd)/1e6:.0f}M "
f"{density_mark}{level.density.upper()}"
)
print(f"\nSHORT LIQUIDATIONS (above ${summary.current_price:,}):")
for level in summary.short_levels[:4]:
bar_len = min(int(float(level.total_value_usd) / 10_000_000), 20)
bar = "█" * bar_len
density_mark = "⚠️ " if level.density in ["high", "critical"] else ""
print(
f" ${float(level.price):>10,.0f} {bar} "
f"${float(level.total_value_usd)/1e6:.0f}M "
f"{density_mark}{level.density.upper()}"
)
# Large liquidations
if args.large:
print(console.section("RECENT LARGE LIQUIDATIONS"))
large = monitor.get_recent_large_liquidations(
args.symbol, min_value_usd=1_000_000, limit=5
)
if large:
print(f"\n{'Exchange':<10} {'Side':<6} {'Price':>12} {'Value':>12} {'When':>10}")
print("-" * 60)
for l in large:
print(
f"{l['exchange']:<10} "
f"{l['side']:<6} "
f"${l['price']:>10,.0f} "
f"${l['value_usd']/1e6:>10.1f}M "
f"{l['time_ago']:>10}"
)
def cmd_options(args):
"""Handle options subcommand."""
analyzer = OptionsAnalyzer()
console = ConsoleFormatter()
json_fmt = JSONFormatter()
price = Decimal(str(args.price)) if args.price else None
analysis = analyzer.analyze(args.symbol, current_price=price)
print(console.header(f"{args.symbol} OPTIONS ANALYSIS"))
if args.format == "json":
print(json_fmt.format({
"symbol": analysis.symbol,
"expiry": analysis.snapshot.expiry,
"atm_iv": analysis.snapshot.atm_iv,
"iv_interpretation": analysis.iv_interpretation,
"iv_percentile": analysis.iv_percentile,
"put_call_ratio_volume": analysis.snapshot.put_call_ratio_volume,
"put_call_ratio_oi": analysis.snapshot.put_call_ratio_oi,
"sentiment_from_pcr": analysis.sentiment_from_pcr,
"sentiment_from_skew": analysis.sentiment_from_skew,
"overall_sentiment": analysis.overall_sentiment,
"max_pain": float(analysis.snapshot.max_pain),
"max_pain_distance_pct": analysis.max_pain_distance_pct,
"expiry_pressure": analysis.expiry_pressure,
"total_call_oi": float(analysis.snapshot.total_call_oi),
"total_put_oi": float(analysis.snapshot.total_put_oi),
}))
return
snap = analysis.snapshot
print(f"\nExpiry: {snap.expiry}")
print(f"Exchange: {snap.exchange}")
print(f"\nImplied Volatility:")
print(f" ATM IV: {snap.atm_iv:.1f}%")
print(f" Interpretation: {analysis.iv_interpretation.upper()}")
print(f" IV Rank: {analysis.iv_percentile:.0f}th percentile")
print(f"\nPut/Call Analysis:")
print(f" PCR (Volume): {snap.put_call_ratio_volume:.2f}")
print(f" PCR (OI): {snap.put_call_ratio_oi:.2f}")
print(f" Sentiment: {console.sentiment_icon(analysis.sentiment_from_pcr)} "
f"{analysis.sentiment_from_pcr.upper()}")
print(f"\nMax Pain:")
print(f" Price: ${snap.max_pain:,.0f}")
print(f" Distance: {analysis.max_pain_distance_pct:+.1f}% from current")
print(f"\nOpen Interest:")
print(f" Calls: ${float(snap.total_call_oi)/1e9:.2f}B")
print(f" Puts: ${float(snap.total_put_oi)/1e9:.2f}B")
print(f"\nOverall Sentiment: {console.sentiment_icon(analysis.overall_sentiment)} "
f"{analysis.overall_sentiment.upper()}")
print(f"Expiry Pressure: {analysis.expiry_pressure.upper()}")
# Max pain levels
if args.max_pain:
print(console.section("MAX PAIN BY EXPIRY"))
levels = analyzer.get_max_pain_levels(args.symbol)
print(f"\n{'Expiry':<12} {'Max Pain':>12} {'Call OI':>12} {'Put OI':>12} {'PCR':>6}")
print("-" * 50)
for lvl in levels:
print(
f"{lvl['expiry']:<12} "
f"${lvl['max_pain']:>10,.0f} "
f"${lvl['call_oi']/1e9:>10.1f}B "
f"${lvl['put_oi']/1e9:>10.1f}B "
f"{lvl['pcr_oi']:>5.2f}"
)
# Options flow
if args.flow:
print(console.section("OPTIONS FLOW (Simulated)"))
flows = analyzer.generate_mock_flow(args.symbol, count=5)
print(f"\n{'Type':<6} {'Strike':>10} {'Size':>8} {'Premium':>12} {'Interpretation':<25}")
print("-" * 70)
for flow in flows:
print(
f"{flow.option_type.upper():<6} "
f"${float(flow.strike):>8,.0f} "
f"{flow.size_contracts:>8} "
f"${float(flow.premium_usd):>10,.0f} "
f"{flow.interpretation:<25}"
)
def cmd_basis(args):
"""Handle basis subcommand."""
calc = BasisCalculator()
console = ConsoleFormatter()
json_fmt = JSONFormatter()
price = Decimal(str(args.price)) if args.price else None
analysis = calc.analyze(args.symbol, price)
print(console.header(f"{args.symbol} BASIS ANALYSIS"))
if args.format == "json":
print(json_fmt.format({
"symbol": analysis.symbol,
"spot_price": float(analysis.spot_price),
"avg_basis_pct": analysis.avg_basis_pct,
"avg_annualized": analysis.avg_annualized,
"market_structure": analysis.market_structure,
"structure_strength": analysis.structure_strength,
"best_carry_expiry": analysis.best_carry_expiry,
"best_carry_yield": analysis.best_carry_yield,
"basis_data": [
{
"expiry": b.expiry,
"futures_price": float(b.futures_price),
"basis_pct": b.basis_pct,
"annualized_pct": b.annualized_pct,
"days_to_expiry": b.days_to_expiry,
}
for b in analysis.basis_data
],
}))
return
print(f"\n Spot Price: ${analysis.spot_price:,}")
print("-" * 60)
print(f"\n{'Expiry':<12} {'Futures':>12} {'Basis':>10} {'Annual':>10} {'Days':>6}")
print("-" * 60)
for basis in sorted(analysis.basis_data, key=lambda b: b.days_to_expiry):
print(
f"{basis.expiry:<12} "
f"${float(basis.futures_price):>10,.0f} "
f"{basis.basis_pct:>+9.2f}% "
f"{basis.annualized_pct:>+9.1f}% "
f"{basis.days_to_expiry:>6}"
)
print("-" * 60)
print(f"\nMarket Structure: {analysis.structure_strength.title()} "
f"{analysis.market_structure.title()}")
print(f"Average Basis: {analysis.avg_basis_pct:+.2f}%")
print(f"Average Annualized: {analysis.avg_annualized:+.1f}%")
print(f"Best Carry: {analysis.best_carry_expiry} "
f"({analysis.best_carry_yield:+.1f}% annualized)")
# Term structure
print(console.section("TERM STRUCTURE"))
structure = calc.get_term_structure(args.symbol, analysis.spot_price)
for point in structure:
bar = "+" * min(int(abs(point["annualized_pct"]) / 2), 20)
direction = "▲" if point["annualized_pct"] > 0 else "▼"
print(f"{point['expiry']:<12} {direction} {bar} {point['annualized_pct']:+.1f}%")
# Carry scanner
if args.carry:
print(console.section("CARRY TRADE SCANNER"))
opportunities = calc.find_carry_opportunities([args.symbol], min_yield=5.0)
if opportunities:
print(f"\n{'Expiry':<12} {'Basis':>8} {'Annual':>10} {'Direction':<12}")
print("-" * 50)
for opp in opportunities[:5]:
print(
f"{opp.expiry:<12} "
f"{opp.basis_pct:>+7.2f}% "
f"{opp.annualized_yield:>+9.1f}% "
f"{opp.direction:<12}"
)
print("\nTop Opportunity:")
top = opportunities[0]
print(f" Strategy: {top.strategy}")
print(f" Risk: {top.risk_notes}")
else:
print("\nNo carry opportunities found above threshold")
def cmd_dashboard(args):
"""Handle dashboard subcommand."""
console = ConsoleFormatter()
report_gen = ReportGenerator()
funding_tracker = FundingTracker()
oi_analyzer = OIAnalyzer()
liq_monitor = LiquidationMonitor()
print(console.header("CRYPTO DERIVATIVES DASHBOARD"))
for symbol in args.symbols:
print(f"\n{'=' * 70}")
print(f" {symbol} ".center(70, "="))
print("=" * 70)
try:
# Funding
funding = funding_tracker.analyze(symbol)
print(f"\n📊 FUNDING")
print(f" Rate: {funding.weighted_avg:+.4%} ({funding.annualized_avg:+.1f}% annual)")
print(f" Sentiment: {console.sentiment_icon(funding.sentiment)} "
f"{funding.sentiment.title()}")
# OI
oi = oi_analyzer.analyze(symbol)
print(f"\n📈 OPEN INTEREST")
print(f" Total: ${float(oi.total_oi_usd)/1e9:.1f}B ({oi.avg_change_24h:+.1f}% 24h)")
print(f" Long/Short: {oi.weighted_long_ratio:.2f} ({oi.long_percentage:.0f}% long)")
print(f" Trend: {oi.trend_strength.title()} {oi.trend.title()}")
# Liquidations
liq = liq_monitor.get_summary(symbol)
print(f"\n💥 LIQUIDATIONS (24h)")
print(f" Total: ${float(liq.total_24h_usd)/1e6:.1f}M")
print(f" Longs: ${float(liq.long_liquidations_usd)/1e6:.1f}M | "
f"Shorts: ${float(liq.short_liquidations_usd)/1e6:.1f}M")
print(f" Cascade Risk: {console.risk_icon(liq.cascade_risk)} "
f"{liq.cascade_risk.upper()}")
except Exception as e:
print(f"\n⚠️ Error fetching data for {symbol}: {e}")
print(f"\n{'=' * 70}")
print(f"Dashboard generated at: {console.H_LINE * 50}")
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Crypto Derivatives Tracker",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s funding BTC
%(prog)s oi BTC --price-change 3.5
%(prog)s liquidations BTC --large
%(prog)s options BTC --flow --max-pain
%(prog)s basis BTC --carry
%(prog)s dashboard BTC ETH SOL
""",
)
subparsers = parser.add_subparsers(dest="command", help="Available commands")
# Funding subcommand
funding_parser = subparsers.add_parser("funding", help="Analyze funding rates")
funding_parser.add_argument("symbol", help="Trading symbol (e.g., BTC)")
funding_parser.add_argument("--format", choices=["console", "json"],
default="console", help="Output format")
# OI subcommand
oi_parser = subparsers.add_parser("oi", help="Analyze open interest")
oi_parser.add_argument("symbol", help="Trading symbol")
oi_parser.add_argument("--price-change", type=float, dest="price_change",
help="24h price change %% for divergence analysis")
oi_parser.add_argument("--format", choices=["console", "json"],
default="console", help="Output format")
# Liquidations subcommand
liq_parser = subparsers.add_parser("liquidations", help="Monitor liquidations")
liq_parser.add_argument("symbol", help="Trading symbol")
liq_parser.add_argument("--price", type=float, help="Current price override")
liq_parser.add_argument("--large", action="store_true",
help="Show recent large liquidations")
liq_parser.add_argument("--format", choices=["console", "json"],
default="console", help="Output format")
# Options subcommand
opt_parser = subparsers.add_parser("options", help="Analyze options market")
opt_parser.add_argument("symbol", help="Trading symbol")
opt_parser.add_argument("--price", type=float, help="Current price override")
opt_parser.add_argument("--max-pain", action="store_true", dest="max_pain",
help="Show max pain by expiry")
opt_parser.add_argument("--flow", action="store_true",
help="Show options flow")
opt_parser.add_argument("--format", choices=["console", "json"],
default="console", help="Output format")
# Basis subcommand
basis_parser = subparsers.add_parser("basis", help="Calculate futures basis")
basis_parser.add_argument("symbol", help="Trading symbol")
basis_parser.add_argument("--price", type=float, help="Spot price override")
basis_parser.add_argument("--carry", action="store_true",
help="Show carry opportunities")
basis_parser.add_argument("--format", choices=["console", "json"],
default="console", help="Output format")
# Dashboard subcommand
dash_parser = subparsers.add_parser("dashboard", help="Multi-asset dashboard")
dash_parser.add_argument("symbols", nargs="+", help="Trading symbols")
args = parser.parse_args()
if not args.command:
parser.print_help()
sys.exit(1)
# Dispatch to command handler
commands = {
"funding": cmd_funding,
"oi": cmd_oi,
"liquidations": cmd_liquidations,
"options": cmd_options,
"basis": cmd_basis,
"dashboard": cmd_dashboard,
}
try:
commands[args.command](args)
except KeyboardInterrupt:
print("\nInterrupted")
sys.exit(1)
except Exception as e:
print(f"\n❌ Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Output formatters for derivatives tracker.
Provides consistent formatting for:
- Console output (tables, charts)
- JSON export
- Report generation
"""
import json
from dataclasses import asdict
from datetime import datetime
from decimal import Decimal
from typing import Any, Dict, List, Optional, Union
class DecimalEncoder(json.JSONEncoder):
"""JSON encoder that handles Decimal types."""
def default(self, obj):
if isinstance(obj, Decimal):
return float(obj)
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
def format_currency(value: Union[float, Decimal], decimals: int = 0) -> str:
"""Format value as currency."""
val = float(value)
if abs(val) >= 1e9:
return f"${val/1e9:.1f}B"
elif abs(val) >= 1e6:
return f"${val/1e6:.1f}M"
elif abs(val) >= 1e3:
return f"${val/1e3:.1f}K"
else:
return f"${val:,.{decimals}f}"
def format_percent(value: float, decimals: int = 2, sign: bool = True) -> str:
"""Format value as percentage."""
if sign:
return f"{value:+.{decimals}f}%"
else:
return f"{value:.{decimals}f}%"
def format_time_ago(dt: datetime) -> str:
"""Format datetime as time ago string."""
delta = datetime.now() - dt
minutes = int(delta.total_seconds() / 60)
if minutes < 1:
return "just now"
elif minutes < 60:
return f"{minutes}m ago"
elif minutes < 1440:
hours = minutes // 60
return f"{hours}h ago"
else:
days = minutes // 1440
return f"{days}d ago"
class ConsoleFormatter:
"""
Formats data for console output.
Features:
- ASCII tables
- Bar charts
- Color indicators
- Consistent widths
"""
# Box drawing characters
H_LINE = "─"
V_LINE = "│"
CROSS = "┼"
TOP_LEFT = "┌"
TOP_RIGHT = "┐"
BOT_LEFT = "└"
BOT_RIGHT = "┘"
# Sentiment indicators
BULLISH = "🟢"
BEARISH = "🔴"
NEUTRAL = "🟡"
MIXED = "⚪"
# Risk indicators
RISK_CRITICAL = "🔴"
RISK_HIGH = "🟠"
RISK_MEDIUM = "🟡"
RISK_LOW = "🟢"
def __init__(self, width: int = 70):
"""Initialize formatter with terminal width."""
self.width = width
def header(self, title: str, char: str = "=") -> str:
"""Create a centered header."""
return f"{char * self.width}\n{title.center(self.width)}\n{char * self.width}"
def subheader(self, title: str, char: str = "-") -> str:
"""Create a subheader."""
return f"{char * self.width}\n{title}\n{char * self.width}"
def section(self, title: str) -> str:
"""Create a section divider."""
return f"\n{self.H_LINE * self.width}\n{title}\n{self.H_LINE * self.width}"
def sentiment_icon(self, sentiment: str) -> str:
"""Get icon for sentiment."""
icons = {
"bullish": self.BULLISH,
"bearish": self.BEARISH,
"neutral": self.NEUTRAL,
"mixed": self.MIXED,
}
return icons.get(sentiment.lower(), self.NEUTRAL)
def risk_icon(self, risk: str) -> str:
"""Get icon for risk level."""
icons = {
"critical": self.RISK_CRITICAL,
"high": self.RISK_HIGH,
"medium": self.RISK_MEDIUM,
"low": self.RISK_LOW,
}
return icons.get(risk.lower(), self.RISK_LOW)
def bar(
self,
value: float,
max_value: float,
width: int = 20,
char: str = "█",
) -> str:
"""Create a horizontal bar."""
if max_value <= 0:
return ""
fill = min(int(value / max_value * width), width)
return char * fill
def format_funding_table(
self,
rates: List[Dict],
) -> str:
"""Format funding rates as table."""
lines = []
lines.append(f"{'Exchange':<12} {'Current':>10} {'Annualized':>12} {'Next Payment':>14}")
lines.append("-" * 50)
for rate in sorted(rates, key=lambda r: r.get("rate", 0), reverse=True):
lines.append(
f"{rate['exchange']:<12} "
f"{rate['rate']:>+9.4%} "
f"{rate['annualized']:>+11.1f}% "
f"{rate.get('next_payment', 'N/A'):>14}"
)
return "\n".join(lines)
def format_oi_table(
self,
exchanges: List[Dict],
total: float,
) -> str:
"""Format open interest as table."""
lines = []
lines.append(f"{'Exchange':<12} {'OI (USD)':>14} {'24h Chg':>10} {'7d Chg':>10} {'Share':>8}")
lines.append("-" * 60)
for ex in sorted(exchanges, key=lambda x: x.get("oi_usd", 0), reverse=True):
share = ex.get("oi_usd", 0) / total * 100 if total > 0 else 0
lines.append(
f"{ex['exchange']:<12} "
f"{format_currency(ex.get('oi_usd', 0)):>14} "
f"{ex.get('change_24h', 0):>+9.1f}% "
f"{ex.get('change_7d', 0):>+9.1f}% "
f"{share:>7.1f}%"
)
return "\n".join(lines)
def format_liquidation_heatmap(
self,
levels: List[Dict],
side: str,
max_value: float,
) -> str:
"""Format liquidation levels as visual heatmap."""
lines = []
for level in levels:
bar_len = min(int(level.get("value_usd", 0) / 10_000_000), 20)
bar = "█" * bar_len
density = level.get("density", "low")
marker = "⚠️ " if density in ["high", "critical"] else ""
lines.append(
f" ${float(level.get('price', 0)):>10,.0f} {bar} "
f"{format_currency(level.get('value_usd', 0))} "
f"{marker}{density.upper()}"
)
return "\n".join(lines)
def format_options_summary(
self,
analysis: Dict,
) -> str:
"""Format options analysis summary."""
lines = []
lines.append(f"Implied Volatility:")
lines.append(f" ATM IV: {analysis.get('atm_iv', 0):.1f}%")
lines.append(f" Interpretation: {analysis.get('iv_interpretation', 'unknown').upper()}")
lines.append(f" IV Rank: {analysis.get('iv_percentile', 50):.0f}th percentile")
lines.append(f"\nPut/Call Analysis:")
lines.append(f" PCR (Volume): {analysis.get('pcr_volume', 0):.2f}")
lines.append(f" PCR (OI): {analysis.get('pcr_oi', 0):.2f}")
lines.append(f" Sentiment: {analysis.get('pcr_sentiment', 'neutral').upper()}")
lines.append(f"\nMax Pain:")
lines.append(f" Price: ${analysis.get('max_pain', 0):,.0f}")
lines.append(f" Distance: {analysis.get('max_pain_distance', 0):+.1f}% from current")
return "\n".join(lines)
def format_basis_term_structure(
self,
structure: List[Dict],
) -> str:
"""Format term structure as visual chart."""
lines = []
for point in structure:
annual = point.get("annualized_pct", 0)
bar = "+" * min(int(abs(annual) / 2), 20)
direction = "▲" if annual > 0 else "▼"
lines.append(
f"{point.get('expiry', 'N/A'):<12} {direction} {bar} "
f"{annual:+.1f}%"
)
return "\n".join(lines)
class JSONFormatter:
"""
Formats data for JSON export.
Features:
- Clean JSON structure
- Decimal handling
- Datetime serialization
- Nested object support
"""
def __init__(self, indent: int = 2):
"""Initialize formatter."""
self.indent = indent
def format(self, data: Any) -> str:
"""Format any data as JSON string."""
return json.dumps(
self._prepare(data),
cls=DecimalEncoder,
indent=self.indent,
)
def _prepare(self, obj: Any) -> Any:
"""Prepare object for JSON serialization."""
if hasattr(obj, "__dataclass_fields__"):
# Dataclass - convert to dict
return {k: self._prepare(v) for k, v in asdict(obj).items()}
elif isinstance(obj, dict):
return {k: self._prepare(v) for k, v in obj.items()}
elif isinstance(obj, (list, tuple)):
return [self._prepare(item) for item in obj]
elif isinstance(obj, Decimal):
return float(obj)
elif isinstance(obj, datetime):
return obj.isoformat()
else:
return obj
def funding_report(
self,
symbol: str,
analysis: Dict,
) -> str:
"""Generate funding rate JSON report."""
report = {
"report_type": "funding_rates",
"symbol": symbol,
"generated_at": datetime.now().isoformat(),
"data": self._prepare(analysis),
}
return self.format(report)
def oi_report(
self,
symbol: str,
analysis: Dict,
) -> str:
"""Generate open interest JSON report."""
report = {
"report_type": "open_interest",
"symbol": symbol,
"generated_at": datetime.now().isoformat(),
"data": self._prepare(analysis),
}
return self.format(report)
def derivatives_dashboard(
self,
symbol: str,
funding: Dict,
oi: Dict,
liquidations: Dict,
options: Optional[Dict] = None,
basis: Optional[Dict] = None,
) -> str:
"""Generate complete derivatives dashboard JSON."""
report = {
"report_type": "derivatives_dashboard",
"symbol": symbol,
"generated_at": datetime.now().isoformat(),
"funding": self._prepare(funding),
"open_interest": self._prepare(oi),
"liquidations": self._prepare(liquidations),
}
if options:
report["options"] = self._prepare(options)
if basis:
report["basis"] = self._prepare(basis)
return self.format(report)
class ReportGenerator:
"""
Generates formatted reports combining multiple data sources.
"""
def __init__(self):
"""Initialize report generator."""
self.console = ConsoleFormatter()
self.json_fmt = JSONFormatter()
def derivatives_summary(
self,
symbol: str,
funding: Dict,
oi: Dict,
liquidations: Dict,
format: str = "console",
) -> str:
"""
Generate derivatives market summary.
Args:
symbol: Trading symbol
funding: Funding rate analysis
oi: Open interest analysis
liquidations: Liquidation summary
format: Output format ("console" or "json")
Returns:
Formatted summary string
"""
if format == "json":
return self.json_fmt.derivatives_dashboard(
symbol, funding, oi, liquidations
)
# Console format
lines = []
lines.append(self.console.header(f"{symbol} DERIVATIVES SUMMARY"))
# Funding section
lines.append(f"\n📊 FUNDING RATES")
lines.append(f" Weighted Average: {format_percent(funding.get('weighted_avg', 0) * 100, 4)}")
lines.append(f" Annualized: {format_percent(funding.get('annualized_avg', 0), 1)}")
lines.append(f" Sentiment: {funding.get('sentiment', 'unknown').upper()}")
# OI section
lines.append(f"\n📈 OPEN INTEREST")
lines.append(f" Total: {format_currency(oi.get('total_oi_usd', 0))}")
lines.append(f" 24h Change: {format_percent(oi.get('avg_change_24h', 0), 1)}")
lines.append(f" Trend: {oi.get('trend', 'unknown').title()}")
# Liquidations section
lines.append(f"\n💥 LIQUIDATIONS")
lines.append(f" 24h Total: {format_currency(liquidations.get('total_24h_usd', 0))}")
lines.append(f" Longs: {format_currency(liquidations.get('long_liquidations_usd', 0))}")
lines.append(f" Shorts: {format_currency(liquidations.get('short_liquidations_usd', 0))}")
risk = liquidations.get('cascade_risk', 'low')
lines.append(f" Cascade Risk: {self.console.risk_icon(risk)} {risk.upper()}")
lines.append(f"\n{self.console.H_LINE * self.console.width}")
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
return "\n".join(lines)
def demo():
"""Demonstrate formatters."""
console = ConsoleFormatter()
json_fmt = JSONFormatter()
print(console.header("FORMATTER DEMO"))
# Currency formatting
print("\nCurrency Formatting:")
print(f" $1,234,567,890 → {format_currency(1234567890)}")
print(f" $12,345,678 → {format_currency(12345678)}")
print(f" $123,456 → {format_currency(123456)}")
# Percent formatting
print("\nPercent Formatting:")
print(f" 5.5 → {format_percent(5.5)}")
print(f" -3.25 → {format_percent(-3.25)}")
print(f" 0.02 → {format_percent(0.02, 4)}")
# Bars
print("\nBar Charts:")
print(f" 100/100: {console.bar(100, 100)}")
print(f" 50/100: {console.bar(50, 100)}")
print(f" 25/100: {console.bar(25, 100)}")
# Sentiment icons
print("\nSentiment Icons:")
for sent in ["bullish", "bearish", "neutral", "mixed"]:
print(f" {sent}: {console.sentiment_icon(sent)}")
# JSON export
print("\n" + console.section("JSON EXPORT"))
sample_data = {
"symbol": "BTC",
"price": Decimal("67500.50"),
"timestamp": datetime.now(),
"metrics": {
"funding": 0.01,
"oi": Decimal("15000000000"),
}
}
print(json_fmt.format(sample_data))
if __name__ == "__main__":
demo()
#!/usr/bin/env python3
"""
Funding rate tracker and analyzer.
Tracks funding rates across exchanges with:
- Multi-exchange aggregation
- Historical averages
- Arbitrage opportunity detection
- Sentiment analysis
"""
from dataclasses import dataclass
from decimal import Decimal
from typing import Dict, List, Optional
from datetime import datetime
from exchange_client import ExchangeClient, FundingRate, Exchange
@dataclass
class FundingAnalysis:
"""Aggregated funding rate analysis."""
symbol: str
rates: List[FundingRate]
weighted_avg: float
annualized_avg: float
min_rate: FundingRate
max_rate: FundingRate
spread: float # Max - min rate
sentiment: str # "bullish", "bearish", "neutral"
sentiment_strength: str # "strong", "moderate", "weak"
arbitrage_opportunity: bool
arbitrage_spread: float
timestamp: datetime
@property
def is_extreme(self) -> bool:
"""Check if funding is at extreme levels."""
return abs(self.weighted_avg) > 0.08 # 0.08% 8-hour
@property
def exchanges_count(self) -> int:
"""Number of exchanges with data."""
return len(self.rates)
class FundingTracker:
"""
Tracks and analyzes funding rates across exchanges.
Features:
- Real-time funding aggregation
- Weighted average calculation
- Sentiment analysis
- Arbitrage detection
"""
# Funding rate interpretation thresholds
NEUTRAL_THRESHOLD = 0.005 # Below this is neutral
MODERATE_THRESHOLD = 0.03 # Below this is moderate
EXTREME_THRESHOLD = 0.08 # Above this is extreme
# Arbitrage minimum spread
ARB_MIN_SPREAD = 0.02 # 0.02% minimum for arbitrage
def __init__(
self,
client: Optional[ExchangeClient] = None,
):
"""
Initialize funding tracker.
Args:
client: Exchange client for data fetching
"""
self.client = client or ExchangeClient(use_mock=True)
def analyze(
self,
symbol: str,
exchanges: Optional[List[Exchange]] = None,
) -> FundingAnalysis:
"""
Analyze funding rates for a symbol.
Args:
symbol: Trading symbol (e.g., "BTC")
exchanges: Exchanges to include
Returns:
FundingAnalysis with all metrics
"""
# Fetch rates from all exchanges
rates = self.client.get_all_funding_rates(symbol, exchanges)
if not rates:
raise ValueError(f"No funding data available for {symbol}")
# Calculate weighted average (by estimated OI)
# For simplicity, use equal weights
avg_rate = sum(float(r.rate) for r in rates) / len(rates)
avg_annualized = sum(r.annualized for r in rates) / len(rates)
# Find min and max
min_rate = min(rates, key=lambda r: r.rate)
max_rate = max(rates, key=lambda r: r.rate)
spread = float(max_rate.rate - min_rate.rate)
# Determine sentiment
sentiment, strength = self._analyze_sentiment(avg_rate)
# Check for arbitrage opportunity
arb_opportunity = spread >= self.ARB_MIN_SPREAD
return FundingAnalysis(
symbol=symbol,
rates=rates,
weighted_avg=round(avg_rate, 6),
annualized_avg=round(avg_annualized, 2),
min_rate=min_rate,
max_rate=max_rate,
spread=round(spread, 6),
sentiment=sentiment,
sentiment_strength=strength,
arbitrage_opportunity=arb_opportunity,
arbitrage_spread=round(spread, 6),
timestamp=datetime.now(),
)
def _analyze_sentiment(
self,
avg_rate: float,
) -> tuple:
"""
Analyze market sentiment from funding rate.
Returns:
(sentiment, strength) tuple
"""
abs_rate = abs(avg_rate)
# Determine direction
if avg_rate > self.NEUTRAL_THRESHOLD:
sentiment = "bullish"
elif avg_rate < -self.NEUTRAL_THRESHOLD:
sentiment = "bearish"
else:
sentiment = "neutral"
# Determine strength
if abs_rate >= self.EXTREME_THRESHOLD:
strength = "extreme"
elif abs_rate >= self.MODERATE_THRESHOLD:
strength = "strong"
elif abs_rate >= self.NEUTRAL_THRESHOLD:
strength = "moderate"
else:
strength = "weak"
return sentiment, strength
def get_arbitrage_opportunities(
self,
symbols: List[str],
min_spread: float = 0.02,
) -> List[Dict]:
"""
Find funding arbitrage opportunities across symbols.
Strategy: Long on exchange with negative/low funding,
Short on exchange with positive/high funding.
Args:
symbols: Symbols to check
min_spread: Minimum spread to report
Returns:
List of arbitrage opportunities
"""
opportunities = []
for symbol in symbols:
analysis = self.analyze(symbol)
if analysis.spread >= min_spread:
profit_8h = analysis.spread
profit_daily = profit_8h * 3
profit_annual = profit_8h * 365 * 3
opportunities.append({
"symbol": symbol,
"long_exchange": analysis.min_rate.exchange,
"long_rate": float(analysis.min_rate.rate),
"short_exchange": analysis.max_rate.exchange,
"short_rate": float(analysis.max_rate.rate),
"spread": analysis.spread,
"profit_8h_pct": round(profit_8h, 4),
"profit_daily_pct": round(profit_daily, 4),
"profit_annual_pct": round(profit_annual, 2),
})
# Sort by spread descending
opportunities.sort(key=lambda x: x["spread"], reverse=True)
return opportunities
def get_extreme_funding(
self,
symbols: List[str],
threshold: float = 0.08,
) -> List[Dict]:
"""
Find symbols with extreme funding rates.
Extreme funding often indicates crowded trades and
potential mean reversion opportunities.
Args:
symbols: Symbols to check
threshold: Extreme threshold (default 0.08%)
Returns:
List of extreme funding situations
"""
extreme = []
for symbol in symbols:
analysis = self.analyze(symbol)
if abs(analysis.weighted_avg) >= threshold:
extreme.append({
"symbol": symbol,
"avg_rate": analysis.weighted_avg,
"annualized": analysis.annualized_avg,
"sentiment": analysis.sentiment,
"strength": analysis.sentiment_strength,
"signal": "short" if analysis.weighted_avg > 0 else "long",
"signal_reason": "Contrarian: extreme funding often reverts",
})
# Sort by absolute rate descending
extreme.sort(key=lambda x: abs(x["avg_rate"]), reverse=True)
return extreme
def demo():
"""Demonstrate funding tracker."""
tracker = FundingTracker()
print("=" * 70)
print("FUNDING RATE TRACKER")
print("=" * 70)
# Analyze BTC funding
analysis = tracker.analyze("BTC")
print(f"\n📊 {analysis.symbol} FUNDING ANALYSIS")
print("-" * 50)
print(f"\n{'Exchange':<12} {'Current':>10} {'Annualized':>12} {'Next Payment':>14}")
print("-" * 50)
for rate in sorted(analysis.rates, key=lambda r: r.rate, reverse=True):
print(
f"{rate.exchange:<12} "
f"{float(rate.rate):>+9.4%} "
f"{rate.annualized:>+11.2f}% "
f"{rate.time_to_payment_str:>14}"
)
print("-" * 50)
print(f"\nWeighted Average: {analysis.weighted_avg:+.4%}")
print(f"Annualized: {analysis.annualized_avg:+.2f}%")
print(f"Spread (max-min): {analysis.spread:.4%}")
print(f"\nSentiment: {analysis.sentiment_strength.title()} {analysis.sentiment.title()}")
if analysis.is_extreme:
print(f"\n⚠️ EXTREME FUNDING - Contrarian opportunity")
if analysis.arbitrage_opportunity:
print(f"\n💰 ARBITRAGE OPPORTUNITY")
print(f" Long on {analysis.min_rate.exchange} ({float(analysis.min_rate.rate):+.4%})")
print(f" Short on {analysis.max_rate.exchange} ({float(analysis.max_rate.rate):+.4%})")
print(f" Profit: {analysis.arbitrage_spread:.4%} per 8h")
# Check multiple symbols for arbitrage
print("\n" + "=" * 70)
print("FUNDING ARBITRAGE SCANNER")
print("=" * 70)
opportunities = tracker.get_arbitrage_opportunities(["BTC", "ETH", "SOL"])
if opportunities:
print(f"\n{'Symbol':<8} {'Long On':<12} {'Short On':<12} {'Spread':>8} {'Annual':>10}")
print("-" * 50)
for opp in opportunities:
print(
f"{opp['symbol']:<8} "
f"{opp['long_exchange']:<12} "
f"{opp['short_exchange']:<12} "
f"{opp['spread']:>7.4%} "
f"{opp['profit_annual_pct']:>+9.1f}%"
)
else:
print("\nNo arbitrage opportunities found")
if __name__ == "__main__":
demo()
#!/usr/bin/env python3
"""
Liquidation monitor and heatmap generator.
Tracks liquidations across exchanges with:
- Real-time liquidation events
- Liquidation level clustering
- Cascade risk assessment
- Heatmap visualization
"""
from dataclasses import dataclass
from decimal import Decimal
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from exchange_client import (
ExchangeClient, Liquidation, LiquidationLevel, Exchange
)
@dataclass
class LiquidationSummary:
"""Summary of liquidation activity."""
symbol: str
current_price: Decimal
total_24h_usd: Decimal
long_liquidations_usd: Decimal
short_liquidations_usd: Decimal
largest_single: Liquidation
recent_liquidations: List[Liquidation]
long_levels: List[LiquidationLevel]
short_levels: List[LiquidationLevel]
cascade_risk: str # "low", "medium", "high", "critical"
nearest_long_level: Optional[LiquidationLevel]
nearest_short_level: Optional[LiquidationLevel]
timestamp: datetime
class LiquidationMonitor:
"""
Monitors liquidation events and levels.
Features:
- Real-time liquidation tracking
- Heatmap generation
- Cascade risk assessment
- Level clustering
"""
# Cascade risk thresholds (USD within 5% of price)
CRITICAL_THRESHOLD = 500_000_000 # $500M
HIGH_THRESHOLD = 200_000_000 # $200M
MEDIUM_THRESHOLD = 100_000_000 # $100M
def __init__(
self,
client: Optional[ExchangeClient] = None,
):
"""
Initialize liquidation monitor.
Args:
client: Exchange client for data fetching
"""
self.client = client or ExchangeClient(use_mock=True)
def get_summary(
self,
symbol: str,
current_price: Optional[Decimal] = None,
) -> LiquidationSummary:
"""
Get comprehensive liquidation summary.
Args:
symbol: Trading symbol (e.g., "BTC")
current_price: Current price (fetched if not provided)
Returns:
LiquidationSummary with all metrics
"""
# Set default price if not provided
if current_price is None:
if symbol == "BTC":
current_price = Decimal("67500")
elif symbol == "ETH":
current_price = Decimal("2500")
else:
current_price = Decimal("100")
# Fetch recent liquidations
liquidations = self.client.get_recent_liquidations(
symbol, limit=100, min_value_usd=100000
)
# Fetch liquidation levels
levels = self.client.get_liquidation_levels(symbol, current_price)
# Separate long and short levels
long_levels = [l for l in levels if l.side == "long"]
short_levels = [l for l in levels if l.side == "short"]
# Sort by distance from current price
long_levels.sort(key=lambda x: x.price, reverse=True)
short_levels.sort(key=lambda x: x.price)
# Calculate 24h totals
cutoff = datetime.now() - timedelta(hours=24)
recent_24h = [l for l in liquidations if l.timestamp > cutoff]
total_24h = sum(float(l.value_usd) for l in recent_24h)
long_24h = sum(float(l.value_usd) for l in recent_24h if l.side == "long")
short_24h = sum(float(l.value_usd) for l in recent_24h if l.side == "short")
# Find largest single liquidation
largest = max(liquidations, key=lambda x: x.value_usd) if liquidations else None
# Find nearest levels
nearest_long = long_levels[0] if long_levels else None
nearest_short = short_levels[0] if short_levels else None
# Assess cascade risk
cascade_risk = self._assess_cascade_risk(
current_price, long_levels, short_levels
)
return LiquidationSummary(
symbol=symbol,
current_price=current_price,
total_24h_usd=Decimal(str(int(total_24h))),
long_liquidations_usd=Decimal(str(int(long_24h))),
short_liquidations_usd=Decimal(str(int(short_24h))),
largest_single=largest,
recent_liquidations=liquidations[:20],
long_levels=long_levels,
short_levels=short_levels,
cascade_risk=cascade_risk,
nearest_long_level=nearest_long,
nearest_short_level=nearest_short,
timestamp=datetime.now(),
)
def _assess_cascade_risk(
self,
current_price: Decimal,
long_levels: List[LiquidationLevel],
short_levels: List[LiquidationLevel],
) -> str:
"""
Assess cascade risk based on nearby liquidation levels.
Considers liquidations within 5% of current price.
"""
price = float(current_price)
lower_bound = price * 0.95
upper_bound = price * 1.05
# Sum liquidations within range
nearby_value = 0
for level in long_levels:
if float(level.price) >= lower_bound:
nearby_value += float(level.total_value_usd)
for level in short_levels:
if float(level.price) <= upper_bound:
nearby_value += float(level.total_value_usd)
# Determine risk level
if nearby_value >= self.CRITICAL_THRESHOLD:
return "critical"
elif nearby_value >= self.HIGH_THRESHOLD:
return "high"
elif nearby_value >= self.MEDIUM_THRESHOLD:
return "medium"
else:
return "low"
def generate_heatmap_data(
self,
symbol: str,
current_price: Decimal,
levels: int = 5,
) -> Dict:
"""
Generate heatmap visualization data.
Args:
symbol: Trading symbol
current_price: Current price
levels: Number of levels above/below
Returns:
Dict with heatmap data for visualization
"""
summary = self.get_summary(symbol, current_price)
heatmap = {
"symbol": symbol,
"current_price": float(current_price),
"long_levels": [],
"short_levels": [],
}
# Add long levels (below price)
for level in summary.long_levels[:levels]:
distance_pct = (float(current_price) - float(level.price)) / float(current_price) * 100
heatmap["long_levels"].append({
"price": float(level.price),
"value_usd": float(level.total_value_usd),
"distance_pct": round(distance_pct, 1),
"density": level.density,
})
# Add short levels (above price)
for level in summary.short_levels[:levels]:
distance_pct = (float(level.price) - float(current_price)) / float(current_price) * 100
heatmap["short_levels"].append({
"price": float(level.price),
"value_usd": float(level.total_value_usd),
"distance_pct": round(distance_pct, 1),
"density": level.density,
})
return heatmap
def get_recent_large_liquidations(
self,
symbol: str,
min_value_usd: float = 1_000_000,
limit: int = 10,
) -> List[Dict]:
"""
Get recent large liquidation events.
Args:
symbol: Trading symbol
min_value_usd: Minimum liquidation size
limit: Maximum results
Returns:
List of large liquidations
"""
liquidations = self.client.get_recent_liquidations(
symbol, limit=limit * 2, min_value_usd=min_value_usd
)
# Filter by size and limit
large = [l for l in liquidations if float(l.value_usd) >= min_value_usd]
large = sorted(large, key=lambda x: x.value_usd, reverse=True)[:limit]
return [
{
"exchange": l.exchange,
"side": l.side,
"price": float(l.price),
"quantity": float(l.quantity),
"value_usd": float(l.value_usd),
"time_ago": self._time_ago(l.timestamp),
}
for l in large
]
def _time_ago(self, dt: datetime) -> str:
"""Format timestamp as time ago string."""
delta = datetime.now() - dt
minutes = int(delta.total_seconds() / 60)
if minutes < 60:
return f"{minutes}m ago"
elif minutes < 1440:
hours = minutes // 60
return f"{hours}h ago"
else:
days = minutes // 1440
return f"{days}d ago"
def demo():
"""Demonstrate liquidation monitor."""
monitor = LiquidationMonitor()
print("=" * 70)
print("LIQUIDATION MONITOR")
print("=" * 70)
# Get BTC liquidation summary
summary = monitor.get_summary("BTC", Decimal("67500"))
print(f"\n💥 {summary.symbol} LIQUIDATION SUMMARY")
print(f" Current Price: ${summary.current_price:,}")
print("-" * 60)
# 24h totals
print(f"\n24h Liquidations:")
print(f" Total: ${float(summary.total_24h_usd)/1e6:,.1f}M")
print(f" Longs: ${float(summary.long_liquidations_usd)/1e6:,.1f}M")
print(f" Shorts: ${float(summary.short_liquidations_usd)/1e6:,.1f}M")
# Cascade risk
risk_emoji = {
"low": "🟢",
"medium": "🟡",
"high": "🟠",
"critical": "🔴",
}
print(f"\nCascade Risk: {risk_emoji[summary.cascade_risk]} {summary.cascade_risk.upper()}")
# Heatmap
print("\n" + "-" * 60)
print("LIQUIDATION HEATMAP")
print("-" * 60)
print(f"\nLONG LIQUIDATIONS (below ${summary.current_price:,}):")
for level in summary.long_levels[:4]:
bar_len = min(int(float(level.total_value_usd) / 10_000_000), 20)
bar = "█" * bar_len
density_mark = "⚠️ " if level.density in ["high", "critical"] else ""
print(
f" ${float(level.price):>10,.0f} {bar} "
f"${float(level.total_value_usd)/1e6:.0f}M {density_mark}{level.density.upper()}"
)
print(f"\nSHORT LIQUIDATIONS (above ${summary.current_price:,}):")
for level in summary.short_levels[:4]:
bar_len = min(int(float(level.total_value_usd) / 10_000_000), 20)
bar = "█" * bar_len
density_mark = "⚠️ " if level.density in ["high", "critical"] else ""
print(
f" ${float(level.price):>10,.0f} {bar} "
f"${float(level.total_value_usd)/1e6:.0f}M {density_mark}{level.density.upper()}"
)
# Recent large liquidations
print("\n" + "-" * 60)
print("RECENT LARGE LIQUIDATIONS (>$1M)")
print("-" * 60)
large = monitor.get_recent_large_liquidations("BTC", min_value_usd=1_000_000, limit=5)
if large:
print(f"\n{'Exchange':<10} {'Side':<6} {'Price':>12} {'Value':>12} {'When':>10}")
print("-" * 60)
for l in large:
print(
f"{l['exchange']:<10} "
f"{l['side']:<6} "
f"${l['price']:>10,.0f} "
f"${l['value_usd']/1e6:>10.1f}M "
f"{l['time_ago']:>10}"
)
if __name__ == "__main__":
demo()