Willkommen zu diesem umfassenden Leitfaden für den Einstieg in die Welt der Finanzdaten-APIs. In diesem Tutorial zeige ich Ihnen Schritt für Schritt, wie Sie historische Optionsdaten von Deribit abrufen und für die Analyse von impliziter Volatilität sowie die Validierung von Risikomodellen nutzen können. Dieser Leitfaden richtet sich an absolute Anfänger ohne Vorkenntnisse in API-Programmierung.

1. Was ist Deribit und warum sind Optionsdaten wichtig?

Deribit ist eine der weltweit führenden Krypto-Derivatebörsen, die sich auf Bitcoin- und Ethereum-Optionen spezialisiert hat. Im Gegensatz zu traditionellen Börsen wie CBOE oder CME bietet Deribit eine besonders umfangreiche Datenbasis für Optionskontrakte mit hoher Liquidität und niedrigen Gebühren.

Historische Optionsdaten sind für verschiedene Anwendungsfälle unverzichtbar:

2. Voraussetzungen und Umgebung

Bevor wir mit der API-Integration beginnen, benötigen Sie folgende Werkzeuge:

3. Deribit API-Grundlagen

3.1 API-Endpunkte verstehen

Die Deribit API bietet verschiedene Endpunkte für den Zugriff auf unterschiedliche Datentypen. Für historische Optionsdaten sind folgende Endpunkte relevant:

3.2 Erste Schritte mit der API

Beginnen wir mit einer einfachen Verbindung zur Deribit API. Im folgenden Beispiel sehen Sie, wie Sie eine Verbindung herstellen und eine Liste der verfügbaren Optionskontrakte abrufen:

#!/usr/bin/env python3
"""
Deribit API Grundverbindung - Erste Schritte
Dieses Skript zeigt, wie Sie eine Verbindung zur Deribit API herstellen
und verfügbare Optionskontrakte abrufen.
"""

import requests
import json
import time
from datetime import datetime

API-Endpunkt-Konfiguration

