Spaces:
Running
Running
| from flask import Flask, jsonify, render_template | |
| import requests | |
| import math | |
| import statistics | |
| import time | |
| app = Flask(__name__) | |
| # Helper: safe fetch with timeout | |
| def fetch_json(url): | |
| try: | |
| r = requests.get(url, timeout=5) | |
| r.raise_for_status() | |
| return r.json() | |
| except Exception as e: | |
| print("Fetch error:", e) | |
| return {} | |
| # Compute PHI components | |
| def compute_phi_metrics(symbol): | |
| # Binance endpoints | |
| ticker = fetch_json(f"https://api.binance.com/api/v3/ticker/24hr?symbol={symbol}") | |
| klines = fetch_json(f"https://api.binance.com/api/v3/klines?symbol={symbol}&interval=1h&limit=100") | |
| funding = fetch_json(f"https://fapi.binance.com/fapi/v1/fundingRate?symbol={symbol}&limit=1") | |
| oi = fetch_json(f"https://fapi.binance.com/fapi/v1/openInterest?symbol={symbol}") | |
| # Price data | |
| try: | |
| closes = [float(k[4]) for k in klines] | |
| returns = [math.log(closes[i]/closes[i-1]) for i in range(1, len(closes))] | |
| volx = min(100, statistics.pstdev(returns) * 5000) | |
| momx = max(0, min(100, ((closes[-1] - closes[0]) / closes[0]) * 200)) | |
| except Exception: | |
| volx = momx = 0 | |
| # Funding bias (FBS) and leverage pressure (LPI) | |
| try: | |
| fbs = float(funding[0]["fundingRate"]) * 10000 | |
| except Exception: | |
| fbs = 0 | |
| try: | |
| lpi = min(100, float(oi.get("openInterest", 0)) / 1e8) | |
| except Exception: | |
| lpi = 0 | |
| # PHI calculation | |
| phi_score = round(0.4 * momx + 0.3 * volx + 0.2 * abs(fbs) + 0.1 * lpi, 1) | |
| return { | |
| "symbol": symbol, | |
| "price": float(ticker.get("lastPrice", 0)), | |
| "change_24h": float(ticker.get("priceChangePercent", 0)), | |
| "funding_rate": fbs / 10000, | |
| "open_interest": float(oi.get("openInterest", 0)), | |
| "volx": volx, | |
| "momx": momx, | |
| "lpi": lpi, | |
| "phi_score": phi_score, | |
| "price_history": closes[-24:] if len(klines) >= 24 else [], | |
| } | |
| def home(): | |
| return render_template("index.html") | |
| def get_data(): | |
| btc = compute_phi_metrics("BTCUSDT") | |
| eth = compute_phi_metrics("ETHUSDT") | |
| # Weighted average PHI | |
| phi_score = round((btc["phi_score"] * 0.6 + eth["phi_score"] * 0.4), 1) | |
| # Global derived data | |
| data = { | |
| "phi_score": phi_score, | |
| "volx": round((btc["volx"] + eth["volx"]) / 2, 1), | |
| "momx": round((btc["momx"] + eth["momx"]) / 200, 2), # normalize to 0–1 scale | |
| "fbs": round((btc["funding_rate"] + eth["funding_rate"]) / 2, 6), | |
| "lpi": round((btc["lpi"] + eth["lpi"]) / 2, 1), | |
| "btc": btc, | |
| "eth": eth, | |
| # Realistic placeholders (to be expanded later) | |
| "long_short_ratio": 1.05, | |
| "fear_greed": {"value": 55, "label": "Neutral"}, | |
| "top_gainers": [ | |
| {"symbol": "SOLUSDT", "price": 148.5, "change": 3.2}, | |
| {"symbol": "AVAXUSDT", "price": 33.8, "change": 2.1}, | |
| {"symbol": "LINKUSDT", "price": 12.9, "change": 1.4} | |
| ], | |
| "top_losers": [ | |
| {"symbol": "DOGEUSDT", "price": 0.123, "change": -1.2}, | |
| {"symbol": "PEPEUSDT", "price": 0.000012, "change": -1.0} | |
| ], | |
| "funding_rates": { | |
| "Binance": btc["funding_rate"], | |
| "OKX": eth["funding_rate"] * 1.1, | |
| "Bybit": eth["funding_rate"] * 0.9, | |
| "Deribit": eth["funding_rate"] * 0.8, | |
| "Bitget": eth["funding_rate"] * 1.2 | |
| }, | |
| "open_interest": { | |
| "btc_history": [btc["open_interest"] * (0.95 + 0.1 * math.sin(i)) for i in range(7)], | |
| "eth_history": [eth["open_interest"] * (0.96 + 0.08 * math.cos(i)) for i in range(7)] | |
| }, | |
| "liquidations": { | |
| "longs": [abs(math.sin(i)) * 8_000_000 for i in range(8)], | |
| "shorts": [abs(math.cos(i)) * 7_000_000 for i in range(8)] | |
| } | |
| } | |
| return jsonify(data) | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0", port=7860) | |