import key
from pybit.unified_trading import HTTP
from datetime import datetime, timedelta
import re
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor

# Кэш для хранения taker_fee
cache = {}
cache_expiry = timedelta(minutes=30)  # Время жизни кэша

def get_fee_from_cache(fee_type, symbol):
    """Получить fee из кэша по типу и символу."""
    cache_key = f"{fee_type}_{symbol}"
    if cache_key in cache:
        cached_fee, expiry_time = cache[cache_key]
        if datetime.now() < expiry_time:
            return cached_fee
    return None

def set_fee_cache(fee_type, symbol, fee):
    """Сохранить fee в кэше по типу и символу."""
    cache_key = f"{fee_type}_{symbol}"
    cache[cache_key] = (fee, datetime.now() + cache_expiry)

def get_options(session):
    cached_fee = get_fee_from_cache("taker_fee", "BTC")
    if cached_fee is not None:
        taker_fee = cached_fee  # Используем значение из кэша
    else:
        # Получаем taker_fee
        taker_fee = float(session.get_fee_rates(category="option", baseCoin="BTC").get('result').get('list')[0].get('takerFeeRate'))
        set_fee_cache("taker_fee", "BTC", taker_fee)  # Сохраняем taker_fee в кэш

    # Получаем тикеры
    response = session.get_tickers(category="option", baseCoin="BTC")

    if response.get("retCode") == 0 and "result" in response:
        tickers = response["result"].get("list", [])
        parsed_tickers = []
        return_tickers = {}

        for ticker in tickers:
            symbol = ticker.get("symbol")
            bid1Price = ticker.get("bid1Price")
            bid1Size = ticker.get("bid1Size")
            ask1Price = ticker.get("ask1Price")
            ask1Size = ticker.get("ask1Size")

            # Ищем в symbol подстроку вида "DMMMYY" или "DDMMMYY"
            matches = re.findall(r'(\d{1,2})([A-Za-z]{3})(\d{2})', symbol)
            parsed_date = datetime.min  # значение по умолчанию

            for day_str, month_str, year_str in matches:
                if month_str.upper() in ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]:
                    year_str = "20" + year_str
                    try:
                        parsed_date = datetime.strptime(f"{day_str}{month_str.upper()}{year_str}", "%d%b%Y")
                        break
                    except ValueError:
                        continue

            symbol_parts = symbol.split('-')
            if len(symbol_parts) == 4:
                name = symbol_parts[0]
                date_exp = symbol_parts[1]
                str_price = symbol_parts[2]
                option_type = symbol_parts[3]

                option_type = 'Put' if option_type == 'P' else 'Call' if option_type == 'C' else "N/A"
            else:
                name = date_exp = str_price = option_type = "N/A"

            parsed_tickers.append({
                "name": name,
                "date_exp": date_exp,
                "str_price": str_price,
                "option_type": option_type,
                "bid1Price": bid1Price,
                "bid1Size": bid1Size,
                "ask1Price": ask1Price,
                "ask1Size": ask1Size,
                "date": parsed_date
            })

        sorted_tickers = sorted(parsed_tickers, key=lambda x: x["date"])

        for ticker in sorted_tickers:
            date_str = ticker["date"].strftime("%d %b %Y") if ticker["date"] != datetime.min else "N/A"
            if ticker["date_exp"] not in return_tickers:
                return_tickers[ticker["date_exp"]] = []

            return_tickers[ticker["date_exp"]].append({
                "str_price": ticker['str_price'],
                "option_type": ticker['option_type'],
                "bid1Price": ticker['bid1Price'],
                "bid1Size": ticker['bid1Size'],
                "ask1Price": ticker['ask1Price'],
                "ask1Size": ticker['ask1Size'],
                "date": date_str,
                "fee": taker_fee
            })

    else:
        print("Ошибка получения данных:", response)

    result = {}

    for date, tickers in return_tickers.items():
        grouped_tickers = defaultdict(list)

        for ticker in tickers:
            grouped_tickers[ticker['str_price']].append(ticker)

        sorted_groups = sorted(grouped_tickers.items(), key=lambda kv: int(kv[0]))

        result[date] = []
        for str_price, items in sorted_groups:
            result[date].append({
                'str_price': str_price,
                'options': items
            })

    return result