BASE_URL = "https://test.deribit.com/api/v2" def get_option_contracts(currency="BTC", kind="option"): """ Ruft alle verfügbaren Optionskontrakte ab Args: currency: 'BTC' oder 'ETH' kind: 'option' für Optionskontrakte Returns: Liste der verfügbaren Kontrakte """ endpoint = f"{BASE_URL}/public/get_instruments" params = { "currency": currency, "kind": kind, "expired": "false" # Nur aktive Kontrakte } try: response = requests.get(endpoint, params=params, timeout=10) response.raise_for_status() data = response.json() if data.get("success"): return data["result"] else: print(f"API-Fehler: {data.get('error')}") return [] except requests.exceptions.RequestException as e: print(f"Verbindungsfehler: {e}") return [] def get_contract_details(instrument_name): """ Ruft Details für einen spezifischen Kontrakt ab Args: instrument_name: z.B. 'BTC-28MAR25-95000-C' Returns: Dictionary mit Kontraktdetails """ endpoint = f"{BASE_URL}/public/get_instrument" params = {"instrument_name": instrument_name} try: response = requests.get(endpoint, params=params, timeout=10) response.raise_for_status() data = response.json() if data.get("success"): return data["result"] else: print(f"API-Fehler: {data.get('error')}") return {} except requests.exceptions.RequestException as e: print(f"Verbindungsfehler: {e}") return {}

Hauptprogramm

if __name__ == "__main__": print("=== Deribit Options-API Einrichtung ===") print(f"Zeitstempel: {datetime.now()}") print("-" * 50) # Abrufen der BTC-Optionskontrakte contracts = get_option_contracts(currency="BTC") if contracts: print(f"\nGefundene BTC-Optionskontrakte: {len(contracts)}") print("\nErste 5 Kontrakte:") for i, contract in enumerate(contracts[:5]): print(f"\n{i+1}. {contract['instrument_name']}") print(f" Basiswert: {contract['base_currency']}") print(f" Strike: {contract['strike']}") print(f" Verfall: {contract['expiration_timestamp']}") print(f" Typ: {contract['option_type']}") print(f" Min. Handelsgröße: {contract['min_trade_amount']}") else: print("Keine Kontrakte gefunden.")

4. Historische Daten abrufen und verarbeiten

4.1 Struktur der historischen Daten

Die historischen Daten von Deribit enthalten wichtige Informationen für die Volatilitätsanalyse. Jeder Datensatz umfasst:

4.2 Vollständiges Skript für historische Daten

#!/usr/bin/env python3
"""
Historische Optionsdaten von Deribit abrufen
Mit diesem Skript können Sie Daten für die Volatilitätsanalyse sammeln
"""

import requests
import json
import csv
import time
from datetime import datetime, timedelta
from typing import List, Dict, Optional

class DeribitDataFetcher:
    """Klasse für den Zugriff auf Deribit historische Daten"""
    
    def __init__(self, testnet=True):
        if testnet:
            self.base_url = "https://test.deribit.com/api/v2"
        else:
            self.base_url = "https://deribit.com/api/v2"
        
        self.session = requests.Session()
        self.session.headers.update({
            "Content-Type": "application/json",
            "User-Agent": "DeribitDataFetcher/1.0"
        })
    
    def get_historical_data(
        self,
        instrument_name: str,
        start_time: int,
        end_time: int,
        resolution: str = "1D"
    ) -> List[Dict]:
        """
        Ruft historische Daten für einen Kontrakt ab
        
        Args:
            instrument_name: Name des Optionskontrakts
            start_time: Startzeitpunkt in Millisekunden (Unix)
            end_time: Endzeitpunkt in Millisekunden (Unix)
            resolution: '1M', '5M', '15M', '1H', '1D'
        
        Returns:
            Liste von Datensätzen mit OHLCV-Daten
        """
        endpoint = f"{self.base_url}/public/get_historical_data"
        
        # Resolution Mapping
        resolution_map = {
            "1M": 1,
            "5M": 5,
            "15M": 15,
            "1H": 60,
            "1D": 1440
        }
        
        params = {
            "instrument_name": instrument_name,
            "start": start_time,
            "end": end_time,
            "resolution": resolution_map.get(resolution, 1440)
        }
        
        max_retries = 3
        for attempt in range(max_retries):
            try:
                response = self.session.get(
                    endpoint,
                    params=params,
                    timeout=30
                )
                response.raise_for_status()
                data = response.json()
                
                if data.get("success"):
                    return data["result"]
                else:
                    print(f"API-Fehler: {data.get('error', {}).get('message')}")
                    return []
                    
            except requests.exceptions.RequestException as e:
                print(f"Versuch {attempt + 1}/{max_retries} fehlgeschlagen: {e}")
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)  # Exponential backoff
                else:
                    return []
        
        return []
    
    def get_all_options_for_underlying(
        self,
        underlying: str = "BTC",
        expiry_filter: Optional[str] = None
    ) -> List[str]:
        """
        Ruft alle Optionskontrakte für einen Basiswert ab
        
        Args:
            underlying: 'BTC' oder 'ETH'
            expiry_filter: Optionaler Verfallsfilter (z.B. '28MAR25')
        
        Returns:
            Liste von Instrument-Namen
        """
        endpoint = f"{self.base_url}/public/get_instruments"
        params = {
            "currency": underlying,
            "kind": "option",
            "expired": "false"
        }
        
        try:
            response = self.session.get(endpoint, params=params, timeout=30)
            response.raise_for_status()
            data = response.json()
            
            if data.get("success"):
                instruments = data["result"]
                
                # Optional filtern nach Verfallsdatum
                if expiry_filter:
                    instruments = [
                        i for i in instruments
                        if expiry_filter in i["instrument_name"]
                    ]
                
                return [i["instrument_name"] for i in instruments]
            return []
            
        except requests.exceptions.RequestException as e:
            print(f"Fehler beim Abrufen der Instrumente: {e}")
            return []

    def save_to_csv(self, data: List[Dict], filename: str):
        """Speichert Daten als CSV-Datei"""
        if not data:
            print("Keine Daten zum Speichern.")
            return
        
        # CSV-Header basierend auf ersten Datensatz
        fieldnames = list(data[0].keys())
        
        with open(filename, 'w', newline='', encoding='utf-8') as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerows(data)
        
        print(f"Daten gespeichert: {filename} ({len(data)} Einträge)")

Beispiel-Nutzung

