
Tracking Crypto Derivatives
- 8 installs
- 82 repo stars
- Updated August 2, 2026
- aaaaqwq/agi-super-skills
tracking-crypto-derivatives is a Claude Code skill that tracks crypto futures, options, and perpetual swaps, aggregating funding rates, open interest, liquidations, and options data across exchanges.
About
tracking-crypto-derivatives is a Claude Code skill for analyzing cryptocurrency derivatives markets. It aggregates funding rates, open interest, liquidations, and options data across centralized and decentralized exchanges to surface trading signals. A derivatives_tracker.py script exposes funding, OI, liquidations, options, basis, and full-dashboard commands with interpretation guidance.
- Tracks funding rates, open interest, and liquidations across exchanges
- Analyzes options flow, put/call ratio, and max pain
- Computes spot-perp and quarterly futures basis
Tracking Crypto Derivatives by the numbers
- 8 all-time installs (skills.sh)
- Ranked #820 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
tracking-crypto-derivatives capabilities & compatibility
Free to run; optional exchange API keys raise rate limits.
- Capabilities
- derivatives tracking · funding rate analysis · open interest analysis · options analysis · basis calculation
- Use cases
- trading · data analysis
- Pricing
- Bring your own API key
- Requires keys
- OPTIONALEXCHANGEAPIKEYSFORHIGHERRATELIMITS
What tracking-crypto-derivatives says it does
Track cryptocurrency futures, options, and perpetual swaps with funding rates, open interest, liquidations, and comprehensive derivatives market analysis.
**Perpetual Swaps**: Binance, Bybit, OKX, Deribit, BitMEX
npx skills add https://github.com/aaaaqwq/agi-super-skills --skill tracking-crypto-derivativesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 82 |
| Last updated | August 2, 2026 |
| Repository | aaaaqwq/agi-super-skills ↗ |
What it does
Use when a trader wants to monitor crypto derivatives markets, funding rates, open interest, liquidations, or options flow.
Who is it for?
Monitoring crypto derivatives markets: funding rates, open interest, liquidations, options flow, and basis.
Skip if: Spot-only portfolio tracking, which the companion crypto-portfolio skill handles.
When should I use this skill?
When the user mentions funding rate, open interest, perpetual swap, futures basis, liquidation levels, options flow, or derivatives analysis.
What you get
A consolidated derivatives view with funding, OI, liquidation, options, and basis signals per asset.
- funding rate report
- open interest report
- liquidation heatmap
By the numbers
- 6 command steps: funding, OI, liquidations, options, basis, dashboard
- Perpetual swaps across 5 exchanges (Binance, Bybit, OKX, Deribit, BitMEX)
Files
Tracking Crypto Derivatives
Overview
Comprehensive derivatives market analysis across centralized and decentralized exchanges. This skill aggregates funding rates, open interest, liquidations, and options data to provide actionable trading insights.
Supported Markets:
- Perpetual Swaps: Binance, Bybit, OKX, Deribit, BitMEX
- Futures: Quarterly and monthly contracts
- Options: Deribit (primary), OKX, Bybit
- DEX Perpetuals: dYdX, GMX, Drift Protocol
Prerequisites
Before using this skill, ensure you have:
- Python 3.8+ installed
- Network access to exchange APIs
- Optional: API keys for higher rate limits
- Understanding of derivatives concepts (funding, OI, basis)
Instructions
Step 1: Check Funding Rates
Monitor funding rates across exchanges to identify sentiment and arbitrage opportunities.
# Check BTC funding rates across all exchanges
python derivatives_tracker.py funding BTC
# Check multiple assets
python derivatives_tracker.py funding BTC ETH SOL
# Show historical average
python derivatives_tracker.py funding BTC --history 7dInterpret Results:
- 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
Step 2: Analyze Open Interest
Track open interest to gauge market positioning and trend strength.
# Get BTC open interest across exchanges
python derivatives_tracker.py oi BTC
# Show OI changes over time
python derivatives_tracker.py oi BTC --changes
# Compare OI vs price
python derivatives_tracker.py oi BTC --divergenceOI Interpretation:
- 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
Step 3: Monitor Liquidations
Track liquidation levels and recent liquidation events.
# Get liquidation heatmap
python derivatives_tracker.py liquidations BTC
# Show recent large liquidations
python derivatives_tracker.py liquidations BTC --recent
# Set minimum size filter
python derivatives_tracker.py liquidations BTC --min-size 100000Liquidation Signals:
- Large liquidation clusters indicate support/resistance
- Cascading liquidations can accelerate price moves
- Long/short liquidation ratio indicates market direction
Step 4: Analyze Options Market
Research options flow and implied volatility.
# 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
Step 5: Calculate Basis
Find basis trading and arbitrage opportunities.
# 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:
- Positive basis: Futures > Spot (contango, normal)
- Negative basis: Futures < Spot (backwardation)
- Cash-and-carry: Buy spot + sell futures when basis high
Step 6: Full Dashboard
Get comprehensive derivatives overview.
# Full derivatives dashboard for BTC
python derivatives_tracker.py dashboard BTC
# Multi-asset dashboard
python derivatives_tracker.py dashboard BTC ETH SOL
# Export to JSON
python derivatives_tracker.py dashboard BTC --output jsonSee {baseDir}/references/implementation.md for detailed implementation guide.
Output
The skill provides structured reports including:
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.8MError Handling
See {baseDir}/references/errors.md for comprehensive error handling.
Common issues:
- ERR_RATE_LIMIT: Reduce request frequency or add API key
- ERR_EXCHANGE_DOWN: Exchange API unavailable, try alternative
- ERR_SYMBOL_INVALID: Check symbol format (BTC, ETH, not BTCUSDT)
Examples
See {baseDir}/references/examples.md for detailed examples.
Quick examples:
# Morning derivatives check
python derivatives_tracker.py dashboard BTC ETH SOL
# Monitor funding for arbitrage
python derivatives_tracker.py funding BTC --alert-threshold 0.08
# Pre-expiry options analysis
python derivatives_tracker.py options BTC --expiry friday
# Find basis trading opportunities
python derivatives_tracker.py basis --all --min-yield 5Resources
Data Sources
- Coinglass: Aggregated derivatives data
- Exchange APIs: Binance, Bybit, OKX, Deribit
- The Graph: DEX perpetuals data
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
ARD: Crypto Derivatives Tracker
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
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)Implementation Guide
Architecture Overview
The crypto derivatives tracker uses a modular architecture with specialized analyzers for each derivatives metric type.
┌─────────────────────────────────────────────────────────────────┐
│ derivatives_tracker.py │
│ (Main CLI Entry) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│FundingTracker │ │ OIAnalyzer │ │Liquidation │
│ │ │ │ │ Monitor │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ ExchangeClient │
│ (Unified Data Layer) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────┬───────┴───────┬─────────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Binance │ │ Bybit │ │ OKX │ │ Deribit │
└─────────┘ └─────────┘ └─────────┘ └─────────┘Step 1: Exchange Client Setup
The ExchangeClient provides a unified interface for all exchanges.
Configuration
Set up API credentials in environment variables or config file:
# Environment-based configuration
import os
config = {
"binance": {
"api_key": os.getenv("BINANCE_API_KEY"),
"api_secret": os.getenv("BINANCE_API_SECRET"),
"base_url": "https://fapi.binance.com",
},
"bybit": {
"api_key": os.getenv("BYBIT_API_KEY"),
"api_secret": os.getenv("BYBIT_API_SECRET"),
"base_url": "https://api.bybit.com",
},
"okx": {
"api_key": os.getenv("OKX_API_KEY"),
"api_secret": os.getenv("OKX_API_SECRET"),
"passphrase": os.getenv("OKX_PASSPHRASE"),
"base_url": "https://www.okx.com",
},
"deribit": {
"client_id": os.getenv("DERIBIT_CLIENT_ID"),
"client_secret": os.getenv("DERIBIT_CLIENT_SECRET"),
"base_url": "https://www.deribit.com",
},
}Mock Mode
For development and testing, use mock mode:
from exchange_client import ExchangeClient
# Use mock data (no API calls)
client = ExchangeClient(use_mock=True)
# Use live data
client = ExchangeClient(use_mock=False)Step 2: Funding Rate Tracking
Data Collection
Funding rates are collected every 8 hours on most exchanges:
from funding_tracker import FundingTracker
tracker = FundingTracker()
# Get current funding rates
analysis = tracker.analyze("BTC")
# Access individual exchange rates
for rate in analysis.rates:
print(f"{rate.exchange}: {rate.rate:.4%} (next: {rate.time_to_payment_str})")Interpretation Thresholds
| Rate Range | Interpretation | Action |
|---|---|---|
| > 0.08% | Extreme Bullish | Contrarian short opportunity |
| 0.03-0.08% | Strong Bullish | Market overheated |
| 0.005-0.03% | Moderate Bullish | Normal uptrend |
| -0.005-0.005% | Neutral | Balanced positioning |
| -0.03-(-0.005)% | Moderate Bearish | Normal downtrend |
| < -0.03% | Strong Bearish | Contrarian long opportunity |
Arbitrage Detection
# Find funding rate discrepancies between exchanges
opportunities = tracker.get_arbitrage_opportunities(
symbols=["BTC", "ETH"],
min_spread=0.02 # 0.02% minimum spread
)Step 3: Open Interest Analysis
Data Aggregation
OI is aggregated across exchanges with weighted calculations:
from oi_analyzer import OIAnalyzer
analyzer = OIAnalyzer()
analysis = analyzer.analyze("BTC")
# Weighted average change (by OI size)
print(f"24h Change: {analysis.avg_change_24h}%")
# Market structure
print(f"Trend: {analysis.trend} ({analysis.trend_strength})")Divergence Detection
Classic OI/Price divergence patterns:
| OI Direction | Price Direction | Signal | Interpretation |
|---|---|---|---|
| Up | Up | Bullish | New longs entering, trend confirmed |
| Up | Down | Bearish | New shorts entering, trend confirmed |
| Down | Up | Short Squeeze | Shorts covering, rally may be weak |
| Down | Down | Long Liquidation | Longs closing, selloff may find support |
divergence = analyzer.detect_divergence("BTC", price_change_24h=3.5)
if divergence:
print(f"Signal: {divergence.signal}")
print(f"Confidence: {divergence.confidence}")Step 4: Liquidation Monitoring
Level Calculation
Liquidation levels are estimated based on:
- Open positions at each exchange
- Average leverage used
- Maintenance margin requirements
from liquidation_monitor import LiquidationMonitor
monitor = LiquidationMonitor()
summary = monitor.get_summary("BTC", current_price=Decimal("67500"))
# Cascade risk assessment
print(f"Risk: {summary.cascade_risk}") # low, medium, high, criticalCascade Risk Thresholds
| Risk Level | Liquidations Within 5% | Description |
|---|---|---|
| Critical | > $500M | High probability of cascade |
| High | $200-500M | Elevated risk |
| Medium | $100-200M | Moderate risk |
| Low | < $100M | Normal conditions |
Heatmap Generation
# Get structured data for visualization
heatmap = monitor.generate_heatmap_data(
symbol="BTC",
current_price=Decimal("67500"),
levels=5 # 5 levels above and below
)Step 5: Options Analysis
IV Interpretation
Implied volatility is compared to historical ranges:
from options_analyzer import OptionsAnalyzer
analyzer = OptionsAnalyzer()
analysis = analyzer.analyze("BTC")
# IV interpretation
if analysis.iv_interpretation == "high":
print("IV elevated - consider selling premium")
elif analysis.iv_interpretation == "low":
print("IV compressed - consider buying premium")Put/Call Ratio
| PCR Range | Interpretation |
|---|---|
| > 1.2 | Bearish (more puts than calls) |
| 0.7-1.2 | Neutral |
| < 0.7 | Bullish (more calls than puts) |
Max Pain Calculation
Max pain is the strike price where options writers have minimum payout:
levels = analyzer.get_max_pain_levels("BTC")
for level in levels:
print(f"{level['expiry']}: ${level['max_pain']:,.0f}")Step 6: Basis Calculations
Term Structure Analysis
from basis_calculator import BasisCalculator
calc = BasisCalculator()
analysis = calc.analyze("BTC", spot_price=Decimal("67500"))
# Market structure
print(f"Structure: {analysis.market_structure}") # contango or backwardationCarry Trade Identification
opportunities = calc.find_carry_opportunities(
symbols=["BTC", "ETH"],
min_yield=5.0 # Minimum 5% annualized
)
for opp in opportunities:
print(f"{opp.symbol}: {opp.annualized_yield:.1f}% yield")
print(f" Strategy: {opp.strategy}")Step 7: Report Generation
Console Output
from formatters import ConsoleFormatter
console = ConsoleFormatter(width=70)
# Create headers and sections
print(console.header("BTC DERIVATIVES"))
print(console.section("FUNDING RATES"))JSON Export
from formatters import JSONFormatter
json_fmt = JSONFormatter(indent=2)
# Export analysis results
report = json_fmt.derivatives_dashboard(
symbol="BTC",
funding=funding_data,
oi=oi_data,
liquidations=liq_data
)
# Write to file
with open("report.json", "w") as f:
f.write(report)Performance Considerations
Caching
Cache static data that doesn't change frequently:
from functools import lru_cache
from datetime import datetime, timedelta
@lru_cache(maxsize=100)
def get_max_pain_cached(symbol, expiry):
# Only recalculate every 15 minutes
cache_key = (symbol, expiry, datetime.now().strftime("%Y%m%d%H%M")[:11])
return calculate_max_pain(symbol, expiry)Rate Limiting
Implement proper rate limiting for API calls:
import time
from collections import defaultdict
class RateLimiter:
def __init__(self, calls_per_minute=60):
self.calls_per_minute = calls_per_minute
self.calls = defaultdict(list)
def wait_if_needed(self, exchange):
now = time.time()
minute_ago = now - 60
# Clean old calls
self.calls[exchange] = [
t for t in self.calls[exchange] if t > minute_ago
]
if len(self.calls[exchange]) >= self.calls_per_minute:
sleep_time = 60 - (now - self.calls[exchange][0])
time.sleep(sleep_time)
self.calls[exchange].append(now)Parallel Fetching
Fetch from multiple exchanges in parallel:
import asyncio
from concurrent.futures import ThreadPoolExecutor
async def fetch_all_funding(symbols):
with ThreadPoolExecutor(max_workers=5) as executor:
loop = asyncio.get_event_loop()
tasks = [
loop.run_in_executor(executor, fetch_funding, symbol)
for symbol in symbols
]
return await asyncio.gather(*tasks)Testing
Unit Tests
def test_funding_sentiment():
tracker = FundingTracker()
# High positive funding should be bullish
sentiment, strength = tracker._analyze_sentiment(0.05)
assert sentiment == "bullish"
assert strength == "strong"
# Negative funding should be bearish
sentiment, strength = tracker._analyze_sentiment(-0.03)
assert sentiment == "bearish"Mock Testing
def test_with_mock_data():
client = ExchangeClient(use_mock=True)
tracker = FundingTracker(client=client)
analysis = tracker.analyze("BTC")
assert analysis.weighted_avg is not None
assert len(analysis.rates) > 0Deployment
Environment Variables
Required for production:
# Exchange API Keys
export BINANCE_API_KEY="your-key"
export BINANCE_API_SECRET="your-secret"
export BYBIT_API_KEY="your-key"
export BYBIT_API_SECRET="your-secret"
# Optional: Deribit for options data
export DERIBIT_CLIENT_ID="your-id"
export DERIBIT_CLIENT_SECRET="your-secret"Running the CLI
# Install dependencies
pip install -r requirements.txt
# Run analysis
python derivatives_tracker.py funding BTC
python derivatives_tracker.py dashboard BTC ETH SOL --format jsonScheduling
For continuous monitoring, schedule regular runs:
# Cron job every 15 minutes
*/15 * * * * cd /path/to/skill && python derivatives_tracker.py dashboard BTC ETH >> /var/log/derivatives.log 2>&1#!/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
"""
Unified exchange client for derivatives data.
Provides consistent interface across multiple exchanges with:
- Rate limiting and retry logic
- Data normalization
- Mock data for simulation
"""
from dataclasses import dataclass
from datetime import datetime, timedelta
from decimal import Decimal
from enum import Enum
from typing import Dict, List, Optional
import random
import time
class Exchange(Enum):
"""Supported exchanges."""
BINANCE = "binance"
BYBIT = "bybit"
OKX = "okx"
DERIBIT = "deribit"
BITMEX = "bitmex"
@dataclass
class FundingRate:
"""Funding rate data point."""
exchange: str
symbol: str
rate: Decimal # Current 8-hour rate
predicted_rate: Decimal # Next predicted rate
next_payment: datetime # Time of next payment
interval_hours: int = 8 # Funding interval
@property
def annualized(self) -> float:
"""Calculate annualized funding rate."""
return float(self.rate) * (365 * 24 / self.interval_hours) * 100
@property
def time_to_payment(self) -> timedelta:
"""Time until next funding payment."""
return self.next_payment - datetime.now()
@property
def time_to_payment_str(self) -> str:
"""Human-readable time to payment."""
delta = self.time_to_payment
hours = int(delta.total_seconds() // 3600)
minutes = int((delta.total_seconds() % 3600) // 60)
return f"{hours}h {minutes}m"
@dataclass
class OpenInterest:
"""Open interest data point."""
exchange: str
symbol: str
oi_usd: Decimal # Total OI in USD
oi_contracts: Decimal # Total contracts
change_1h_pct: float # 1h change
change_24h_pct: float # 24h change
change_7d_pct: float # 7d change
long_ratio: float # Long/short ratio (1.0 = balanced)
timestamp: datetime
@dataclass
class Liquidation:
"""Single liquidation event."""
exchange: str
symbol: str
side: str # "long" or "short"
price: Decimal
quantity: Decimal
value_usd: Decimal
timestamp: datetime
@dataclass
class LiquidationLevel:
"""Aggregated liquidation level."""
price: Decimal
side: str # "long" or "short"
total_value_usd: Decimal
density: str # "low", "medium", "high", "critical"
@dataclass
class OptionsSnapshot:
"""Options market snapshot."""
symbol: str
exchange: str
expiry: str
atm_iv: float # At-the-money IV
put_call_ratio_volume: float # Put/call by volume
put_call_ratio_oi: float # Put/call by OI
max_pain: Decimal # Max pain price
total_call_oi: Decimal
total_put_oi: Decimal
timestamp: datetime
@dataclass
class BasisData:
"""Basis/spread data."""
symbol: str
spot_price: Decimal
perp_price: Decimal
perp_basis_pct: float # Perpetual basis
quarterly_price: Optional[Decimal] = None
quarterly_basis_pct: Optional[float] = None
quarterly_expiry: Optional[str] = None
annualized_yield: Optional[float] = None
class ExchangeClient:
"""
Unified client for fetching derivatives data from exchanges.
Uses mock data for demonstration. In production, replace with
actual API calls.
"""
# Rate limits by exchange
RATE_LIMITS = {
Exchange.BINANCE: {"rpm": 1200, "delay": 0.05},
Exchange.BYBIT: {"rpm": 120, "delay": 0.5},
Exchange.OKX: {"rpm": 60, "delay": 1.0},
Exchange.DERIBIT: {"rpm": 100, "delay": 0.6},
Exchange.BITMEX: {"rpm": 30, "delay": 2.0},
}
def __init__(self, use_mock: bool = True):
"""
Initialize exchange client.
Args:
use_mock: Use mock data (True) or live APIs (False)
"""
self.use_mock = use_mock
self._last_request: Dict[Exchange, float] = {}
def _rate_limit(self, exchange: Exchange):
"""Apply rate limiting for exchange."""
delay = self.RATE_LIMITS[exchange]["delay"]
last = self._last_request.get(exchange, 0)
elapsed = time.time() - last
if elapsed < delay:
time.sleep(delay - elapsed)
self._last_request[exchange] = time.time()
# -------------------------------------------------------------------------
# Funding Rate Methods
# -------------------------------------------------------------------------
def get_funding_rate(
self,
symbol: str,
exchange: Exchange,
) -> Optional[FundingRate]:
"""Get funding rate for symbol on exchange."""
if self.use_mock:
return self._mock_funding_rate(symbol, exchange)
self._rate_limit(exchange)
# Production: implement actual API calls
raise NotImplementedError("Live API not implemented")
def get_all_funding_rates(
self,
symbol: str,
exchanges: Optional[List[Exchange]] = None,
) -> List[FundingRate]:
"""Get funding rates from all exchanges."""
if exchanges is None:
exchanges = list(Exchange)
rates = []
for exchange in exchanges:
rate = self.get_funding_rate(symbol, exchange)
if rate:
rates.append(rate)
return rates
def _mock_funding_rate(
self,
symbol: str,
exchange: Exchange,
) -> FundingRate:
"""Generate mock funding rate."""
# Base rates vary by exchange
base_rates = {
Exchange.BINANCE: 0.0150,
Exchange.BYBIT: 0.0180,
Exchange.OKX: 0.0130,
Exchange.DERIBIT: 0.0200,
Exchange.BITMEX: 0.0100,
}
base = base_rates.get(exchange, 0.0100)
# Add some randomness
rate = base + random.uniform(-0.005, 0.005)
predicted = rate + random.uniform(-0.002, 0.002)
# Next funding payment (8-hour intervals)
now = datetime.now()
# Find next 00:00, 08:00, or 16:00 UTC
hours_since_midnight = now.hour
next_funding_hour = ((hours_since_midnight // 8) + 1) * 8
if next_funding_hour >= 24:
next_funding_hour = 0
next_payment = now.replace(hour=0, minute=0, second=0) + timedelta(days=1)
else:
next_payment = now.replace(hour=next_funding_hour, minute=0, second=0)
if next_payment <= now:
next_payment += timedelta(hours=8)
return FundingRate(
exchange=exchange.value,
symbol=symbol,
rate=Decimal(str(round(rate, 6))),
predicted_rate=Decimal(str(round(predicted, 6))),
next_payment=next_payment,
)
# -------------------------------------------------------------------------
# Open Interest Methods
# -------------------------------------------------------------------------
def get_open_interest(
self,
symbol: str,
exchange: Exchange,
) -> Optional[OpenInterest]:
"""Get open interest for symbol on exchange."""
if self.use_mock:
return self._mock_open_interest(symbol, exchange)
self._rate_limit(exchange)
raise NotImplementedError("Live API not implemented")
def get_all_open_interest(
self,
symbol: str,
exchanges: Optional[List[Exchange]] = None,
) -> List[OpenInterest]:
"""Get open interest from all exchanges."""
if exchanges is None:
exchanges = list(Exchange)
oi_list = []
for exchange in exchanges:
oi = self.get_open_interest(symbol, exchange)
if oi:
oi_list.append(oi)
return oi_list
def _mock_open_interest(
self,
symbol: str,
exchange: Exchange,
) -> OpenInterest:
"""Generate mock open interest data."""
# Base OI varies by exchange (in billions USD)
base_oi = {
Exchange.BINANCE: 8.2,
Exchange.BYBIT: 4.5,
Exchange.OKX: 3.1,
Exchange.DERIBIT: 1.2,
Exchange.BITMEX: 1.5,
}
oi_usd = base_oi.get(exchange, 1.0) * 1_000_000_000
# Add randomness
oi_usd *= (1 + random.uniform(-0.1, 0.1))
# Calculate contracts (assuming ~$67k BTC)
if symbol == "BTC":
price = 67500
elif symbol == "ETH":
price = 2500
oi_usd *= 0.4 # ETH has ~40% of BTC OI
else:
price = 100
oi_usd *= 0.1
contracts = oi_usd / price
return OpenInterest(
exchange=exchange.value,
symbol=symbol,
oi_usd=Decimal(str(int(oi_usd))),
oi_contracts=Decimal(str(int(contracts))),
change_1h_pct=round(random.uniform(-2, 3), 2),
change_24h_pct=round(random.uniform(-5, 8), 2),
change_7d_pct=round(random.uniform(-10, 15), 2),
long_ratio=round(1.0 + random.uniform(-0.2, 0.3), 2),
timestamp=datetime.now(),
)
# -------------------------------------------------------------------------
# Liquidation Methods
# -------------------------------------------------------------------------
def get_recent_liquidations(
self,
symbol: str,
exchange: Optional[Exchange] = None,
limit: int = 50,
min_value_usd: float = 100000,
) -> List[Liquidation]:
"""Get recent liquidation events."""
if self.use_mock:
return self._mock_liquidations(symbol, limit, min_value_usd)
raise NotImplementedError("Live API not implemented")
def get_liquidation_levels(
self,
symbol: str,
current_price: Decimal,
) -> List[LiquidationLevel]:
"""Get aggregated liquidation levels."""
if self.use_mock:
return self._mock_liquidation_levels(symbol, current_price)
raise NotImplementedError("Live API not implemented")
def _mock_liquidations(
self,
symbol: str,
limit: int,
min_value_usd: float,
) -> List[Liquidation]:
"""Generate mock liquidation events."""
liquidations = []
exchanges = [e.value for e in Exchange]
if symbol == "BTC":
base_price = 67500
elif symbol == "ETH":
base_price = 2500
else:
base_price = 100
for i in range(limit):
side = random.choice(["long", "short"])
# Liquidation prices cluster around support/resistance
if side == "long":
price = base_price * (1 - random.uniform(0.01, 0.05))
else:
price = base_price * (1 + random.uniform(0.01, 0.05))
value = random.uniform(min_value_usd, min_value_usd * 50)
quantity = value / price
liquidations.append(Liquidation(
exchange=random.choice(exchanges),
symbol=symbol,
side=side,
price=Decimal(str(round(price, 2))),
quantity=Decimal(str(round(quantity, 4))),
value_usd=Decimal(str(int(value))),
timestamp=datetime.now() - timedelta(minutes=random.randint(1, 1440)),
))
return sorted(liquidations, key=lambda x: x.timestamp, reverse=True)
def _mock_liquidation_levels(
self,
symbol: str,
current_price: Decimal,
) -> List[LiquidationLevel]:
"""Generate mock liquidation level clusters."""
levels = []
price = float(current_price)
# Long liquidation levels (below current price)
long_levels = [
(price * 0.96, 125_000_000, "high"),
(price * 0.93, 85_000_000, "medium"),
(price * 0.89, 210_000_000, "critical"),
(price * 0.85, 150_000_000, "high"),
]
# Short liquidation levels (above current price)
short_levels = [
(price * 1.04, 95_000_000, "medium"),
(price * 1.07, 145_000_000, "high"),
(price * 1.11, 180_000_000, "high"),
(price * 1.15, 120_000_000, "medium"),
]
for lvl_price, value, density in long_levels:
levels.append(LiquidationLevel(
price=Decimal(str(int(lvl_price))),
side="long",
total_value_usd=Decimal(str(int(value * random.uniform(0.8, 1.2)))),
density=density,
))
for lvl_price, value, density in short_levels:
levels.append(LiquidationLevel(
price=Decimal(str(int(lvl_price))),
side="short",
total_value_usd=Decimal(str(int(value * random.uniform(0.8, 1.2)))),
density=density,
))
return sorted(levels, key=lambda x: x.price)
# -------------------------------------------------------------------------
# Options Methods
# -------------------------------------------------------------------------
def get_options_snapshot(
self,
symbol: str,
expiry: Optional[str] = None,
) -> Optional[OptionsSnapshot]:
"""Get options market snapshot."""
if self.use_mock:
return self._mock_options_snapshot(symbol, expiry)
raise NotImplementedError("Live API not implemented")
def _mock_options_snapshot(
self,
symbol: str,
expiry: Optional[str] = None,
) -> OptionsSnapshot:
"""Generate mock options snapshot."""
if symbol == "BTC":
max_pain = 67000
atm_iv = 55 + random.uniform(-5, 10)
elif symbol == "ETH":
max_pain = 2500
atm_iv = 60 + random.uniform(-5, 15)
else:
max_pain = 100
atm_iv = 80 + random.uniform(-10, 20)
if expiry is None:
# Default to next Friday
expiry = "2025-01-17"
call_oi = random.uniform(1, 5) * 1_000_000_000
put_oi = call_oi * random.uniform(0.6, 0.9)
return OptionsSnapshot(
symbol=symbol,
exchange="deribit",
expiry=expiry,
atm_iv=round(atm_iv, 1),
put_call_ratio_volume=round(random.uniform(0.5, 1.2), 2),
put_call_ratio_oi=round(put_oi / call_oi, 2),
max_pain=Decimal(str(max_pain)),
total_call_oi=Decimal(str(int(call_oi))),
total_put_oi=Decimal(str(int(put_oi))),
timestamp=datetime.now(),
)
# -------------------------------------------------------------------------
# Basis Methods
# -------------------------------------------------------------------------
def get_basis_data(
self,
symbol: str,
) -> BasisData:
"""Get basis/spread data."""
if self.use_mock:
return self._mock_basis_data(symbol)
raise NotImplementedError("Live API not implemented")
def _mock_basis_data(self, symbol: str) -> BasisData:
"""Generate mock basis data."""
if symbol == "BTC":
spot = 67500
elif symbol == "ETH":
spot = 2500
else:
spot = 100
# Perpetual typically trades at small premium/discount
perp_basis = random.uniform(-0.05, 0.15)
perp_price = spot * (1 + perp_basis / 100)
# Quarterly typically in contango
quarterly_basis = random.uniform(1, 5)
quarterly_price = spot * (1 + quarterly_basis / 100)
# Annualized yield (assuming ~3 months to expiry)
days_to_expiry = 90
annualized = quarterly_basis * (365 / days_to_expiry)
return BasisData(
symbol=symbol,
spot_price=Decimal(str(round(spot, 2))),
perp_price=Decimal(str(round(perp_price, 2))),
perp_basis_pct=round(perp_basis, 3),
quarterly_price=Decimal(str(round(quarterly_price, 2))),
quarterly_basis_pct=round(quarterly_basis, 3),
quarterly_expiry="2025-03-28",
annualized_yield=round(annualized, 2),
)
def demo():
"""Demonstrate exchange client."""
client = ExchangeClient(use_mock=True)
print("=" * 60)
print("EXCHANGE CLIENT DEMO")
print("=" * 60)
# Funding rates
print("\n📊 BTC Funding Rates:")
rates = client.get_all_funding_rates("BTC")
for rate in rates:
print(f" {rate.exchange:<10} {float(rate.rate):+.4%} | "
f"Annualized: {rate.annualized:+.2f}%")
# Open interest
print("\n📈 BTC Open Interest:")
oi_list = client.get_all_open_interest("BTC")
total = sum(float(oi.oi_usd) for oi in oi_list)
for oi in sorted(oi_list, key=lambda x: x.oi_usd, reverse=True):
share = float(oi.oi_usd) / total * 100
print(f" {oi.exchange:<10} ${float(oi.oi_usd)/1e9:.1f}B | "
f"24h: {oi.change_24h_pct:+.1f}% | Share: {share:.1f}%")
# Basis
print("\n💱 BTC Basis:")
basis = client.get_basis_data("BTC")
print(f" Spot: ${basis.spot_price:,.2f}")
print(f" Perp: ${basis.perp_price:,.2f} ({basis.perp_basis_pct:+.3f}%)")
print(f" Quarterly: ${basis.quarterly_price:,.2f} ({basis.quarterly_basis_pct:+.3f}%)")
print(f" Annualized: {basis.annualized_yield:+.2f}%")
if __name__ == "__main__":
demo()
#!/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()
Related skills
FAQ
Which exchanges does it cover?
Perpetual swaps on Binance, Bybit, OKX, Deribit, and BitMEX, options primarily on Deribit, and DEX perpetuals on dYdX, GMX, and Drift.
What derivatives metrics does it report?
Funding rates, open interest, liquidations, options flow with put/call ratio and max pain, and spot-perp or quarterly basis.