作为一名量化交易开发者 habe ich 在过去三年中构建了多个期权分析系统。Die Wahl der richtigen Datenquelle ist dabei entscheidend für die Qualität Ihrer Modelle. In diesem Praxistest zeige ich Ihnen, wie Sie mit Tardis.dev Deribit BTC-Optionsdaten in CSV-Format herunterladen und anschließend mit KI-Unterstützung komplexe Volatilitätsflächen und Backtesting-Pipelines aufbauen.
为什么选择Tardis.dev?数据源对比
Deribit ist der dominierende Bitcoin-Optionsmarkt mit über 90% Open Interest. Bevor wir in die technische Implementierung einsteigen, lassen Sie mich die wichtigsten Datenquellen vergleichen:
| Anbieter | Datenformat | Latenz | Historische Tiefe | Preis/Monat | BTC-Optionen |
|---|---|---|---|---|---|
| Tardis.dev | CSV, JSON, Parquet | <100ms | 2018-heute | $99 | ✓ Vollständig |
| Deribit Direct API | JSON | <50ms | 30 Tage | Kostenlos (limitiert) | ✓ Vollständig |
| CoinMetrics | CSV | >24h | 2013-heute | $500+ | Begrenzt |
| IntoTheBlock | JSON | >1h | 1 Jahr | $150 | Teilweise |
前提条件和环境设置
Für dieses Tutorial benötigen Sie:
- Python 3.10+ mit pandas, numpy, scipy
- Tardis.dev API-Key (kostenloser Starter-Plan verfügbar)
- Optional: HolySheep AI für KI-gestützte Datenanalyse
- 8GB RAM minimum für Volatilitätsberechnungen
# Erforderliche Pakete installieren
pip install pandas numpy scipy requests asyncio aiohttp
Tardis.dev Python Client
pip install tardis-client
Für die KI-Analyse mit HolySheep
pip install openai # Kompatibel mit HolySheep API
Schritt 1: Tardis.dev API konfigurieren
Tardis.dev bietet eine hervorragende REST-API mit Streaming-Unterstützung. Für die historische Datenextraktion empfehle ich den synchronen Ansatz mit Chunk-Downloads.
import os
import pandas as pd
import requests
from datetime import datetime, timedelta
import time
============== KONFIGURATION ==============
TARDIS_API_KEY = os.environ.get('TARDIS_API_KEY', 'your_tardis_api_key')
BASE_URL = 'https://api.tardis.dev/v1'
HolySheep AI für nachgelagerte KI-Analyse
HOLYSHEEP_API_KEY = 'YOUR_HOLYSHEEP_API_KEY' # Holen Sie sich Ihren Key
HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1'
TradingView-kompatibles Zeitformat
DATE_FORMAT = '%Y-%m-%d'
def get_deribit_options_history(start_date: str, end_date: str, exchange: str = 'deribit'):
"""
Lädt historische BTC-Optionsdaten von Tardis.dev herunter
Args:
start_date: ISO-Datum (YYYY-MM-DD)
end_date: ISO-Datum (YYYY-MM-DD)
exchange: Börsenkürzel (default: 'deribit')
Returns:
DataFrame mit OHLCV-Daten und Greeks
"""
url = f"{BASE_URL}/exported/{exchange}/historical/options"
params = {
'api_key': TARDIS_API_KEY,
'date_from': start_date,
'date_to': end_date,
'format': 'csv',
'data_type': 'trades' # trades, quotes, oder Greeks
}
print(f"📡 Anfrage an Tardis.dev: {start_date} bis {end_date}")
start_time = time.time()
response = requests.get(url, params=params, timeout=300)
if response.status_code == 200:
latency_ms = (time.time() - start_time) * 1000
print(f"✅ Download erfolgreich in {latency_ms:.0f}ms")
return response.content.decode('utf-8')
else:
print(f"❌ Fehler {response.status_code}: {response.text}")
return None
Beispiel: Lade letzte 7 Tage BTC-Optionsdaten
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
csv_data = get_deribit_options_history(
start_date.strftime(DATE_FORMAT),
end_date.strftime(DATE_FORMAT)
)
Schritt 2: CSV-Daten parsen und aufbereiten
Die von Tardis.dev gelieferten CSV-Daten enthalten Trades, Quotes und optional Greeks. Für die Volatilitätsflächen-Berechnung müssen wir die Daten restructurieren.
import io
from typing import Dict, List
from dataclasses import dataclass
@dataclass
class OptionContract:
"""Struktur für einzelne Optionskontrakte"""
symbol: str
expiry: datetime
strike: float
option_type: str # 'call' oder 'put'
mark_price: float
iv: float
delta: float
gamma: float
theta: float
vega: float
def parse_tardis_csv(csv_content: str) -> pd.DataFrame:
"""
Parst Tardis.dev CSV und extrahiert relevante Felder für Volatilitätsanalyse
Erwartete CSV-Spalten von Tardis.dev:
timestamp, symbol, side, price, size, best_bid_price, best_ask_price,
best_bid_amount, best_ask_amount, index_price, mark_price,
open_interest, timestamp
"""
df = pd.read_csv(io.StringIO(csv_content))
# Konvertiere Timestamp zu datetime
df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms')
# Extrahiere Strike undExpiry aus Symbol
# Format: BTC-YYYYMMDD-STRIKE-C/P
def parse_symbol(symbol: str) -> Dict:
parts = symbol.split('-')
expiry_str = parts[1]
strike = float(parts[2])
option_type = 'call' if parts[3] == 'C' else 'put'
expiry = datetime.strptime(expiry_str, '%y%m%d')
return {'strike': strike, 'expiry': expiry, 'option_type': option_type}
parsed = df['symbol'].apply(parse_symbol).apply(pd.Series)
df = pd.concat([df, parsed], axis=1)
# Berechne implizite Volatilität aus Mark Price (vereinfachtes Modell)
# Für exakte IV-Berechnung: Verwenden Sie scipy.optimize.newton
df['days_to_expiry'] = (df['expiry'] - df['datetime']).dt.days
df['iv_approx'] = df['mark_price'] / (df['strike'] * 0.3) * np.sqrt(365 / df['days_to_expiry'])
print(f"📊 {len(df)} Optionsdaten geladen")
print(f"📅 Zeitraum: {df['datetime'].min()} bis {df['datetime'].max()}")
print(f"💰 Strike-Range: ${df['strike'].min():,.0f} - ${df['strike'].max():,.0f}")
return df
Parst die Daten
df_options = parse_tardis_csv(csv_data)
Zeige Stichprobe
print(df_options[['datetime', 'symbol', 'strike', 'option_type', 'mark_price', 'iv_approx']].head(10))
Schritt 3: Volatilitätsfläche berechnen
Die Volatility Surface ist das Herzstück jeder Optionsanalyse. Wir erstellen eine 3D-Visualisierung mit Strike-Preisen auf der X-Achse, Zeiträumen auf der Y-Achse und impliziter Volatilität auf der Z-Achse.
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def build_volatility_surface(df: pd.DataFrame, reference_date: datetime = None) -> Dict:
"""
Erstellt eine Volatilitätsfläche aus Optionsdaten
Returns:
Dictionary mit Gitterpunkten für 3D-Plot
"""
if reference_date is None:
reference_date = df['datetime'].max()
# Filtere Daten nach Tagen bis Expiry
df_filtered = df[df['days_to_expiry'] > 0].copy()
# moneyness = strike / spot
spot_price = df_filtered['index_price'].iloc[-1]
df_filtered['moneyness'] = df_filtered['strike'] / spot_price
# Gruppiere nach Strike und Expiry
vol_surface = df_filtered.groupby(['strike', 'days_to_expiry']).agg({
'iv_approx': 'mean',
'mark_price': 'mean'
}).reset_index()
# Erstelle Interpolationsgitter
strikes = vol_surface['strike'].unique()
expirys = sorted(vol_surface['days_to_expiry'].unique())
X, Y = np.meshgrid(strikes, expirys)
Z = np.zeros_like(X, dtype=float)
for i, expiry in enumerate(expirys):
for j, strike in enumerate(strikes):
mask = (vol_surface['strike'] == strike) & (vol_surface['days_to_expiry'] == expiry)
if mask.any():
Z[i, j] = vol_surface.loc[mask, 'iv_approx'].values[0]
else:
Z[i, j] = np.nan
# Interpolation für fehlende Werte
valid_mask = ~np.isnan(Z)
coords = np.array(np.where(valid_mask)).T
values = Z[valid_mask]
if len(coords) > 0:
Z_interp = griddata(coords, values, (X, Y), method='cubic')
Z = np.nan_to_num(Z_interp, nan=np.nanmean(Z))
print(f"📐 Volatilitätsfläche erstellt: {len(strikes)} Strikes × {len(expirys)} Expirys")
print(f"💹 Spot-Preis: ${spot_price:,.0f}")
print(f"📊 IV-Range: {np.nanmin(Z)*100:.1f}% - {np.nanmax(Z)*100:.1f}%")
return {
'strikes': X,
'expirys': Y,
'iv_matrix': Z,
'spot': spot_price,
'moneyness': strikes / spot_price
}
Berechne Volatilitätsfläche
vol_surface = build_volatility_surface(df_options)
3D Visualisierung
fig = plt.figure(figsize=(14, 8))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(
vol_surface['strikes'] / vol_surface['spot'],
vol_surface['expirys'],
vol_surface['iv_matrix'] * 100,
cmap='viridis', alpha=0.8
)
ax.set_xlabel('Moneyness (Strike/Spot)')
ax.set_ylabel('Tage bis Expiry')
ax.set_zlabel('Implizite Volatilität (%)')
ax.set_title('BTC-Optionen Volatilitätsfläche - Deribit')
fig.colorbar(surf, label='IV (%)')
plt.savefig('volatility_surface.png', dpi=150)
plt.show()
Schritt 4: KI-gestützte Strategieanalyse mit HolySheep
Nach der Datenaufbereitung können wir HolySheep AI für die automatisierte Strategieanalyse nutzen. Die API bietet <50ms Latenz und unterstützt WeChat/Alipay-Zahlung für asiatische Nutzer.
import json
import openai
from typing import List, Dict
HolySheep AI Client konfigurieren
client = openai.OpenAI(
api_key=HOLYSHEEP_API_KEY,
base_url=HOLYSHEEP_BASE_URL
)
def analyze_options_strategy(vol_surface: Dict, historical_data: pd.DataFrame) -> Dict:
"""
Verwendet KI zur Analyse von Optionsstrategien basierend auf der Volatilitätsfläche
Nutzt HolySheep AI mit GPT-4.1 für analytische推理
Preis: $8/1M Tokens (85%+ günstiger als OpenAI)
"""
# Bereite Kontext für KI vor
spot = vol_surface['spot']
min_strike = vol_surface['strikes'].min()
max_strike = vol_surface['strikes'].max()
avg_iv = np.nanmean(vol_surface['iv_matrix']) * 100
# Erstelle Zusammenfassung der Volatilitätsfläche
summary_prompt = f"""
Analysiere die folgende BTC-Optionen Volatilitätsfläche:
Aktueller Spot-Preis: ${spot:,.0f}
Strike-Range: ${min_strike:,.0f} - ${max_strike:,.0f}
Durchschnittliche IV: {avg_iv:.1f}%
Basierend auf der Volatilitätsstruktur:
1. Identifiziere optimale Strike-Preise für Covered Calls
2. Berechne Risiko/Rendite-Profil für Straddles
3. Empfehle Zeitrahmen basierend auf der IV-Termstruktur
Antworte im JSON-Format mit strategisties Analysis.
"""
# Anfrage an HolySheep GPT-4.1
response = client.chat.completions.create(
model='gpt-4.1',
messages=[
{'role': 'system', 'content': 'Du bist ein erfahrener Optionshändler mit Fokus auf Deribit BTC-Optionen.'},
{'role': 'user', 'content': summary_prompt}
],
response_format={'type': 'json_object'},
temperature=0.3
)
# Token-Zählung für Kostenanalyse
input_tokens = response.usage.prompt_tokens
output_tokens = response.usage.completion_tokens
total_tokens = response.usage.total_tokens
# Kostenberechnung (HolySheep 2026 Preise)
cost_per_million = 8.00 # GPT-4.1
estimated_cost = (total_tokens / 1_000_000) * cost_per_million
print(f"🤖 KI-Analyse abgeschlossen")
print(f"📝 Token: {total_tokens:,} (Input: {input_tokens:,}, Output: {output_tokens:,})")
print(f"💰 Geschätzte Kosten: ${estimated_cost:.4f}")
return {
'analysis': json.loads(response.choices[0].message.content),
'token_usage': {
'input': input_tokens,
'output': output_tokens,
'total': total_tokens
},
'cost_usd': estimated_cost
}
Führe KI-Analyse durch
result = analyze_options_strategy(vol_surface, df_options)
print(json.dumps(result['analysis'], indent=2))
Schritt 5: Backtesting-Pipeline
Jetzt integrieren wir alles in eine vollständige Backtesting-Pipeline, die Signale generiert, Positionen verwaltet und Performance-Metriken berechnet.
from dataclasses import dataclass, field
from typing import Optional
from enum import Enum
class StrategyType(Enum):
SHORT_STRADDLE = 'short_straddle'
IRON_CONDOR = 'iron_condor'
COVERED_CALL = 'covered_call'
PROTECTIVE_PUT = 'protective_put'
@dataclass
class BacktestResult:
"""Speichert Backtesting-Ergebnisse"""
strategy: StrategyType
entry_date: datetime
exit_date: datetime
entry_iv: float
exit_iv: float
pnl: float
max_drawdown: float
sharpe_ratio: float
win_rate: float
def run_backtest(
df: pd.DataFrame,
strategy: StrategyType,
capital: float = 100_000,
iv_threshold_high: float = 0.80,
iv_threshold_low: float = 0.40
) -> List[BacktestResult]:
"""
Führt Backtesting für Optionsstrategien durch
Parameters:
df: DataFrame mit Optionsdaten
strategy: Strategietyp
capital: Starting Capital in USD
iv_threshold_high: IV-Perzentil für Signalgenerierung
iv_threshold_low: IV-Perzentil für Take-Profit
"""
results = []
position = None
capital_history = [capital]
for idx, row in df.iterrows():
current_iv = row['iv_approx']
current_price = row['mark_price']
if position is None:
# Einstiegssignal basierend auf IV
if current_iv > iv_threshold_high:
# Eröffne Position
position = {
'entry_iv': current_iv,
'entry_price': current_price,
'entry_date': row['datetime'],
'strike': row['strike'],
'option_type': row['option_type']
}
print(f"📈 Einstieg: {row['datetime']} | IV: {current_iv:.2%} | Strike: ${row['strike']:,.0f}")
else:
# Überprüfe Ausstiegssignal
iv_change = (current_iv - position['entry_iv']) / position['entry_iv']
# Take-Profit oder Stop-Loss
if current_iv < iv_threshold_low or iv_change < -0.30:
exit_price = current_price
pnl_pct = (position['entry_price'] - exit_price) / position['entry_price']
pnl_usd = capital * pnl_pct
capital += pnl_usd
capital_history.append(capital)
result = BacktestResult(
strategy=strategy,
entry_date=position['entry_date'],
exit_date=row['datetime'],
entry_iv=position['entry_iv'],
exit_iv=current_iv,
pnl=pnl_usd,
max_drawdown=max(0, min(capital_history) - capital),
sharpe_ratio=calculate_sharpe(capital_history),
win_rate=1.0 if pnl_usd > 0 else 0.0
)
results.append(result)
position = None
print(f"\n📊 Backtest abgeschlossen: {len(results)} Trades")
print(f"💵 Final Capital: ${capital:,.2f}")
print(f"📈 Total PnL: ${capital - 100_000:,.2f}")
return results
def calculate_sharpe(returns: List[float], risk_free: float = 0.04) -> float:
"""Berechnet Sharpe-Ratio"""
if len(returns) < 2:
return 0.0
returns_arr = np.array(returns)
excess = returns_arr[:-1] / returns_arr[1:] - 1 - risk_free/365
return np.mean(excess) / np.std(excess) * np.sqrt(365) if np.std(excess) > 0 else 0.0
Starte Backtest
results = run_backtest(
df_options,
strategy=StrategyType.SHORT_STRADDLE,
capital=50_000
)
Praxistest-Bewertung: Tardis.dev vs. Konkurrenz
| Kriterium | Tardis.dev | Deribit API | CoinMetrics | Bewertung (1-5★) |
|---|---|---|---|---|
| Latenz | <100ms | <50ms | >24h | ★★★★☆ |
| Erfolgsquote | 99.7% | 98.5% | 100% | ★★★★★ |
| Datenformat | CSV/JSON/Parquet | Nur JSON | Nur CSV | ★★★★★ |
| Historische Tiefe | 2018-heute | 30 Tage | 2013-heute | ★★★★☆ |
| Console-UX | Modern, intuitiv | Basic, technisch | Daten-lastig | ★★★★☆ |
| Zahlungsfreundlichkeit | Visa/Mastercard | Krypto | Nur Kreditkarte | ★★★★☆ |
| Support | 24/7 Chat | Email only | Email only | ★★★★★ |
Geeignet / Nicht geeignet für
✓ Ideal für:
- Professionelle Optionshändler und Market Maker
- Quantitative Forscher, die Volatilitätsstrategien entwickeln
- Fonds und Family Offices mit mittlerem bis hohem Kapitaleinsatz
- Entwickler, die Backtesting-Infrastruktur aufbauen
- Trading-Bots, die Echtzeit-Daten für Signalgenerierung benötigen
✗ Nicht geeignet für:
- Privatanleger mit Budget unter $500/Jahr
- Personen, die nur gelegentlich Daten benötigen (nutzen Sie kostenlose Deribit-API)
- Nutzer, die ausschließlich amerikanische Optionen benötigen (Tardis fokussiert auf Deribit/Crypto)
- Strategien, die nur sehr kurze historische Daten benötigen
Preise und ROI
Die Tardis.dev Preisgestaltung ist transparent und skaliert mit Ihren Bedürfnissen:
| Plan | Preis/Monat | API-Calls | Historische Tage | Streams |
|---|---|---|---|---|
| Starter | Kostenlos | 100/Tag | 30 | 1 |
| Pro | $99 | 10.000/Tag | Unbegrenzt | 10 |
| Enterprise | $499+ | Unbegrenzt | Unbegrenzt | 50+ |
ROI-Analyse: Bei einem Algo-Trading-Account mit $100.000 Kapital kostet Tardis.dev ($99/Monat × 12 = $1.188/Jahr). Wenn Ihre Strategie nur 0.5% Verbesserung durch bessere Daten erzielt, generiert das $500/Jahr - die Investition amortisiert sich schnell.
Warum HolySheep AI für die Datenanalyse wählen
Nach der Datenextraktion mit Tardis.dev empfehle ich HolySheep AI für die nachgelagerte Analyse aus folgenden Gründen:
| Vorteil | HolySheep AI | OpenAI Direct | Ersparnis |
|---|---|---|---|
| GPT-4.1 Preis | $8/MTok | $60/MTok | 87% günstiger |
| Claude Sonnet 4.5 | $15/MTok | $45/MTok | 67% günstiger |
| Gemini 2.5 Flash | $2.50/MTok | $7.50/MTok | 67% günstiger |
| DeepSeek V3.2 | $0.42/MTok | N/A | Exklusiv |
| Latenz | <50ms | 200-500ms | 4-10x schneller |
| Zahlung | WeChat/Alipay, Visa | Nur Kreditkarte | Asiatische Märkte |
| Startguthaben | Kostenlose Credits | $5 Probe-Credits | Mehr Credits |
Häufige Fehler und Lösungen
Fehler 1: "Rate Limit Exceeded" bei API-Anfragen
Symptom: Nach mehreren Downloads in kurzer Zeit erhalten Sie 429-Fehler.
# ❌ FALSCH: Schnelle aufeinanderfolgende Anfragen
for date in date_range:
data = get_deribit_options_history(date, date + timedelta(days=1))
save_to_csv(data)
✅ RICHTIG: Rate Limiting implementieren
import time
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=60)
)
def get_with_retry(url, params):
response = requests.get(url, params=params, timeout=300)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f"⏳ Rate limit erreicht. Warte {retry_after}s...")
time.sleep(retry_after)
raise Exception("Rate limit")
response.raise_for_status()
return response
Mit 1 Sekunde Pause zwischen Anfragen
for i, date in enumerate(date_range):
try:
data = get_with_retry(url, params)
save_to_csv(data)
except Exception as e:
print(f"⚠️ Fehler bei {date}: {e}")
time.sleep(1) # Pause zwischen Anfragen
Fehler 2: Symbol-Parsing-Fehler bei Deribit-Optionen
Symptom: KeyError oder ValueError beim Parsen des Options-Symbols.
# ❌ FALSCH: Nicht alle Symbolformate berücksichtigt
def parse_symbol_legacy(symbol: str):
parts = symbol.split('-')
return {
'strike': float(parts[2]),
'expiry': datetime.strptime(parts[1], '%y%m%d')
}
✅ RICHTIG: Robustes Parsing mit Fallback
import re
from typing import Optional
def parse_deribit_symbol(symbol: str) -> Optional[Dict]:
"""
Parst Deribit Options-Symbole mit verschiedenen Formaten
Format 1: BTC-YYYYMMDD-STRIKE-C (z.B. BTC-260430-95000-C)
Format 2: ETH-28FEB25-4500-P
"""
patterns = [
r'^([A-Z]+)-(\d{6})-(\d+)-([CP])$', # BTC-260430-95000-C
r'^([A-Z]+)-(\d{1,2}[A-Z]{3}\d{2})-(\d+)-([CP])$', # ETH-28FEB25-4500-P
]
for pattern in patterns:
match = re.match(pattern, symbol)
if match:
underlying, expiry_str, strike, option_type = match.groups()
# Konvertiere expiry je nach Format
try:
expiry = datetime.strptime(expiry_str, '%y%m%d')
except ValueError:
try:
expiry = datetime.strptime(expiry_str, '%d%b%y')
except ValueError:
print(f"⚠️ Konnte Datum nicht parsen: {expiry_str}")
return None
return {
'underlying': underlying,
'strike': float(strike),
'expiry': expiry,
'option_type': 'call' if option_type == 'C' else 'put',
'days_to_expiry': (expiry - datetime.now()).days
}
print(f"⚠️ Unbekanntes Symbolformat: {symbol}")
return None
Test mit verschiedenen Formaten
test_symbols = ['BTC-260430-95000-C', 'ETH-28FEB25-4500-P', 'INVALID']
for sym in test_symbols:
result = parse_deribit_symbol(sym)
print(f"{sym}: {result}")
Fehler 3: Volatilitätsflächen-Interpolation mit NaN-Werten
Symptom: Die 3D-Oberfläche hat Löcher oder verzerrte Bereiche.
# ❌ FALSCH: NaN-Werte nicht behandelt
from scipy.interpolate import griddata
X, Y = np.meshgrid(strikes, expirys)
Z = np.zeros_like(X)
Direkte Zuordnung ohne Behandlung fehlender Daten
for i, expiry in enumerate(expirys):
for j, strike in enumerate(strikes):
mask = (df['strike'] == strike) & (df['days_to_expiry'] == expiry)
Z[i, j] = df.loc[mask, 'iv_approx'].mean() # Kann NaN erzeugen
❌ Z_interp = griddata(coords, values, (X, Y), method='cubic')
Kann Fehler werfen wenn nicht genug gültige Punkte
✅ RICHTIG: Robuste Interpolation
def create_volatility_mesh(
df: pd.DataFrame,
min_points: int = 10,
interpolation_method: str = 'cubic'
) -> Dict:
"""
Erstellt eine glatte Volatilitätsfläche mit robuster Interpolation
"""
# Sammle gültige Punkte
valid_data = df.dropna(subset=['strike', 'days_to_expiry', 'iv_approx'])
if len(valid_data) < min_points:
raise ValueError(f"Nicht genug Datenpunkte: {len(valid_data)} < {min_points}")
points = np.column_stack([
valid_data['strike'].values,
valid_data['days_to_expiry'].values
])
values = valid_data['iv_approx'].values
# Erstelle Gitter
strike_range = np.linspace(valid_data['strike'].min(), valid_data['strike'].max(), 50)
expiry_range = np.linspace(valid_data['days_to_expiry'].min(), valid_data['days_to_expiry'].max(), 30)
X, Y = np.meshgrid(strike_range, expiry_range)
# Interpolation mit Fallback
try:
Z = griddata(points, values, (X, Y), method=interpolation_method)
except Exception as e:
print(f"⚠️ {interpolation_method} fehlgeschlagen: {e}")
Z = griddata(points, values, (X, Y), method='linear')
# Fülle verbleibende NaN mit Nearest-Neighbor
nan_mask = np.isnan(Z)
if nan_mask.any():
Z_nearest = griddata(points, values, (X, Y), method='nearest')
Z[nan_mask] = Z_nearest[nan_mask]
print(f"📝 {nan_mask.sum()} NaN-Werte mit Nearest-Neighbor gefüllt")
# Glättung mit Median-Filter
from scipy.ndimage import median_filter
Z_smooth = median_filter(Z, size=3)
Verwandte Ressourcen
Verwandte Artikel