if __name__ == "__main__": fetcher = DeribitDataFetcher(testnet=True) # Konfiguration underlying = "BTC" expiry = "28MAR25" print("=" * 60) print("Deribit Historische Daten - Abrufscript") print("=" * 60) # Schritt 1: Verfügbare Kontrakte abrufen print(f"\n1. Abrufen aller {underlying}-Optionskontrakte mit Verfall {expiry}...") instruments = fetcher.get_all_options_for_underlying( underlying=underlying, expiry_filter=expiry ) print(f" Gefundene Kontrakte: {len(instruments)}") # Schritt 2: Datumsbereich definieren (letzte 30 Tage) end_time = int(datetime.now().timestamp() * 1000) start_time = int((datetime.now() - timedelta(days=30)).timestamp() * 1000) print(f"\n2. Zeitraum: {datetime.fromtimestamp(start_time/1000)} bis {datetime.fromtimestamp(end_time/1000)}") # Schritt 3: Daten für jeden Kontrakt abrufen all_data = [] for i, instrument in enumerate(instruments[:10]): # Limit für Demo print(f"\n3.{i+1} Abrufen: {instrument}") data = fetcher.get_historical_data( instrument_name=instrument, start_time=start_time, end_time=end_time, resolution="1D" ) if data: print(f" Datensätze: {len(data)}") all_data.extend(data) # Rate Limiting: Pause zwischen Anfragen time.sleep(0.5) # Schritt 4: Daten speichern if all_data: output_file = f"deribit_options_{underlying}_{datetime.now().strftime('%Y%m%d')}.csv" fetcher.save_to_csv(all_data, output_file) print(f"\nGesamtDatensätze gesammelt: {len(all_data)}") else: print("\nKeine Daten abgerufen. Bitte überprüfen Sie Ihre API-Einstellungen.")

5. Implizite Volatilität berechnen

5.1 Grundlagen der impliziten Volatilität

Die implizite Volatilität (IV) ist ein Maß für die vom Markt erwartete zukünftige Volatilität eines Basiswerts. Sie wird aus dem aktuellen Optionspreis rückgerechnet und spiegelt die Markterwartungen wider. Ein hoher IV-Wert deutet auf unsichere Markterwartungen hin, während ein niedriger Wert auf Stabilität hindeutet.

Für die Berechnung der IV verwenden wir typischerweise das Black-Scholes-Modell. Die Grundformel lautet:

wobei S der aktuelle Preis, K der Strike-Preis, r der Zinssatz, T die Zeit bis zum Verfall und σ die Volatilität ist.

5.2 Python-Implementierung mit SciPy

#!/usr/bin/env python3
"""
Implizite Volatilität Berechnung
Verwendet Newton-Raphson Methode zur Lösung der Black-Scholes Gleichung
"""

import numpy as np
from scipy.stats import norm
from scipy.optimize import brentq, newton
from typing import Tuple, Optional
from dataclasses import dataclass
from datetime import datetime

@dataclass
class Option:
    """Datenklasse für Optionsdaten"""
    spot_price: float      # Aktueller Preis des Basiswerts
    strike_price: float    # Ausübungspreis
    time_to_expiry: float  # Zeit bis zum Verfall (in Jahren)
    risk_free_rate: float # Risikofreier Zinssatz (annualisiert)
    option_price: float   # Marktpreis der Option
    option_type: str       # 'call' oder 'put'

