#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Bybit 주식 퍼프 전종목: 오더북 뎁스 × 실현변동성 랭킹
# 션 시스템 기준 = 2만불 한방에 들어가고(뎁스) 자주 흔들리는(변동성) 종목이 최적
import json, urllib.request, time, statistics

def get(u):
    req = urllib.request.Request(u, headers={"User-Agent": "Mozilla/5.0"})
    return json.load(urllib.request.urlopen(req, timeout=20))

SIZE = 20000   # 판정 기준 노셔널

inst = get("https://api.bybit.com/v5/market/instruments-info?category=linear&limit=1000")
stocks = {x["symbol"] for x in inst["result"]["list"] if x.get("symbolType") == "stock"}
tk = get("https://api.bybit.com/v5/market/tickers?category=linear")
rows = [x for x in tk["result"]["list"] if x["symbol"] in stocks]
rows.sort(key=lambda x: -float(x.get("turnover24h") or 0))

print(f"주식 퍼프 {len(stocks)}개 · 거래대금 상위 25개 정밀검사\n")
out = []
for x in rows[:25]:
    s = x["symbol"]
    try:
        ob = get(f"https://api.bybit.com/v5/market/orderbook?category=linear&symbol={s}&limit=200")["result"]
        a, b = ob.get("a", []), ob.get("b", [])
        if not a or not b: continue
        best_a, best_b = float(a[0][0]), float(b[0][0])
        spread = (best_a / best_b - 1) * 100
        # SIZE 만큼 시장가 매수 시 평균가
        got = cost = 0.0
        for p, v in a:
            p, v = float(p), float(v)
            take = min(p * v, SIZE - cost)
            got += take / p; cost += take
            if cost >= SIZE: break
        slip = ((cost / got) / best_a - 1) * 100 if got and cost >= SIZE * 0.99 else None

        kl = get(f"https://api.bybit.com/v5/market/kline?category=linear&symbol={s}&interval=D&limit=21")["result"]["list"]
        cl = [float(k[4]) for k in kl][::-1]
        rets = [abs(cl[i]/cl[i-1]-1)*100 for i in range(1, len(cl))]
        vol = statistics.mean(rets) if rets else 0

        out.append((s, float(x["turnover24h"]), spread, slip, vol))
        time.sleep(0.15)
    except Exception:
        continue

print(f"{'심볼':<16}{'거래대금24h':>13}{'스프레드':>9}{'2만불슬립':>10}{'일평균변동':>11}  판정")
for s, t, sp, sl, v in out:
    slt = f"{sl:.2f}%" if sl is not None else "부족"
    if sl is None or sl > 0.5: verdict = "탈락(얇음)"
    elif v >= 2.5: verdict = "★ 최적(뎁스+변동성)"
    elif v >= 1.5: verdict = "가능"
    else: verdict = "뎁스OK/저변동"
    print(f"{s:<16}{t:>13,.0f}{sp:>8.3f}%{slt:>10}{v:>10.2f}%  {verdict}")
print(f"\n기준: 2만불 슬리피지 0.5% 이하 = 한방 가능 / 일평균변동 2.5%+ = 리셋기회 많음")
