Spaces:
Running
Running
Upload deep_diver_engine.py
Browse files
src/services/deep_diver_engine.py
CHANGED
|
@@ -1,57 +1,75 @@
|
|
| 1 |
import requests
|
| 2 |
-
import
|
| 3 |
-
import
|
| 4 |
|
| 5 |
-
|
| 6 |
-
"""
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
DATA_DIR = os.path.join(os.getcwd(), "data")
|
| 11 |
-
TICKER_FILE = os.path.join(DATA_DIR, "tickers.json")
|
| 12 |
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
|
|
|
|
|
|
|
|
|
| 18 |
try:
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
#
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
for coin in m_data:
|
| 28 |
-
top_metadata[coin['id']] = {
|
| 29 |
-
"img": coin['image'],
|
| 30 |
-
"rank": coin['market_cap_rank']
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
# 3. Merge into memory-efficient structure
|
| 34 |
-
library = []
|
| 35 |
-
for coin in all_coins:
|
| 36 |
-
c_id = coin['id']
|
| 37 |
-
meta = top_metadata.get(c_id, {})
|
| 38 |
-
library.append({
|
| 39 |
-
"id": c_id,
|
| 40 |
-
"s": coin['symbol'].lower(),
|
| 41 |
-
"n": coin['name'],
|
| 42 |
-
"i": meta.get("img", None),
|
| 43 |
-
"r": meta.get("rank", 99999)
|
| 44 |
-
})
|
| 45 |
|
| 46 |
-
#
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
except Exception as e:
|
| 53 |
-
print(f"[SYNC ERROR] {str(e)}")
|
| 54 |
-
return False
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import requests
|
| 2 |
+
import time
|
| 3 |
+
from decimal import Decimal, ROUND_HALF_UP # Added for financial precision
|
| 4 |
|
| 5 |
+
STEALTH_HEADERS = {
|
| 6 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
| 7 |
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
| 8 |
+
"Connection": "keep-alive",
|
| 9 |
+
}
|
|
|
|
|
|
|
| 10 |
|
| 11 |
+
def format_compact(num):
|
| 12 |
+
if num is None or num == 0: return "0"
|
| 13 |
+
for unit in ['', 'K', 'M', 'B', 'T']:
|
| 14 |
+
if abs(num) < 1000.0:
|
| 15 |
+
return f"{num:,.2f}{unit}".replace(".00", "")
|
| 16 |
+
num /= 1000.0
|
| 17 |
+
return f"{num:,.2f}P"
|
| 18 |
|
| 19 |
+
def calculate_deep_dive(coin_id: str, user_keys: dict):
|
| 20 |
+
cg_key = str(user_keys.get("COINGECKO_API_KEY", "")).strip()
|
| 21 |
+
coin_id = coin_id.strip().lower()
|
| 22 |
+
base_url = "https://api.coingecko.com/api/v3"
|
| 23 |
+
headers = STEALTH_HEADERS.copy()
|
| 24 |
|
| 25 |
+
if cg_key and cg_key != "CONFIG_REQUIRED_CG":
|
| 26 |
+
headers["x-cg-demo-api-key" if cg_key.startswith("CG-") else "x-cg-pro-api-key"] = cg_key
|
| 27 |
+
|
| 28 |
try:
|
| 29 |
+
r = requests.get(f"{base_url}/coins/{coin_id}?localization=false&tickers=true&market_data=true", headers=headers, timeout=15)
|
| 30 |
+
if r.status_code != 200: return {"status": "error", "message": f"API {r.status_code}"}
|
| 31 |
+
|
| 32 |
+
res = r.json()
|
| 33 |
+
mkt = res.get('market_data', {})
|
| 34 |
|
| 35 |
+
# RAW DATA (Restored v_ch_pct for perfect logic alignment)
|
| 36 |
+
mcap = mkt.get('market_cap', {}).get('usd', 0) or 0
|
| 37 |
+
vol = mkt.get('total_volume', {}).get('usd', 0) or 0
|
| 38 |
+
p_ch = mkt.get('price_change_percentage_24h', 0) or 0
|
| 39 |
+
v_ch_pct = mkt.get('total_volume_change_24h_percentage', 0) or 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
+
# 3. METRIC CALCULATIONS
|
| 42 |
+
# High-accuracy VTMR using Decimal to prevent approximation errors
|
| 43 |
+
d_vol = Decimal(str(vol))
|
| 44 |
+
d_mcap = Decimal(str(mcap))
|
| 45 |
+
# Rounding to 2 decimal places using standard financial ROUND_HALF_UP
|
| 46 |
+
vtmr_val = (d_vol / d_mcap).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) if d_mcap > 0 else 0
|
| 47 |
|
| 48 |
+
vtpc_val = vol / abs(p_ch) if p_ch != 0 else 0
|
| 49 |
+
current_price = mkt.get('current_price', {}).get('usd', 0)
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
+
return {
|
| 52 |
+
"status": "success",
|
| 53 |
+
"vitals": {
|
| 54 |
+
"name": res.get('name', 'Unknown'),
|
| 55 |
+
"symbol": res.get('symbol', '').upper(),
|
| 56 |
+
"price": f"${current_price:,.8f}" if current_price < 1 else f"${current_price:,.2f}",
|
| 57 |
+
"mcap": f"${format_compact(mcap)}",
|
| 58 |
+
"vol24h": f"${format_compact(vol)}"
|
| 59 |
+
},
|
| 60 |
+
"ratios": {
|
| 61 |
+
"vtmr": f"{vtmr_val}x",
|
| 62 |
+
"vtpc": f"${format_compact(vtpc_val)}"
|
| 63 |
+
},
|
| 64 |
+
"velocity": {
|
| 65 |
+
"h24": f"{p_ch:+.2f}%",
|
| 66 |
+
"d7": f"{(mkt.get('price_change_percentage_7d') or 0):+.2f}%",
|
| 67 |
+
"m1": f"{(mkt.get('price_change_percentage_30d') or 0):+.2f}%",
|
| 68 |
+
"y1": f"{(mkt.get('price_change_percentage_1y') or 0):+.2f}%"
|
| 69 |
+
},
|
| 70 |
+
"supply": {
|
| 71 |
+
"total": format_compact(mkt.get('total_supply', 0))
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
+
except Exception as e:
|
| 75 |
+
return {"status": "error", "message": str(e)}
|