class ImpliedVolatilityCalculator:
    """Berechnet implizite Volatilität aus Optionspreisen"""
    
    @staticmethod
    def black_scholes_price(
        spot: float,
        strike: float,
        time_to_expiry: float,
        risk_free_rate: float,
        volatility: float,
        option_type: str = 'call'
    ) -> float:
        """
        Berechnet den theoretischen Optionspreis mit Black-Scholes
        
        Args:
            spot: Aktueller Preis des Basiswerts
            strike: Ausübungspreis
            time_to_expiry: Zeit bis zum Verfall (Jahre)
            risk_free_rate: Risikoloser Zinssatz
            volatility: Volatilität (annualisiert)
            option_type: 'call' oder 'put'
        
        Returns:
            Optionspreis
        """
        if time_to_expiry <= 0 or volatility <= 0:
            return 0.0
        
        d1 = (np.log(spot / strike) + 
              (risk_free_rate + 0.5 * volatility**2) * time_to_expiry) / \
             (volatility * np.sqrt(time_to_expiry))
        d2 = d1 - volatility * np.sqrt(time_to_expiry)
        
        if option_type == 'call':
            price = (spot * norm.cdf(d1) - 
                    strike * np.exp(-risk_free_rate * time_to_expiry) * norm.cdf(d2))
        else:
            price = (strike * np.exp(-risk_free_rate * time_to_expiry) * norm.cdf(-d2) - 
                    spot * norm.cdf(-d1))
        
        return price
    
    @staticmethod
    def implied_volatility_brent(
        option_price: float,
        spot: float,
        strike: float,
        time_to_expiry: float,
        risk_free_rate: float,
        option_type: str = 'call',
        tol: float = 1e-6,
        max_iter: int = 100
    ) -> Optional[float]:
        """
        Berechnet IV mit Brent-Methode (robuster)
        
        Returns:
            Implizite Volatilität oder None bei Fehler
        """
        intrinsic = max(0, spot - strike) if option_type == 'call' else max(0, strike - spot)
        
        if option_price <= intrinsic:
            return None
        
        # Suchbereich definieren
        sigma_low = 0.001   # 0.1%
        sigma_high = 5.0    # 500%
        
        def objective(sigma):
            return (ImpliedVolatilityCalculator.black_scholes_price(
                spot, strike, time_to_expiry, risk_free_rate, sigma, option_type
            ) - option_price)
        
        try:
            iv = brentq(objective, sigma_low, sigma_high, xtol=tol, maxiter=max_iter)
            return iv
        except ValueError:
            return None
    
    @staticmethod
    def implied_volatility_newton(
        option_price: float,
        spot: float,
        strike: float,
        time_to_expiry: float,
        risk_free_rate: float,
        option_type: str = 'call',
        initial_guess: float = 0.3
    ) -> Optional[float]:
        """
        Berechnet IV mit Newton-Raphson (schneller, aber potenziell instabil)
        
        Returns:
            Implizite Volatilität oder None bei Fehler
        """
        def objective(sigma):
            calc_price = ImpliedVolatilityCalculator.black_scholes_price(
                spot, strike, time_to_expiry, risk_free_rate, sigma, option_type
            )
            return calc_price - option_price
        
        def vega(spot, strike, time_to_expiry, volatility):
            """Ableitung des Preises nach Volatilität"""
            d1 = (np.log(spot / strike) + 
                  (0.5 * volatility**2) * time_to_expiry) / \
                 (volatility * np.sqrt(time_to_expiry))
            return spot * np.sqrt(time_to_expiry) * norm.pdf(d1)
        
        def objective_derivative(sigma):
            return vega(spot, strike, time_to_expiry, sigma)
        
        try:
            iv = newton(
                objective,
                initial_guess,
                fprime=objective_derivative,
                maxiter=50,
                tol=1e-6
            )
            return iv if 0 < iv < 5 else None
        except RuntimeError:
            return None

def calculate_volatility_surface_example():
    """Beispiel für die Berechnung einer Volatilitätsfläche"""
    
    print("=" * 70)
    print("Implizite Volatilität - Berechnungsbeispiel")
    print("=" * 70)
    
    calc = ImpliedVolatilityCalculator()
    
    # Beispiel: Angenommene Marktdaten
    spot = 95000        # BTC-Preis
    risk_free_rate = 0.05  # 5% annualisiert
    time_to_expiry = 30/365  # 30 Tage
    
    # Strike-Preise für verschiedene Optionen
    strikes = [85000, 90000, 95000, 100000, 105000]
    
    # Simulierte Marktpreise (aus Deribit würde man diese abrufen)
    # In der Praxis: calc.get_market_data() von Deribit
    market_prices_call = [7500, 5000, 3000, 1500, 600]
    
    print(f"\nSzenario-Analyse:")
    print(f"  Spot-Preis: ${spot:,.2f}")
    print(f"  Risikofreier Zins: {risk_free_rate*100:.1f}%")
    print(f"  Zeit bis Verfall: {time_to_expiry*365:.0f} Tage")
    
    print("\n{:<12} {:<15} {:<18} {:<15}".format(
        "Strike", "Marktpreis", "Impl. Volatilität", "Theo. Preis"))
    print("-" * 60)
    
    results = []
    
    for strike, market_price in zip(strikes, market_prices_call):
        iv_brent = calc.implied_volatility_brent(
            option_price=market_price,
            spot=spot,
            strike=strike,
            time_to_expiry=time_to_expiry,
            risk_free_rate=risk_free_rate,
            option_type='call'
        )
        
        iv_newton = calc.implied_volatility_newton(
            option_price=market_price,
            spot=spot,
            strike=strike,
            time_to_expiry=time_to_expiry,
            risk_free_rate=risk_free_rate,
            option_type='call'
        )
        
        # Durchschnitt der beiden Methoden
        if iv_brent and iv_newton:
            iv = (iv_brent + iv_newton) / 2
        elif iv_brent:
            iv = iv_brent
        else:
            iv = iv_newton
        
        if iv:
            theo_price = calc.black_scholes_price(
                spot, strike, time_to_expiry, risk_free_rate, iv, 'call'
            )
            print(f"${strike:,.0f}    ${market_price:,.0f}         {iv*100:>10.2f}%        ${theo_price:,.0f}")
            results.append({
                'strike': strike,
                'market_price': market_price,
                'implied_volatility': iv,
                'theo_price': theo_price
            })
    
    return results

