Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -21,7 +21,7 @@ for module_name, pip_name in REQUIRED_PACKAGES.items():
|
|
| 21 |
print(f"✅ {pip_name} установлен!")
|
| 22 |
|
| 23 |
# ============================================
|
| 24 |
-
# 👑 TOMIRIS SPACE 26 v2.
|
| 25 |
# ============================================
|
| 26 |
import os, time, json, logging, asyncio
|
| 27 |
from typing import Dict, Any, List, Optional
|
|
@@ -37,7 +37,6 @@ logger = logging.getLogger("Space26_Options")
|
|
| 37 |
|
| 38 |
# ================= КОНФИГУРАЦИЯ =================
|
| 39 |
SYMBOLS = ["XAU/USD", "ETH/USD", "SOL/USD"]
|
| 40 |
-
ARBITER_URL = os.getenv("SPACE18_URL", "https://tomiris-ai-name6-6.hf.space")
|
| 41 |
HUB_URL = os.getenv("SPACE17_URL", "https://tomiris-ai-name5-5.hf.space")
|
| 42 |
TWELVE_DATA_KEY = os.getenv("TWELVE_DATA_KEY", "58e67e0008e24161ac9b1671b7c2d2d0")
|
| 43 |
FRED_KEY = os.getenv("FRED_KEY", "faa11c8e2e4beee08c5b966e8b63a513")
|
|
@@ -87,7 +86,7 @@ def save_history():
|
|
| 87 |
with open(HISTORY_FILE, 'w') as f:
|
| 88 |
json.dump(list(OPTIONS_HISTORY), f)
|
| 89 |
|
| 90 |
-
# ================= ЗАГРУЗКА ДАННЫХ =================
|
| 91 |
async def fetch_vix() -> Dict[str, Any]:
|
| 92 |
if breaker_open("vix"): return {"vix": 20.0, "level": "NORMAL", "signal": "NEUTRAL"}
|
| 93 |
try:
|
|
@@ -208,7 +207,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 208 |
native = "XAU" if "XAU" in symbol else ("ETH" if "ETH" in symbol else "SOL")
|
| 209 |
bin_sym = "" if native == "XAU" else (native + "USDT")
|
| 210 |
|
| 211 |
-
# Запускаем сбор параллельно
|
| 212 |
tasks = []
|
| 213 |
if bin_sym:
|
| 214 |
tasks.extend([fetch_funding_rate(bin_sym), fetch_open_interest(bin_sym), fetch_long_short_ratio(bin_sym)])
|
|
@@ -219,7 +217,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 219 |
tasks.append(fetch_vix())
|
| 220 |
|
| 221 |
results = await asyncio.gather(*tasks)
|
| 222 |
-
# Распределяем результаты
|
| 223 |
idx = 0
|
| 224 |
metrics = {}
|
| 225 |
if bin_sym:
|
|
@@ -230,19 +227,17 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 230 |
metrics['options'] = results[idx]; idx += 1
|
| 231 |
if native == "XAU":
|
| 232 |
metrics['gold_derivatives'] = results[idx]; idx += 1
|
| 233 |
-
vix_data = results[idx]
|
| 234 |
|
| 235 |
signals = []
|
| 236 |
score = 50.0
|
| 237 |
|
| 238 |
-
# VIX
|
| 239 |
if vix_data["vix"] > 30:
|
| 240 |
signals.append({"source": "VIX", "signal": "BEARISH_RISK", "reason": f"VIX={vix_data['vix']:.1f}"})
|
| 241 |
score += 15 if native == "XAU" else -10
|
| 242 |
elif vix_data["vix"] > 25:
|
| 243 |
score += 5
|
| 244 |
|
| 245 |
-
# Funding
|
| 246 |
fund = metrics.get('funding_rate', {})
|
| 247 |
if fund.get('signal') == 'BEARISH':
|
| 248 |
signals.append({"source": "FUNDING", "signal": "BEARISH", "reason": f"Перегретый лонг ({fund.get('funding_rate_pct')}%)"})
|
|
@@ -251,7 +246,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 251 |
signals.append({"source": "FUNDING", "signal": "BULLISH", "reason": f"Перегретый шорт ({fund.get('funding_rate_pct')}%)"})
|
| 252 |
score += 15
|
| 253 |
|
| 254 |
-
# OI
|
| 255 |
oi = metrics.get('open_interest', {})
|
| 256 |
if oi.get('signal') == 'BEARISH':
|
| 257 |
signals.append({"source": "OI", "signal": "BEARISH", "reason": f"OI перегрет ({oi.get('change_pct')}%)"})
|
|
@@ -260,7 +254,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 260 |
signals.append({"source": "OI", "signal": "BULLISH", "reason": f"OI растёт ({oi.get('change_pct')}%)"})
|
| 261 |
score += 10
|
| 262 |
|
| 263 |
-
# L/S
|
| 264 |
lsr = metrics.get('long_short_ratio', {})
|
| 265 |
if lsr.get('signal') == 'BEARISH':
|
| 266 |
signals.append({"source": "L/S", "signal": "BEARISH", "reason": f"Слишком много лонгов ({lsr.get('long_pct')}%)"})
|
|
@@ -269,7 +262,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 269 |
signals.append({"source": "L/S", "signal": "BULLISH", "reason": f"Много шортов ({lsr.get('short_pct')}%)"})
|
| 270 |
score += 10
|
| 271 |
|
| 272 |
-
# Options
|
| 273 |
options = metrics.get('options', {})
|
| 274 |
if options.get('signal') == 'BEARISH':
|
| 275 |
signals.append({"source": "OPTIONS", "signal": "BEARISH", "reason": f"PCR={options.get('put_call_ratio_volume')}"})
|
|
@@ -278,7 +270,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 278 |
signals.append({"source": "OPTIONS", "signal": "BULLISH", "reason": f"PCR={options.get('put_call_ratio_volume')}"})
|
| 279 |
score += 8
|
| 280 |
|
| 281 |
-
# Gold
|
| 282 |
gold = metrics.get('gold_derivatives', {})
|
| 283 |
if gold.get('signal') == 'BULLISH':
|
| 284 |
signals.append({"source": "COT/DXY/TIPS", "signal": "BULLISH", "reason": "Макро-факторы за золото"})
|
|
@@ -287,7 +278,6 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 287 |
signals.append({"source": "COT/DXY/TIPS", "signal": "BEARISH", "reason": "Макро-факторы против золота"})
|
| 288 |
score -= 12
|
| 289 |
|
| 290 |
-
# Max Pain (если цена известна)
|
| 291 |
price = await get_current_price(symbol) if native != "XAU" else 0
|
| 292 |
max_pain = calculate_max_pain(price) if price > 0 else 0
|
| 293 |
if max_pain > 0 and price < max_pain:
|
|
@@ -317,12 +307,29 @@ async def analyze_derivatives(symbol: str) -> Dict[str, Any]:
|
|
| 317 |
save_history()
|
| 318 |
return analysis
|
| 319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
# ================= ГЛАВНЫЙ СИГНАЛ =================
|
| 321 |
async def get_derivative_signal(symbol: str = "ETH/USD") -> Dict[str, Any]:
|
| 322 |
start = time.time()
|
| 323 |
analysis = await analyze_derivatives(symbol)
|
| 324 |
latency = int((time.time() - start) * 1000)
|
| 325 |
|
|
|
|
|
|
|
|
|
|
| 326 |
result = {
|
| 327 |
"space": "space_26_options",
|
| 328 |
"timestamp": int(time.time()),
|
|
@@ -332,21 +339,11 @@ async def get_derivative_signal(symbol: str = "ETH/USD") -> Dict[str, Any]:
|
|
| 332 |
"latency_ms": latency
|
| 333 |
}
|
| 334 |
|
| 335 |
-
try:
|
| 336 |
-
await http_client.post(f"{ARBITER_URL}/log_signal", json={
|
| 337 |
-
"space": "space_26_options",
|
| 338 |
-
"symbol": symbol,
|
| 339 |
-
"signal": result["signal"],
|
| 340 |
-
"options_details": {"score": analysis['derivative_score'], "signals": analysis['signals']}
|
| 341 |
-
})
|
| 342 |
-
except:
|
| 343 |
-
pass
|
| 344 |
-
|
| 345 |
logger.info(f"📊 Options {symbol}: {analysis['direction']} conf={analysis['confidence']:.3f} score={analysis['derivative_score']}")
|
| 346 |
return result
|
| 347 |
|
| 348 |
# ================= FASTAPI =================
|
| 349 |
-
app = FastAPI(title="Tomiris Space 26 v2.
|
| 350 |
|
| 351 |
@app.on_event("startup")
|
| 352 |
async def startup(): pass
|
|
@@ -356,7 +353,7 @@ async def shutdown(): await http_client.aclose()
|
|
| 356 |
|
| 357 |
@app.get("/health")
|
| 358 |
async def health():
|
| 359 |
-
return {"status": "operational", "version": "2.
|
| 360 |
|
| 361 |
@app.get("/consilium")
|
| 362 |
async def consilium(symbol: str = Query("ETH/USD")):
|
|
@@ -394,4 +391,4 @@ if __name__ == "__main__":
|
|
| 394 |
import uvicorn
|
| 395 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
| 396 |
|
| 397 |
-
print("🚀 SPACE 26 v2.
|
|
|
|
| 21 |
print(f"✅ {pip_name} установлен!")
|
| 22 |
|
| 23 |
# ============================================
|
| 24 |
+
# 👑 TOMIRIS SPACE 26 v2.3 — OPTIONS & DERIVATIVES ENGINE (Hub-Connected)
|
| 25 |
# ============================================
|
| 26 |
import os, time, json, logging, asyncio
|
| 27 |
from typing import Dict, Any, List, Optional
|
|
|
|
| 37 |
|
| 38 |
# ================= КОНФИГУРАЦИЯ =================
|
| 39 |
SYMBOLS = ["XAU/USD", "ETH/USD", "SOL/USD"]
|
|
|
|
| 40 |
HUB_URL = os.getenv("SPACE17_URL", "https://tomiris-ai-name5-5.hf.space")
|
| 41 |
TWELVE_DATA_KEY = os.getenv("TWELVE_DATA_KEY", "58e67e0008e24161ac9b1671b7c2d2d0")
|
| 42 |
FRED_KEY = os.getenv("FRED_KEY", "faa11c8e2e4beee08c5b966e8b63a513")
|
|
|
|
| 86 |
with open(HISTORY_FILE, 'w') as f:
|
| 87 |
json.dump(list(OPTIONS_HISTORY), f)
|
| 88 |
|
| 89 |
+
# ================= ЗАГРУЗКА ДАННЫХ (без изменений) =================
|
| 90 |
async def fetch_vix() -> Dict[str, Any]:
|
| 91 |
if breaker_open("vix"): return {"vix": 20.0, "level": "NORMAL", "signal": "NEUTRAL"}
|
| 92 |
try:
|
|
|
|
| 207 |
native = "XAU" if "XAU" in symbol else ("ETH" if "ETH" in symbol else "SOL")
|
| 208 |
bin_sym = "" if native == "XAU" else (native + "USDT")
|
| 209 |
|
|
|
|
| 210 |
tasks = []
|
| 211 |
if bin_sym:
|
| 212 |
tasks.extend([fetch_funding_rate(bin_sym), fetch_open_interest(bin_sym), fetch_long_short_ratio(bin_sym)])
|
|
|
|
| 217 |
tasks.append(fetch_vix())
|
| 218 |
|
| 219 |
results = await asyncio.gather(*tasks)
|
|
|
|
| 220 |
idx = 0
|
| 221 |
metrics = {}
|
| 222 |
if bin_sym:
|
|
|
|
| 227 |
metrics['options'] = results[idx]; idx += 1
|
| 228 |
if native == "XAU":
|
| 229 |
metrics['gold_derivatives'] = results[idx]; idx += 1
|
| 230 |
+
vix_data = results[idx]
|
| 231 |
|
| 232 |
signals = []
|
| 233 |
score = 50.0
|
| 234 |
|
|
|
|
| 235 |
if vix_data["vix"] > 30:
|
| 236 |
signals.append({"source": "VIX", "signal": "BEARISH_RISK", "reason": f"VIX={vix_data['vix']:.1f}"})
|
| 237 |
score += 15 if native == "XAU" else -10
|
| 238 |
elif vix_data["vix"] > 25:
|
| 239 |
score += 5
|
| 240 |
|
|
|
|
| 241 |
fund = metrics.get('funding_rate', {})
|
| 242 |
if fund.get('signal') == 'BEARISH':
|
| 243 |
signals.append({"source": "FUNDING", "signal": "BEARISH", "reason": f"Перегретый лонг ({fund.get('funding_rate_pct')}%)"})
|
|
|
|
| 246 |
signals.append({"source": "FUNDING", "signal": "BULLISH", "reason": f"Перегретый шорт ({fund.get('funding_rate_pct')}%)"})
|
| 247 |
score += 15
|
| 248 |
|
|
|
|
| 249 |
oi = metrics.get('open_interest', {})
|
| 250 |
if oi.get('signal') == 'BEARISH':
|
| 251 |
signals.append({"source": "OI", "signal": "BEARISH", "reason": f"OI перегрет ({oi.get('change_pct')}%)"})
|
|
|
|
| 254 |
signals.append({"source": "OI", "signal": "BULLISH", "reason": f"OI растёт ({oi.get('change_pct')}%)"})
|
| 255 |
score += 10
|
| 256 |
|
|
|
|
| 257 |
lsr = metrics.get('long_short_ratio', {})
|
| 258 |
if lsr.get('signal') == 'BEARISH':
|
| 259 |
signals.append({"source": "L/S", "signal": "BEARISH", "reason": f"Слишком много лонгов ({lsr.get('long_pct')}%)"})
|
|
|
|
| 262 |
signals.append({"source": "L/S", "signal": "BULLISH", "reason": f"Много шортов ({lsr.get('short_pct')}%)"})
|
| 263 |
score += 10
|
| 264 |
|
|
|
|
| 265 |
options = metrics.get('options', {})
|
| 266 |
if options.get('signal') == 'BEARISH':
|
| 267 |
signals.append({"source": "OPTIONS", "signal": "BEARISH", "reason": f"PCR={options.get('put_call_ratio_volume')}"})
|
|
|
|
| 270 |
signals.append({"source": "OPTIONS", "signal": "BULLISH", "reason": f"PCR={options.get('put_call_ratio_volume')}"})
|
| 271 |
score += 8
|
| 272 |
|
|
|
|
| 273 |
gold = metrics.get('gold_derivatives', {})
|
| 274 |
if gold.get('signal') == 'BULLISH':
|
| 275 |
signals.append({"source": "COT/DXY/TIPS", "signal": "BULLISH", "reason": "Макро-факторы за золото"})
|
|
|
|
| 278 |
signals.append({"source": "COT/DXY/TIPS", "signal": "BEARISH", "reason": "Макро-факторы против золота"})
|
| 279 |
score -= 12
|
| 280 |
|
|
|
|
| 281 |
price = await get_current_price(symbol) if native != "XAU" else 0
|
| 282 |
max_pain = calculate_max_pain(price) if price > 0 else 0
|
| 283 |
if max_pain > 0 and price < max_pain:
|
|
|
|
| 307 |
save_history()
|
| 308 |
return analysis
|
| 309 |
|
| 310 |
+
# ================= ОТПРАВКА В HUB =================
|
| 311 |
+
async def send_signal_to_hub(symbol: str, direction: str, confidence: float):
|
| 312 |
+
try:
|
| 313 |
+
await http_client.post(f"{HUB_URL}/signal", json={
|
| 314 |
+
"space": "space_26_options",
|
| 315 |
+
"symbol": symbol,
|
| 316 |
+
"direction": direction,
|
| 317 |
+
"confidence": confidence,
|
| 318 |
+
"raw": json.dumps({"source": "space_26_options"})
|
| 319 |
+
})
|
| 320 |
+
logger.info(f"📤 {symbol}: {direction} conf={confidence:.3f} отправлен в Hub")
|
| 321 |
+
except Exception as e:
|
| 322 |
+
logger.error(f"Ошибка отправки в Hub: {e}")
|
| 323 |
+
|
| 324 |
# ================= ГЛАВНЫЙ СИГНАЛ =================
|
| 325 |
async def get_derivative_signal(symbol: str = "ETH/USD") -> Dict[str, Any]:
|
| 326 |
start = time.time()
|
| 327 |
analysis = await analyze_derivatives(symbol)
|
| 328 |
latency = int((time.time() - start) * 1000)
|
| 329 |
|
| 330 |
+
# Отправка в Hub
|
| 331 |
+
await send_signal_to_hub(symbol, analysis['direction'], analysis['confidence'])
|
| 332 |
+
|
| 333 |
result = {
|
| 334 |
"space": "space_26_options",
|
| 335 |
"timestamp": int(time.time()),
|
|
|
|
| 339 |
"latency_ms": latency
|
| 340 |
}
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
logger.info(f"📊 Options {symbol}: {analysis['direction']} conf={analysis['confidence']:.3f} score={analysis['derivative_score']}")
|
| 343 |
return result
|
| 344 |
|
| 345 |
# ================= FASTAPI =================
|
| 346 |
+
app = FastAPI(title="Tomiris Space 26 v2.3 — Options & Derivatives Engine (Hub)")
|
| 347 |
|
| 348 |
@app.on_event("startup")
|
| 349 |
async def startup(): pass
|
|
|
|
| 353 |
|
| 354 |
@app.get("/health")
|
| 355 |
async def health():
|
| 356 |
+
return {"status": "operational", "version": "2.3", "hub_connected": True, "features": ["VIX", "Funding", "OI", "L/S", "Options PCR", "COT/DXY/TIPS", "Max Pain"]}
|
| 357 |
|
| 358 |
@app.get("/consilium")
|
| 359 |
async def consilium(symbol: str = Query("ETH/USD")):
|
|
|
|
| 391 |
import uvicorn
|
| 392 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
| 393 |
|
| 394 |
+
print("🚀 SPACE 26 v2.3 — OPTIONS & DERIVATIVES ENGINE (Hub-Connected) ЗАПУЩЕН!")
|