def get_perpetual_futures(session):
    futures = {}
    USDT_perp = []
    USDC_perp = []

    response = session.get_tickers(category="linear").get("result", []).get("list", [])

    cached_fee = get_fee_from_cache("taker_fee_USDT", "BTCUSDT")
    if cached_fee is not None:
        taker_fee_USDT = cached_fee  # Используем значение из кэша
    else:
        # Получаем taker_fee
        taker_fee_USDT = float(session.get_fee_rates(category="linear", symbol="BTCUSDT").get('result').get('list')[0].get('takerFeeRate'))
        set_fee_cache("taker_fee_USDT","BTCUSDT", taker_fee_USDT)  # Сохраняем taker_fee в кэш

    cached_fee = get_fee_from_cache("taker_fee_USDC", "BTCPERP")
    if cached_fee is not None:
        taker_fee_USDC = cached_fee  # Используем значение из кэша
    else:
        # Получаем taker_fee
        taker_fee_USDC = float(session.get_fee_rates(category="linear", symbol="BTCPERP").get('result').get('list')[0].get('takerFeeRate'))
        set_fee_cache("taker_fee_USDC","BTCPERP", taker_fee_USDC)  # Сохраняем taker_fee в кэш

    for ticker in response:
        symbol = ticker.get("symbol")
        if "BTC-" in symbol:
            cached_fee = get_fee_from_cache("taker_fee_futures", symbol)
            if cached_fee is not None:
                taker_fee_futures = cached_fee  # Используем значение из кэша
            else:
                # Получаем taker_fee
                taker_fee_futures = float(session.get_fee_rates(category="linear", symbol=symbol).get('result').get('list')[0].get('takerFeeRate'))
                set_fee_cache("taker_fee_futures", symbol, taker_fee_futures)  # Сохраняем taker_fee в кэш
            date_exp = symbol.split("BTC-")[1]

            if date_exp not in futures:
                futures[date_exp] = []
            futures[date_exp].append({
                "bid1Price": ticker['bid1Price'],
                "bid1Size": ticker['bid1Size'],
                "ask1Price": ticker['ask1Price'],
                "ask1Size": ticker['ask1Size'],
                "fee": taker_fee_futures
            })
        elif symbol == "BTCUSDT":
            USDT_perp.append({
                "bid1Price": ticker['bid1Price'],
                "bid1Size": ticker['bid1Size'],
                "ask1Price": ticker['ask1Price'],
                "ask1Size": ticker['ask1Size'],
                "fee": taker_fee_USDT
            })
        elif symbol == "BTCPERP":
            USDC_perp.append({
                "bid1Price": ticker['bid1Price'],
                "bid1Size": ticker['bid1Size'],
                "ask1Price": ticker['ask1Price'],
                "ask1Size": ticker['ask1Size'],
                "fee": taker_fee_USDC
            })

    return futures, USDT_perp, USDC_perp

def get_spot(session):
    response = session.get_tickers(category="spot", symbol="BTCUSDT").get('result', {}).get('list')[0]
    spot_BTC = []

    cached_fee = get_fee_from_cache("taker_fee_spot", "BTCUSDT")
    if cached_fee is not None:
        taker_fee_spot = cached_fee  # Используем значение из кэша
    else:
        # Получаем taker_fee
        taker_fee_spot = float(
            session.get_fee_rates(category="spot", symbol="BTCUSDT").get('result').get('list')[0].get('takerFeeRate'))
        set_fee_cache("taker_fee_spot", "BTCUSDT", taker_fee_spot)  # Сохраняем taker_fee в кэш

    spot_BTC.append({
                    "bid1Price": response['bid1Price'],
                    "bid1Size": response['bid1Size'],
                    "ask1Price": response['ask1Price'],
                    "ask1Size": response['ask1Size'],
                    "fee": taker_fee_spot
                    })

    return spot_BTC

def process_tickers():
    # Создаем сессию для API
    session = HTTP(
        api_key=key.APIK,
        api_secret=key.APISK,
    )

    with ThreadPoolExecutor() as executor:
        futures_task = executor.submit(get_perpetual_futures, session)
        options_task = executor.submit(get_options, session)
        spot_task = executor.submit(get_spot, session)

        # spot = spot_task.result()
        options = options_task.result()
        futures, USDT_perp, USDC_perp = futures_task.result()

    return options, futures, USDT_perp, USDC_perp

if __name__ == "__main__":
    options, futures, USDT_perp, USDC_perp = process_tickers()
    print(f'{options} \n {futures} \n {USDT_perp} \n {USDC_perp}')
мне нужно что бы         if "BTC-" in symbol:
            cached_fee = get_fee_from_cache("taker_fee_futures", symbol)
            if cached_fee is not None:
                taker_fee_futures = cached_fee  # Используем значение из кэша
            else:
                # Получаем taker_fee
                taker_fee_futures = float(session.get_fee_rates(category="linear", symbol=symbol).get('result').get('list')[0].get('takerFeeRate'))
                set_fee_cache("taker_fee_futures", symbol, taker_fee_futures)  # Сохраняем taker_fee в кэш
            date_exp = symbol.split("BTC-")[1]

            if date_exp not in futures:
                futures[date_exp] = []
            futures[date_exp].append({
                "bid1Price": ticker['bid1Price'],
                "bid1Size": ticker['bid1Size'],
                "ask1Price": ticker['ask1Price'],
                "ask1Size": ticker['ask1Size'],
                "fee": taker_fee_futures
            }) это так же было отсортировано по date_exp как и в options