# -*- coding: utf-8 -*-
"""
Deribit 公开API封装
"""

import requests
import logging
from collections import defaultdict
from exchange.http import http_get

logger = logging.getLogger("MyTrader")


class Deribit:
    BASE = "https://www.deribit.com/api/v2/public"

    def max_pain(self, currency):
        if currency is None:
            return None
        try:
            r = http_get(f"{self.BASE}/get_book_summary_by_currency",
                         params={"currency": currency, "kind": "option"}, timeout=10)
            if r.status_code != 200:
                return None
            options = r.json().get("result", [])
            if not options:
                return None

            expiry_groups = defaultdict(list)
            for opt in options:
                parts = opt.get("instrument_name", "").split("-")
                if len(parts) >= 4:
                    expiry_groups[parts[1]].append(opt)

            if not expiry_groups:
                return None

            nearest = min(expiry_groups.keys(), key=lambda x: self._parse_exp(x))
            group = expiry_groups[nearest]

            strikes = set()
            for opt in group:
                parts = opt["instrument_name"].split("-")
                if len(parts) >= 4:
                    try: strikes.add(float(parts[2]))
                    except: pass

            best, min_val = None, float('inf')
            for tp in sorted(strikes):
                total = 0
                for opt in group:
                    parts = opt["instrument_name"].split("-")
                    if len(parts) < 4: continue
                    try: strike = float(parts[2])
                    except: continue
                    oi = opt.get("open_interest", 0)
                    if parts[3] == "C":
                        total += max(0, tp - strike) * oi
                    else:
                        total += max(0, strike - tp) * oi
                if total < min_val:
                    min_val, best = total, tp
            return best
        except Exception as e:
            logger.warning(f"Deribit error: {e}")
            return None

    def _parse_exp(self, s):
        months = {"JAN":1,"FEB":2,"MAR":3,"APR":4,"MAY":5,"JUN":6,
                  "JUL":7,"AUG":8,"SEP":9,"OCT":10,"NOV":11,"DEC":12}
        try:
            for i, c in enumerate(s):
                if c.isalpha():
                    return int(s[i+3:]) * 10000 + months.get(s[i:i+3], 0) * 100 + int(s[:i])
        except: pass
        return 99999999

    def dvol(self, currency):
        """获取隐含波动率指数 DVOL"""
        try:
            r = http_get(f"{self.BASE}/get_volatility_index_data",
                params={"currency": currency, "resolution": 3600,
                        "start_timestamp": 0, "end_timestamp": 9999999999999}, timeout=10)
            data = r.json().get("result", {}).get("data", [])
            if len(data) >= 2:
                latest = data[-1][4]  # close
                prev = data[-2][4]
                return latest, prev
        except Exception as e:
            logger.warning(f"DVOL error: {e}")
        return None, None

    def net_gamma_exposure(self, currency, spot_price):
        """做市商净Gamma敞口 — 用book_summary批量估算，不逐个请求"""
        try:
            r = http_get(f"{self.BASE}/get_book_summary_by_currency",
                params={"currency": currency, "kind": "option"}, timeout=10)
            opts = r.json().get("result", [])
            net_gamma = 0
            for o in opts:
                oi = o.get("open_interest", 0)
                if oi == 0:
                    continue
                name = o["instrument_name"]
                parts = name.split("-")
                if len(parts) < 4:
                    continue
                try:
                    strike = float(parts[2])
                except:
                    continue
                if abs(strike - spot_price) / spot_price > 0.10:
                    continue
                iv = o.get("mark_iv", 0)
                if not iv or iv == 0:
                    continue
                # 简化Gamma估算: Gamma ≈ 1/(S*iv*sqrt(T)) for ATM
                # 近似: 越ATM gamma越大
                moneyness = abs(strike - spot_price) / spot_price
                gamma_approx = max(0, 1 - moneyness * 20) * oi  # ATM=1, 5% OTM=0
                if parts[3] == "C":
                    if spot_price > strike:
                        net_gamma += gamma_approx  # ITM call, 做市商买入对冲
                    else:
                        net_gamma -= gamma_approx * 0.3
                else:
                    if spot_price < strike:
                        net_gamma -= gamma_approx  # ITM put, 做市商卖出对冲
                    else:
                        net_gamma += gamma_approx * 0.3
            return net_gamma
        except Exception as e:
            logger.warning(f"Gamma error: {e}")
            return 0