if __name__ == "__main__":
    results = calculate_volatility_surface_example()
    print("\n" + "=" * 70)
    print("Volatilitäts-Smile dargestellt:")
    print("  Strike niedrig → IV hoch  (Volatility Skew)")
    print("  ATM Strike → IV mittel")
    print("  Strike hoch → IV hoch")
    print("=" * 70)

6. Volatilitätsfläche (Volatility Surface) erstellen

6.1 Was ist eine Volatilitätsfläche?

Die Volatilitätsfläche ist eine dreidimensionale Darstellung der impliziten Volatilität über verschiedene Ausübungspreise (Strike) und Verfallsdaten. Diese Fläche ist fundamental für:

6.2 Datenstruktur für die Volatilitätsfläche

Eine vollständige Volatilitätsfläche benötigt Daten über mehrere Dimensionen:

7. Risikomodell-Validierung

7.1 Methoden zur Modellvalidierung

Die Validierung von Risikomodellen ist ein kritischer Prozess in der Finanzindustrie. Hier sind die wichtigsten Methoden:

7.2 Greeks-Berechnung und Validierung

Die Griechen (Greeks) sind Sensitivitätsmaße, die zeigen, wie sich der Optionspreis bei Änderungen verschiedener Parameter verändert:

#!/usr/bin/env python3
"""
Risikomodell-Validierung für Deribit Options
Vergleicht berechnete Greeks mit Marktdaten
"""

import numpy as np
from scipy.stats import norm
from dataclasses import dataclass, field
from typing import List, Dict, Tuple
from datetime import datetime
import json

@dataclass
class Greeks:
    """Sensitivitätskennzahlen einer Option"""
    delta: float = 0.0
    gamma: float = 0.0
    theta: float = 0.0
    vega: float = 0.0
    rho: float = 0.0

@dataclass
class OptionPosition:
    """Eine Optionsposition mit Marktdaten und Griechen"""
    instrument_name: str
    spot: float
    strike: float
    time_to_expiry: float
    risk_free_rate: float
    volatility: float
    option_price: float
    option_type: str
    position_size: float = 1.0
    greeks: Greeks = field(default_factory=Greeks)

