@intentsolutionsio/crypto-derivatives-tracker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +22 -0
- package/LICENSE +21 -0
- package/README.md +173 -0
- package/agents/derivatives-agent.md +408 -0
- package/package.json +43 -0
- package/skills/skill-adapter/assets/README.md +6 -0
- package/skills/skill-adapter/assets/config-template.json +32 -0
- package/skills/skill-adapter/assets/skill-schema.json +28 -0
- package/skills/skill-adapter/assets/test-data.json +27 -0
- package/skills/skill-adapter/references/README.md +4 -0
- package/skills/skill-adapter/references/best-practices.md +69 -0
- package/skills/skill-adapter/references/examples.md +73 -0
- package/skills/skill-adapter/scripts/README.md +8 -0
- package/skills/skill-adapter/scripts/helper-template.sh +42 -0
- package/skills/skill-adapter/scripts/validation.sh +32 -0
- package/skills/tracking-crypto-derivatives/ARD.md +376 -0
- package/skills/tracking-crypto-derivatives/PRD.md +258 -0
- package/skills/tracking-crypto-derivatives/SKILL.md +127 -0
- package/skills/tracking-crypto-derivatives/config/settings.yaml +152 -0
- package/skills/tracking-crypto-derivatives/references/errors.md +224 -0
- package/skills/tracking-crypto-derivatives/references/examples.md +460 -0
- package/skills/tracking-crypto-derivatives/references/implementation.md +113 -0
- package/skills/tracking-crypto-derivatives/scripts/basis_calculator.py +377 -0
- package/skills/tracking-crypto-derivatives/scripts/derivatives_tracker.py +579 -0
- package/skills/tracking-crypto-derivatives/scripts/formatters.py +459 -0
- package/skills/tracking-crypto-derivatives/scripts/funding_tracker.py +308 -0
- package/skills/tracking-crypto-derivatives/scripts/liquidation_monitor.py +356 -0
- package/skills/tracking-crypto-derivatives/scripts/oi_analyzer.py +338 -0
- package/skills/tracking-crypto-derivatives/scripts/options_analyzer.py +373 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Tracking Crypto Derivatives - Implementation Reference
|
|
2
|
+
|
|
3
|
+
## Detailed Output Formats
|
|
4
|
+
|
|
5
|
+
### Funding Rate Report
|
|
6
|
+
```
|
|
7
|
+
BTC PERPETUAL FUNDING RATES
|
|
8
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
9
|
+
Exchange Current 24h Avg 7d Avg Next Payment
|
|
10
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
11
|
+
Binance +0.0150% +0.0120% +0.0080% 2h 15m
|
|
12
|
+
Bybit +0.0180% +0.0140% +0.0100% 2h 15m
|
|
13
|
+
OKX +0.0130% +0.0110% +0.0090% 2h 15m
|
|
14
|
+
Deribit +0.0200% +0.0150% +0.0120% 2h 15m
|
|
15
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
16
|
+
Weighted Avg: +0.0158% | Annualized: +17.29%
|
|
17
|
+
Sentiment: Moderately Bullish
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Open Interest Report
|
|
21
|
+
```
|
|
22
|
+
BTC OPEN INTEREST ANALYSIS
|
|
23
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
24
|
+
Exchange OI (USD) 24h Chg 7d Chg Share
|
|
25
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
26
|
+
Binance $8.2B +2.5% +8.1% 44.3%
|
|
27
|
+
Bybit $4.5B +1.8% +5.2% 24.3%
|
|
28
|
+
OKX $3.1B +3.2% +12.5% 16.8%
|
|
29
|
+
BitMEX $1.5B -0.5% -2.1% 8.1%
|
|
30
|
+
Deribit $1.2B +0.8% +3.4% 6.5%
|
|
31
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
32
|
+
Total OI: $18.5B (+2.3% 24h)
|
|
33
|
+
Long/Short Ratio: 1.15 (53.5% long)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Liquidation Heatmap
|
|
37
|
+
```
|
|
38
|
+
BTC LIQUIDATION LEVELS
|
|
39
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
40
|
+
Current Price: $67,500
|
|
41
|
+
|
|
42
|
+
LONG LIQUIDATIONS (below):
|
|
43
|
+
$65,000 ████████████ $125M (HIGH DENSITY)
|
|
44
|
+
$62,500 ███████ $85M
|
|
45
|
+
$60,000 ████████████████████ $210M (CRITICAL)
|
|
46
|
+
|
|
47
|
+
SHORT LIQUIDATIONS (above):
|
|
48
|
+
$70,000 █████████ $95M
|
|
49
|
+
$72,500 █████████████ $145M (HIGH DENSITY)
|
|
50
|
+
$75,000 █████████████████ $180M
|
|
51
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
52
|
+
24h Liquidations: Longs $45.2M | Shorts $32.8M
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Options Analysis Deep Dive
|
|
56
|
+
|
|
57
|
+
### Options Commands
|
|
58
|
+
```bash
|
|
59
|
+
# Get options overview
|
|
60
|
+
python derivatives_tracker.py options BTC
|
|
61
|
+
|
|
62
|
+
# Show put/call ratio
|
|
63
|
+
python derivatives_tracker.py options BTC --pcr
|
|
64
|
+
|
|
65
|
+
# Find max pain for expiry
|
|
66
|
+
python derivatives_tracker.py options BTC --expiry 2025-01-31
|
|
67
|
+
|
|
68
|
+
# Track large options trades
|
|
69
|
+
python derivatives_tracker.py options BTC --flow
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Options Insights
|
|
73
|
+
- **High IV rank** (>80): Options expensive, consider selling
|
|
74
|
+
- **Low IV rank** (<20): Options cheap, consider buying
|
|
75
|
+
- **Max pain**: Price where most options expire worthless
|
|
76
|
+
|
|
77
|
+
## Basis Trading Guide
|
|
78
|
+
|
|
79
|
+
### Basis Commands
|
|
80
|
+
```bash
|
|
81
|
+
# Get spot-perp basis
|
|
82
|
+
python derivatives_tracker.py basis BTC
|
|
83
|
+
|
|
84
|
+
# Get quarterly futures basis
|
|
85
|
+
python derivatives_tracker.py basis BTC --quarterly
|
|
86
|
+
|
|
87
|
+
# Show all basis opportunities
|
|
88
|
+
python derivatives_tracker.py basis --all
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Basis Trading Interpretation
|
|
92
|
+
- **Positive basis**: Futures > Spot (contango, normal)
|
|
93
|
+
- **Negative basis**: Futures < Spot (backwardation)
|
|
94
|
+
- **Cash-and-carry**: Buy spot + sell futures when basis high
|
|
95
|
+
|
|
96
|
+
## Key Concepts
|
|
97
|
+
|
|
98
|
+
- **Funding Rate**: Payment between longs/shorts every 8h
|
|
99
|
+
- **Open Interest**: Total outstanding contracts
|
|
100
|
+
- **Basis**: Difference between futures and spot price
|
|
101
|
+
- **Max Pain**: Strike where most options expire worthless
|
|
102
|
+
- **IV Rank**: Current IV percentile vs historical
|
|
103
|
+
|
|
104
|
+
## Risk Warning
|
|
105
|
+
|
|
106
|
+
Derivatives are leveraged instruments with high risk of loss.
|
|
107
|
+
- Funding costs accumulate over time
|
|
108
|
+
- Liquidations can happen rapidly
|
|
109
|
+
- Options can expire worthless
|
|
110
|
+
- This tool provides analysis only, not financial advice
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
*[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Basis and spread calculator.
|
|
4
|
+
|
|
5
|
+
Calculates futures basis and spreads with:
|
|
6
|
+
- Spot-futures basis tracking
|
|
7
|
+
- Annualized basis yield
|
|
8
|
+
- Term structure analysis
|
|
9
|
+
- Contango/backwardation detection
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from decimal import Decimal
|
|
14
|
+
from typing import Dict, List, Optional
|
|
15
|
+
from datetime import datetime, date
|
|
16
|
+
|
|
17
|
+
from exchange_client import ExchangeClient, BasisData, Exchange
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class BasisAnalysis:
|
|
22
|
+
"""Comprehensive basis analysis."""
|
|
23
|
+
|
|
24
|
+
symbol: str
|
|
25
|
+
spot_price: Decimal
|
|
26
|
+
basis_data: List[BasisData]
|
|
27
|
+
avg_basis_pct: float
|
|
28
|
+
avg_annualized: float
|
|
29
|
+
market_structure: str # "contango", "backwardation", "mixed"
|
|
30
|
+
structure_strength: str # "strong", "moderate", "weak"
|
|
31
|
+
best_carry_expiry: Optional[str]
|
|
32
|
+
best_carry_yield: float
|
|
33
|
+
timestamp: datetime
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class CarryOpportunity:
|
|
38
|
+
"""Cash-and-carry arbitrage opportunity."""
|
|
39
|
+
|
|
40
|
+
symbol: str
|
|
41
|
+
exchange: str
|
|
42
|
+
expiry: str
|
|
43
|
+
spot_price: Decimal
|
|
44
|
+
futures_price: Decimal
|
|
45
|
+
basis_pct: float
|
|
46
|
+
days_to_expiry: int
|
|
47
|
+
annualized_yield: float
|
|
48
|
+
direction: str # "long_basis" or "short_basis"
|
|
49
|
+
strategy: str # Trade description
|
|
50
|
+
risk_notes: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class BasisCalculator:
|
|
54
|
+
"""
|
|
55
|
+
Calculates and analyzes futures basis.
|
|
56
|
+
|
|
57
|
+
Features:
|
|
58
|
+
- Multi-expiry analysis
|
|
59
|
+
- Term structure visualization
|
|
60
|
+
- Carry trade identification
|
|
61
|
+
- Contango/backwardation detection
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
# Structure interpretation
|
|
65
|
+
STRONG_BASIS = 5.0 # >5% annualized is strong
|
|
66
|
+
MODERATE_BASIS = 2.0 # >2% is moderate
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
client: Optional[ExchangeClient] = None,
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Initialize basis calculator.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
client: Exchange client for data fetching
|
|
77
|
+
"""
|
|
78
|
+
self.client = client or ExchangeClient(use_mock=True)
|
|
79
|
+
|
|
80
|
+
def analyze(
|
|
81
|
+
self,
|
|
82
|
+
symbol: str,
|
|
83
|
+
spot_price: Optional[Decimal] = None,
|
|
84
|
+
exchanges: Optional[List[Exchange]] = None,
|
|
85
|
+
) -> BasisAnalysis:
|
|
86
|
+
"""
|
|
87
|
+
Analyze basis for a symbol.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
symbol: Trading symbol (e.g., "BTC")
|
|
91
|
+
spot_price: Current spot price
|
|
92
|
+
exchanges: Exchanges to include
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
BasisAnalysis with all metrics
|
|
96
|
+
"""
|
|
97
|
+
# Set default spot price if not provided
|
|
98
|
+
if spot_price is None:
|
|
99
|
+
if symbol == "BTC":
|
|
100
|
+
spot_price = Decimal("67500")
|
|
101
|
+
elif symbol == "ETH":
|
|
102
|
+
spot_price = Decimal("2500")
|
|
103
|
+
else:
|
|
104
|
+
spot_price = Decimal("100")
|
|
105
|
+
|
|
106
|
+
# Fetch basis data
|
|
107
|
+
basis_list = self.client.get_all_basis(symbol, spot_price, exchanges)
|
|
108
|
+
|
|
109
|
+
if not basis_list:
|
|
110
|
+
raise ValueError(f"No basis data available for {symbol}")
|
|
111
|
+
|
|
112
|
+
# Calculate averages
|
|
113
|
+
avg_basis = sum(b.basis_pct for b in basis_list) / len(basis_list)
|
|
114
|
+
avg_annual = sum(b.annualized_pct for b in basis_list) / len(basis_list)
|
|
115
|
+
|
|
116
|
+
# Determine market structure
|
|
117
|
+
structure, strength = self._analyze_structure(basis_list)
|
|
118
|
+
|
|
119
|
+
# Find best carry opportunity
|
|
120
|
+
best_carry = max(basis_list, key=lambda b: b.annualized_pct)
|
|
121
|
+
|
|
122
|
+
return BasisAnalysis(
|
|
123
|
+
symbol=symbol,
|
|
124
|
+
spot_price=spot_price,
|
|
125
|
+
basis_data=basis_list,
|
|
126
|
+
avg_basis_pct=round(avg_basis, 3),
|
|
127
|
+
avg_annualized=round(avg_annual, 2),
|
|
128
|
+
market_structure=structure,
|
|
129
|
+
structure_strength=strength,
|
|
130
|
+
best_carry_expiry=best_carry.expiry,
|
|
131
|
+
best_carry_yield=best_carry.annualized_pct,
|
|
132
|
+
timestamp=datetime.now(),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def _analyze_structure(
|
|
136
|
+
self,
|
|
137
|
+
basis_list: List[BasisData],
|
|
138
|
+
) -> tuple:
|
|
139
|
+
"""
|
|
140
|
+
Analyze term structure from basis data.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
(structure, strength) tuple
|
|
144
|
+
"""
|
|
145
|
+
positive = sum(1 for b in basis_list if b.basis_pct > 0)
|
|
146
|
+
negative = sum(1 for b in basis_list if b.basis_pct < 0)
|
|
147
|
+
total = len(basis_list)
|
|
148
|
+
|
|
149
|
+
# Determine structure
|
|
150
|
+
if positive == total:
|
|
151
|
+
structure = "contango"
|
|
152
|
+
elif negative == total:
|
|
153
|
+
structure = "backwardation"
|
|
154
|
+
elif positive > negative:
|
|
155
|
+
structure = "contango" # Mostly contango
|
|
156
|
+
elif negative > positive:
|
|
157
|
+
structure = "backwardation"
|
|
158
|
+
else:
|
|
159
|
+
structure = "mixed"
|
|
160
|
+
|
|
161
|
+
# Determine strength from magnitude
|
|
162
|
+
avg_abs = sum(abs(b.annualized_pct) for b in basis_list) / total
|
|
163
|
+
if avg_abs >= self.STRONG_BASIS:
|
|
164
|
+
strength = "strong"
|
|
165
|
+
elif avg_abs >= self.MODERATE_BASIS:
|
|
166
|
+
strength = "moderate"
|
|
167
|
+
else:
|
|
168
|
+
strength = "weak"
|
|
169
|
+
|
|
170
|
+
return structure, strength
|
|
171
|
+
|
|
172
|
+
def find_carry_opportunities(
|
|
173
|
+
self,
|
|
174
|
+
symbols: List[str],
|
|
175
|
+
min_yield: float = 5.0,
|
|
176
|
+
) -> List[CarryOpportunity]:
|
|
177
|
+
"""
|
|
178
|
+
Find cash-and-carry arbitrage opportunities.
|
|
179
|
+
|
|
180
|
+
Strategy:
|
|
181
|
+
- Contango: Buy spot, sell futures, collect basis
|
|
182
|
+
- Backwardation: Sell spot (if possible), buy futures
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
symbols: Symbols to scan
|
|
186
|
+
min_yield: Minimum annualized yield (%)
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
List of carry opportunities
|
|
190
|
+
"""
|
|
191
|
+
opportunities = []
|
|
192
|
+
|
|
193
|
+
for symbol in symbols:
|
|
194
|
+
try:
|
|
195
|
+
analysis = self.analyze(symbol)
|
|
196
|
+
|
|
197
|
+
for basis in analysis.basis_data:
|
|
198
|
+
if abs(basis.annualized_pct) >= min_yield:
|
|
199
|
+
if basis.basis_pct > 0:
|
|
200
|
+
# Contango - long basis trade
|
|
201
|
+
direction = "long_basis"
|
|
202
|
+
strategy = (
|
|
203
|
+
f"Buy {symbol} spot at ${float(analysis.spot_price):,.0f}, "
|
|
204
|
+
f"sell {basis.expiry} futures at ${float(basis.futures_price):,.0f}"
|
|
205
|
+
)
|
|
206
|
+
risk_notes = "Funding costs may reduce yield; early liquidation risk"
|
|
207
|
+
else:
|
|
208
|
+
# Backwardation - short basis trade
|
|
209
|
+
direction = "short_basis"
|
|
210
|
+
strategy = (
|
|
211
|
+
f"Short {symbol} spot (borrow), "
|
|
212
|
+
f"buy {basis.expiry} futures at ${float(basis.futures_price):,.0f}"
|
|
213
|
+
)
|
|
214
|
+
risk_notes = "Borrowing costs apply; squeeze risk in tight markets"
|
|
215
|
+
|
|
216
|
+
opportunities.append(CarryOpportunity(
|
|
217
|
+
symbol=symbol,
|
|
218
|
+
exchange=basis.exchange,
|
|
219
|
+
expiry=basis.expiry,
|
|
220
|
+
spot_price=analysis.spot_price,
|
|
221
|
+
futures_price=basis.futures_price,
|
|
222
|
+
basis_pct=basis.basis_pct,
|
|
223
|
+
days_to_expiry=basis.days_to_expiry,
|
|
224
|
+
annualized_yield=basis.annualized_pct,
|
|
225
|
+
direction=direction,
|
|
226
|
+
strategy=strategy,
|
|
227
|
+
risk_notes=risk_notes,
|
|
228
|
+
))
|
|
229
|
+
except Exception:
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
# Sort by yield descending
|
|
233
|
+
opportunities.sort(key=lambda x: abs(x.annualized_yield), reverse=True)
|
|
234
|
+
return opportunities
|
|
235
|
+
|
|
236
|
+
def get_term_structure(
|
|
237
|
+
self,
|
|
238
|
+
symbol: str,
|
|
239
|
+
spot_price: Optional[Decimal] = None,
|
|
240
|
+
) -> List[Dict]:
|
|
241
|
+
"""
|
|
242
|
+
Get term structure data for visualization.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
symbol: Trading symbol
|
|
246
|
+
spot_price: Current spot price
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
List of expiry data points
|
|
250
|
+
"""
|
|
251
|
+
analysis = self.analyze(symbol, spot_price)
|
|
252
|
+
|
|
253
|
+
# Sort by days to expiry
|
|
254
|
+
sorted_basis = sorted(
|
|
255
|
+
analysis.basis_data,
|
|
256
|
+
key=lambda b: b.days_to_expiry
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
return [
|
|
260
|
+
{
|
|
261
|
+
"expiry": b.expiry,
|
|
262
|
+
"days": b.days_to_expiry,
|
|
263
|
+
"futures_price": float(b.futures_price),
|
|
264
|
+
"basis_pct": b.basis_pct,
|
|
265
|
+
"annualized_pct": b.annualized_pct,
|
|
266
|
+
"exchange": b.exchange,
|
|
267
|
+
}
|
|
268
|
+
for b in sorted_basis
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
def calculate_implied_rate(
|
|
272
|
+
self,
|
|
273
|
+
spot: Decimal,
|
|
274
|
+
futures: Decimal,
|
|
275
|
+
days: int,
|
|
276
|
+
) -> Dict:
|
|
277
|
+
"""
|
|
278
|
+
Calculate implied interest rate from basis.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
spot: Spot price
|
|
282
|
+
futures: Futures price
|
|
283
|
+
days: Days to expiry
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Dict with rate calculations
|
|
287
|
+
"""
|
|
288
|
+
if days <= 0:
|
|
289
|
+
return {"error": "Days must be positive"}
|
|
290
|
+
|
|
291
|
+
basis = float(futures - spot)
|
|
292
|
+
basis_pct = basis / float(spot) * 100
|
|
293
|
+
annualized = basis_pct * 365 / days
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
"spot": float(spot),
|
|
297
|
+
"futures": float(futures),
|
|
298
|
+
"days_to_expiry": days,
|
|
299
|
+
"basis_usd": round(basis, 2),
|
|
300
|
+
"basis_pct": round(basis_pct, 3),
|
|
301
|
+
"annualized_rate": round(annualized, 2),
|
|
302
|
+
"structure": "contango" if basis > 0 else "backwardation",
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def demo():
|
|
307
|
+
"""Demonstrate basis calculator."""
|
|
308
|
+
calc = BasisCalculator()
|
|
309
|
+
|
|
310
|
+
print("=" * 70)
|
|
311
|
+
print("BASIS CALCULATOR")
|
|
312
|
+
print("=" * 70)
|
|
313
|
+
|
|
314
|
+
# Analyze BTC basis
|
|
315
|
+
analysis = calc.analyze("BTC", Decimal("67500"))
|
|
316
|
+
|
|
317
|
+
print(f"\n📈 {analysis.symbol} BASIS ANALYSIS")
|
|
318
|
+
print(f" Spot Price: ${analysis.spot_price:,}")
|
|
319
|
+
print("-" * 60)
|
|
320
|
+
|
|
321
|
+
print(f"\n{'Expiry':<12} {'Futures':>12} {'Basis':>10} {'Annual':>10} {'Days':>6}")
|
|
322
|
+
print("-" * 60)
|
|
323
|
+
|
|
324
|
+
for basis in sorted(analysis.basis_data, key=lambda b: b.days_to_expiry):
|
|
325
|
+
print(
|
|
326
|
+
f"{basis.expiry:<12} "
|
|
327
|
+
f"${float(basis.futures_price):>10,.0f} "
|
|
328
|
+
f"{basis.basis_pct:>+9.2f}% "
|
|
329
|
+
f"{basis.annualized_pct:>+9.1f}% "
|
|
330
|
+
f"{basis.days_to_expiry:>6}"
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
print("-" * 60)
|
|
334
|
+
print(f"\nMarket Structure: {analysis.structure_strength.title()} {analysis.market_structure.title()}")
|
|
335
|
+
print(f"Average Basis: {analysis.avg_basis_pct:+.2f}%")
|
|
336
|
+
print(f"Average Annualized: {analysis.avg_annualized:+.1f}%")
|
|
337
|
+
print(f"Best Carry: {analysis.best_carry_expiry} ({analysis.best_carry_yield:+.1f}% annualized)")
|
|
338
|
+
|
|
339
|
+
# Term structure
|
|
340
|
+
print("\n" + "-" * 60)
|
|
341
|
+
print("TERM STRUCTURE")
|
|
342
|
+
print("-" * 60)
|
|
343
|
+
|
|
344
|
+
structure = calc.get_term_structure("BTC", Decimal("67500"))
|
|
345
|
+
for point in structure:
|
|
346
|
+
bar = "+" * min(int(abs(point["annualized_pct"]) / 2), 20)
|
|
347
|
+
direction = "▲" if point["annualized_pct"] > 0 else "▼"
|
|
348
|
+
print(f"{point['expiry']:<12} {direction} {bar} {point['annualized_pct']:+.1f}%")
|
|
349
|
+
|
|
350
|
+
# Carry opportunities
|
|
351
|
+
print("\n" + "=" * 70)
|
|
352
|
+
print("CARRY TRADE SCANNER")
|
|
353
|
+
print("=" * 70)
|
|
354
|
+
|
|
355
|
+
opportunities = calc.find_carry_opportunities(["BTC", "ETH"], min_yield=5.0)
|
|
356
|
+
if opportunities:
|
|
357
|
+
print(f"\n{'Symbol':<6} {'Expiry':<12} {'Basis':>8} {'Annual':>10} {'Direction':<12}")
|
|
358
|
+
print("-" * 60)
|
|
359
|
+
for opp in opportunities[:5]:
|
|
360
|
+
print(
|
|
361
|
+
f"{opp.symbol:<6} "
|
|
362
|
+
f"{opp.expiry:<12} "
|
|
363
|
+
f"{opp.basis_pct:>+7.2f}% "
|
|
364
|
+
f"{opp.annualized_yield:>+9.1f}% "
|
|
365
|
+
f"{opp.direction:<12}"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
print("\nTop Opportunity:")
|
|
369
|
+
top = opportunities[0]
|
|
370
|
+
print(f" Strategy: {top.strategy}")
|
|
371
|
+
print(f" Risk: {top.risk_notes}")
|
|
372
|
+
else:
|
|
373
|
+
print("\nNo carry opportunities found above threshold")
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
if __name__ == "__main__":
|
|
377
|
+
demo()
|