import os
import json
import time
import traceback
from okx import PublicData
from decimal import Decimal
from datetime import datetime, UTC

def run_arbitrage():
    start_time = time.time()

    # 初始化 API（flag="0" 為實盤）
    publicDataAPI = PublicData.PublicAPI(flag="0")

    # 取得 SWAP 合約清單
    swap_data = publicDataAPI.get_instruments(instType="SWAP")['data']
    usdt_swap_pairs = set()
    swap_info = {}

    for item in swap_data:
        inst_id = item['instId']
        if inst_id.endswith('-USDT-SWAP'):
            spot_like_id = inst_id.replace('-SWAP', '')
            usdt_swap_pairs.add(spot_like_id)
            swap_info[spot_like_id] = {
                "sw-instId": inst_id,
                "sw-minSz": str(Decimal(item['minSz'])),
                "sw-lotSz": str(Decimal(item['lotSz'])),
                "sw-ctVal": str(Decimal(item['ctVal']))
            }

    # 取得 SPOT 現貨清單
    spot_data = publicDataAPI.get_instruments(instType="SPOT")['data']
    spot_pairs = set()
    spot_info = {}

    for item in spot_data:
        inst_id = item['instId']
        spot_pairs.add(inst_id)
        spot_info[inst_id] = {
            "sp-instId": inst_id,
            "sp-minSz": str(Decimal(item['minSz'])),
            "sp-lotSz": format(Decimal(item['lotSz']), 'f')
        }

    # 找出可套利的交易對
    common_pairs = sorted(usdt_swap_pairs & spot_pairs)
        # 拒絕往來清單，可以隨時加更多!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    blacklist_pairs = {"KISHU-USDT", "SHITCOIN-USDT", "AAA-USDT"}

    # 篩選出交集，然後排除黑名單
    common_pairs = sorted((usdt_swap_pairs & spot_pairs) - blacklist_pairs)

    print(common_pairs)

    result = []

    for pair in common_pairs:
        coin = pair.split('-')[0]
        funding_apy = None

        try:
            inst_id = swap_info[pair]["sw-instId"]
            data = publicDataAPI.get_funding_rate(instId=inst_id)['data'][0]

            funding_rate = float(data['fundingRate'])

            funding_time = datetime.fromtimestamp(int(data['fundingTime']) / 1000, tz=UTC)
            next_time = datetime.fromtimestamp(int(data['nextFundingTime']) / 1000, tz=UTC)
            interval_hr = (next_time - funding_time).total_seconds() / 3600
            daily_times = 24 / interval_hr
            funding_apy = funding_rate * daily_times * 365
            funding_apy = format(funding_apy * 100, '.4f')

        except Exception as e:
            print(f"查詢 {pair} 資費失敗：{e}")
            funding_apy = None

        result.append({
            "coin": coin,
            "sp-minSz": spot_info[pair]["sp-minSz"],
            "sp-lotSz": spot_info[pair]["sp-lotSz"],
            "sw-minSz": swap_info[pair]["sw-minSz"],
            "sw-lotSz": swap_info[pair]["sw-lotSz"],
            "sw-ctVal": swap_info[pair]["sw-ctVal"],
            "funding_apy": funding_apy
        })

    current_dir = os.path.dirname(os.path.abspath(__file__))
    file_path = os.path.join(current_dir, "arbitrage_pairs.json")

    with open(file_path, "w", encoding="utf-8") as f:
        json.dump(result, f, indent=4)

    print(f"[✓] 儲存完成，總共可套利對數: {len(result)}")
    print(f"[✓] 檔案位置: {file_path}")

    end_time = time.time()
    print(f"[✓] 執行時間: {end_time - start_time:.4f} 秒")

# 每30分鐘執行一次，有錯誤會自動繼續下一輪
while True:
    try:
        print("\n========== 開始新的執行輪次 ==========")
        run_arbitrage()
    except Exception as e:
        print("[✗] 發生錯誤！詳細錯誤如下：")
        traceback.print_exc()
    print("[⏳] 等待30分鐘後再次執行...\n")
    time.sleep(1800)  # 等待30分鐘