class RiskModelValidator:
    """Validiert Risikomodelle durch Vergleich mit Marktdaten"""
    
    @staticmethod
    def calculate_greeks(
        spot: float,
        strike: float,
        time_to_expiry: float,
        risk_free_rate: float,
        volatility: float,
        option_type: str
    ) -> Greeks:
        """
        Berechnet alle Greeks für eine Option
        
        Returns:
            Greeks-Objekt mit allen Sensitivitäten
        """
        if time_to_expiry <= 0 or volatility <= 0:
            return Greeks()
        
        sqrt_t = np.sqrt(time_to_expiry)
        d1 = (np.log(spot / strike) + 
              (risk_free_rate + 0.5 * volatility**2) * time_to_expiry) / \
             (volatility * sqrt_t)
        d2 = d1 - volatility * sqrt_t
        
        # Standardnormal_pdf und CDF
        phi = norm.pdf(d1)
        Phi = norm.cdf(d1)
        Phi_minus = norm.cdf(-d1)
        Phi_d2 = norm.cdf(d2) if option_type == 'call' else norm.cdf(-d2)
        
        # Delta
        if option_type == 'call':
            delta = Phi
        else:
            delta = Phi - 1
        
        # Gamma (gleich für Call und Put)
        gamma = phi / (spot * volatility * sqrt_t)
        
        # Theta (pro Tag)
        if option_type == 'call':
            theta = (-(spot * phi * volatility) / (2 * sqrt_t) -
                    risk_free_rate * strike * np.exp(-risk_free_rate * time_to_expiry) * Phi) / 365
        else:
            theta = (-(spot * phi * volatility) / (2 * sqrt_t) +
                    risk_free_rate * strike * np.exp(-risk_free_rate * time_to_expiry) * (1 - Phi)) / 365
        
        # Vega (pro 1% Volatilitätsänderung)
        vega = spot * sqrt_t * phi / 100
        
        # Rho (pro 1% Zinsänderung)
        if option_type == 'call':
            rho = strike * time_to_expiry * np.exp(-risk_free_rate * time_to_expiry) * Phi / 100
        else:
            rho = -strike * time_to_expiry * np.exp(-risk_free_rate * time_to_expiry) * (1 - Phi) / 100
        
        return Greeks(
            delta=delta,
            gamma=gamma,
            theta=theta,
            vega=vega,
            rho=rho
        )
    
    @staticmethod
    def validate_model(
        positions: List[OptionPosition],
        market_observed_greeks: Dict[str, Dict[str, float]],
        tolerance: float = 0.05
    ) -> Dict:
        """
        Vergleicht berechnete Greeks mit Marktdaten
        
        Args:
            positions: Liste von Optionspositionen
            market_observed_greeks: Dictionary mit beobachteten Greeks vom Markt
            tolerance: Akzeptable Abweichung (5% standardmäßig)
        
        Returns:
            Validierungsbericht
        """
        validation_results = {
            'timestamp': datetime.now().isoformat(),
            'total_positions': len(positions),
            'passed': 0,
            'failed': 0,
            'details': []
        }
        
        for pos in positions:
            # Berechnete Greeks
            calc_greeks = RiskModelValidator.calculate_greeks(
                pos.spot, pos.strike, pos.time_to_expiry,
                pos.risk_free_rate, pos.volatility, pos.option_type
            )
            
            # Marktbeobachtete Greeks (aus Deribit order book)
            observed = market_observed_greeks.get(pos.instrument_name, {})
            
            if not observed:
                validation_results['details'].append({
                    'instrument': pos.instrument_name,
                    'status': 'SKIPPED',
                    'reason': 'Keine Marktdaten verfügbar'
                })
                continue
            
            # Vergleich für jeden Greek
            comparison = {}
            all_passed = True
            
            for greek_name in ['delta', 'gamma', 'theta', 'vega']:
                calc_value = getattr(calc_greeks, greek_name)
                obs_value = observed.get(greek_name, calc_value)
                
                if obs_value != 0:
                    error_pct = abs((calc_value - obs_value) / obs_value)
                else:
                    error_pct = abs(calc_value) if calc_value != 0 else 0
                
                passed = error_pct <= tolerance
                all_passed = all_passed and passed
                
                comparison[greek_name] = {
                    'calculated': calc_value,
                    'observed': obs_value,
                    'error_pct': error_pct * 100,
                    'passed': passed
                }
            
            validation_results['details'].append({
                'instrument': pos.instrument_name,
                'status': 'PASSED' if all_passed else 'FAILED',
                'comparison': comparison
            })
            
            if all_passed:
                validation_results['passed'] += 1
            else:
                validation_results['failed'] += 1
        
        # Zusammenfassung
        validation_results['pass_rate'] = (
            validation_results['passed'] / validation_results['total_positions'] * 100
            if validation_results['total_positions'] > 0 else 0
        )
        
        return validation_results

def run_validation_example():
    """Beispiel für die Durchführung einer Modellvalidierung"""
    
    print("=" * 70)
    print("Risikomodell-Validierung für Deribit Options")
    print("=" * 70)
    
    # Simulierte Positionsdaten
    positions = [
        OptionPosition(
            instrument_name="BTC-28MAR25-95000-C",
            spot=95000,
            strike=95000,