tomirisg25 commited on
Commit
aab61df
·
verified ·
1 Parent(s): b49658f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -95
app.py CHANGED
@@ -21,9 +21,7 @@ for module_name, pip_name in REQUIRED_PACKAGES.items():
21
  print(f"✅ {pip_name} установлен!")
22
 
23
  # ============================================
24
- # 👑 TOMIRIS SPACE 25 v3.0 — INTERMARKET CORRELATION ENGINE (PRO-8/tomiris-correlation)
25
- # Миграция с v2.2. Все функции сохранены.
26
- # HUB_URL обновлён, HUB_SECRET во всех запросах.
27
  # ============================================
28
  import os, time, json, logging, asyncio
29
  from typing import Dict, Any, List, Optional, Tuple
@@ -38,6 +36,9 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(level
38
  logger = logging.getLogger("Space25_Correlation")
39
 
40
  # ================= КОНФИГУРАЦИЯ =================
 
 
 
41
  SYMBOLS = ["XAU/USD", "ETH/USD", "SOL/USD"]
42
 
43
  CORRELATION_PAIRS = {
@@ -57,17 +58,15 @@ TICKER_MAP = {
57
  "TIPS": "TIP"
58
  }
59
 
60
- # ================= ОБНОВЛЁННЫЙ HUB URL =================
61
- HUB_URL = "https://pro-3-tomiris-hub.hf.space"
62
  HUB_SECRET = os.getenv("HUB_SECRET", "TomyrisUltraSecret2026!")
 
63
 
64
- TWELVE_DATA_KEY = os.getenv("TWELVE_DATA_KEY", "e3740c072fda4fe8b8539d40b07e445e")
65
-
66
- # ================= СТАРТОВЫЙ СОН =================
67
- STARTUP_SLEEP = int(os.getenv("STARTUP_SLEEP", 600)) # 10 минут
68
 
69
- # Интервал авто-отправки
70
- AUTO_SEND_INTERVAL = int(os.getenv("AUTO_SEND_INTERVAL", "600")) # 10 минут
71
 
72
  HISTORY_FILE = "correlation_history.json"
73
  CACHE_TTL = 300
@@ -75,9 +74,11 @@ CACHE_TTL = 300
75
  # ================= HTTP КЛИЕНТ =================
76
  http_client = httpx.AsyncClient(timeout=15.0)
77
 
78
- # ================= ЗАГОЛОВКИ ДЛЯ ХАБА =================
79
  def hub_headers():
80
- return {"X-Hub-Secret": HUB_SECRET} if HUB_SECRET else {}
 
 
 
81
 
82
  # ================= ГЛОБАЛЬНЫЙ КЭШ И BREAKER =================
83
  price_cache = {}
@@ -112,12 +113,14 @@ else:
112
  DIVERGENCE_HISTORY = deque(maxlen=500)
113
 
114
  def save_history():
115
- with open(HISTORY_FILE, 'w') as f:
116
- json.dump(list(DIVERGENCE_HISTORY), f)
 
 
 
117
 
118
  # ================= ЗАГРУЗКА ЦЕН =================
119
  async def fetch_prices_hub(symbol: str, count: int = 100) -> Optional[np.ndarray]:
120
- """Загружает цены через Хаб (свечи Binance)"""
121
  cache_key = f"hub_{symbol}_{count}"
122
  now = time.time()
123
  if cache_key in price_cache and (now - cache_timestamps.get(cache_key, 0)) < CACHE_TTL:
@@ -143,7 +146,6 @@ async def fetch_prices_hub(symbol: str, count: int = 100) -> Optional[np.ndarray
143
  return None
144
 
145
  async def fetch_prices_twelvedata(symbol: str, count: int = 100) -> Optional[np.ndarray]:
146
- """Fallback: Twelve Data API"""
147
  if breaker_open("twelvedata"):
148
  return None
149
 
@@ -161,7 +163,6 @@ async def fetch_prices_twelvedata(symbol: str, count: int = 100) -> Optional[np.
161
  return None
162
 
163
  async def fetch_prices(symbol: str, count: int = 100) -> Optional[np.ndarray]:
164
- """Основной метод: сначала Хаб, потом Twelve Data"""
165
  prices = await fetch_prices_hub(symbol, count)
166
  if prices is None:
167
  prices = await fetch_prices_twelvedata(symbol, count)
@@ -242,7 +243,7 @@ async def analyze_correlations(symbol: str) -> Dict[str, Any]:
242
  if symbol not in prices:
243
  return {
244
  "correlation_score": 50.0,
245
- "direction": "WAIT",
246
  "confidence": 0.0,
247
  "correlations": [],
248
  "divergences": [],
@@ -287,12 +288,16 @@ async def analyze_correlations(symbol: str) -> Dict[str, Any]:
287
 
288
  score = max(0, min(100, score))
289
 
 
290
  if score > 60:
291
- direction, confidence = "LONG", score / 100
 
292
  elif score < 40:
293
- direction, confidence = "SHORT", (100 - score) / 100
 
294
  else:
295
- direction, confidence = "WAIT", 0.0
 
296
 
297
  if divergences:
298
  DIVERGENCE_HISTORY.append({
@@ -305,7 +310,7 @@ async def analyze_correlations(symbol: str) -> Dict[str, Any]:
305
 
306
  return {
307
  "correlation_score": score,
308
- "direction": direction,
309
  "confidence": round(confidence, 4),
310
  "correlations": correlations,
311
  "divergences": divergences,
@@ -314,44 +319,41 @@ async def analyze_correlations(symbol: str) -> Dict[str, Any]:
314
  "active_pairs": len(correlations)
315
  }
316
 
317
- # ================= ОТПРАВКА В HUB =================
318
- async def send_signal_to_hub(symbol: str, direction: str, confidence: float):
319
- try:
320
- payload = {
321
- "space": "space_25_correlation",
322
- "space_name": "space_25_correlation",
323
- "symbol": symbol,
324
- "direction": direction,
325
- "confidence": confidence,
326
- "features": {},
327
- "metadata": {"version": "3.0", "source": "PRO-8/tomiris-correlation"}
328
- }
329
- r = await http_client.post(
330
- f"{HUB_URL}/signals",
331
- json=payload,
332
- timeout=10,
333
- headers=hub_headers()
334
- )
335
- if r.status_code == 200:
336
- logger.info(f"📤 {symbol}: {direction} conf={confidence:.3f} отправлен в Hub")
337
- else:
338
- r = await http_client.post(
339
- f"{HUB_URL}/signal",
340
- json={
341
- "space": "space_25_correlation",
342
- "symbol": symbol,
343
- "direction": direction,
344
- "confidence": confidence
345
- },
346
- timeout=10,
347
- headers=hub_headers()
348
- )
349
  if r.status_code == 200:
350
- logger.info(f"📤 {symbol}: {direction} conf={confidence:.3f} (через /signal)")
 
 
 
 
 
351
  else:
352
- logger.warning(f"Hub вернул {r.status_code}")
353
- except Exception as e:
354
- logger.error(f"Ошибка отправки в Hub: {e}")
 
 
 
 
355
 
356
  # ================= ГЛАВНЫЙ СИГНАЛ =================
357
  async def get_correlation_signal(symbol: str = "XAU/USD") -> Dict[str, Any]:
@@ -359,53 +361,46 @@ async def get_correlation_signal(symbol: str = "XAU/USD") -> Dict[str, Any]:
359
  analysis = await analyze_correlations(symbol)
360
  latency = int((time.time() - start) * 1000)
361
 
362
- await send_signal_to_hub(symbol, analysis['direction'], analysis['confidence'])
 
 
 
 
 
363
 
364
- result = {
365
- "space": "space_25_correlation",
 
366
  "timestamp": int(time.time()),
367
  "symbol": symbol,
368
- "signal": {
369
- "direction": analysis['direction'],
370
- "confidence": analysis['confidence']
371
- },
372
- "correlation_analysis": {
373
- "score": analysis['correlation_score'],
374
- "active_pairs": analysis['active_pairs'],
375
- "correlations": analysis['correlations'],
376
- "divergences": analysis['divergences'],
377
- "divergence_count": analysis['divergence_count'],
378
- "signals": analysis['signals']
379
- },
380
- "latency_ms": latency
381
  }
382
 
383
- logger.info(f"🔗 Correlation {symbol}: {analysis['direction']} conf={analysis['confidence']:.3f}")
384
- return result
385
-
386
  # ================= АВТО-ОТПРАВКА =================
387
  async def auto_send_loop():
388
- logger.info(f"⏳ Стартовый сон {STARTUP_SLEEP} секунд...")
389
  await asyncio.sleep(STARTUP_SLEEP)
390
- logger.info(f"🔄 Авто-отправка Correlation Engine запущена (интервал {AUTO_SEND_INTERVAL}с)")
391
 
392
  while True:
393
  try:
394
  for symbol in SYMBOLS:
395
  await get_correlation_signal(symbol)
396
  await asyncio.sleep(2)
397
- logger.info("✅ Correlation Engine авто-отправка завершена")
398
  except Exception as e:
399
  logger.error(f"Ошибка авто-отправки: {e}")
400
  await asyncio.sleep(AUTO_SEND_INTERVAL)
401
 
402
  # ================= FASTAPI =================
403
- app = FastAPI(title="Tomiris Space 25 v3.0Intermarket Correlation Engine (PRO-8)")
404
 
405
  @app.on_event("startup")
406
  async def startup():
407
  asyncio.create_task(auto_send_loop())
408
- logger.info("🚀 Space 25 v3.0 запущен на PRO-8/tomiris-correlation")
409
 
410
  @app.on_event("shutdown")
411
  async def shutdown():
@@ -414,16 +409,18 @@ async def shutdown():
414
  @app.get("/health")
415
  async def health():
416
  return {
 
417
  "status": "operational",
418
- "version": "3.0",
419
- "space": "PRO-8/tomiris-correlation",
420
  "hub_url": HUB_URL,
421
- "auto_send_interval": AUTO_SEND_INTERVAL,
422
- "startup_sleep": STARTUP_SLEEP,
423
  "symbols": SYMBOLS,
424
  "history_length": len(DIVERGENCE_HISTORY)
425
  }
426
 
 
 
 
 
427
  @app.get("/consilium")
428
  async def consilium(symbol: str = Query("XAU/USD")):
429
  if symbol not in SYMBOLS:
@@ -459,20 +456,16 @@ async def all_correlations():
459
  async def send_now():
460
  results = {}
461
  for symbol in SYMBOLS:
462
- analysis = await get_correlation_signal(symbol)
463
- results[symbol] = analysis.get("signal", {}).get("direction", "WAIT")
464
  return {"status": "sent", "results": results}
465
 
466
  @app.get("/")
467
  async def root():
468
- return {
469
- "name": "Correlation Engine v3.0",
470
- "space": "PRO-8/tomiris-correlation",
471
- "hub": HUB_URL
472
- }
473
 
474
  if __name__ == "__main__":
475
  import uvicorn
476
  uvicorn.run(app, host="0.0.0.0", port=7860)
477
 
478
- print("🚀 SPACE 25 v3.0INTERMARKET CORRELATION ENGINE (PRO-8/tomiris-correlation) ЗАПУЩЕН!")
 
21
  print(f"✅ {pip_name} установлен!")
22
 
23
  # ============================================
24
+ # 👑 TOMIRIS SPACE 25 v3.1 — INTERMARKET CORRELATION ENGINE (FIXED)
 
 
25
  # ============================================
26
  import os, time, json, logging, asyncio
27
  from typing import Dict, Any, List, Optional, Tuple
 
36
  logger = logging.getLogger("Space25_Correlation")
37
 
38
  # ================= КОНФИГУРАЦИЯ =================
39
+ SPACE_ID = 25
40
+ SPACE_NAME = "Correlation Engine"
41
+
42
  SYMBOLS = ["XAU/USD", "ETH/USD", "SOL/USD"]
43
 
44
  CORRELATION_PAIRS = {
 
58
  "TIPS": "TIP"
59
  }
60
 
61
+ # ================= НАСТРОЙКИ =================
62
+ HUB_URL = os.getenv("HUB_URL", "https://pro-3-tomiris-hub.hf.space")
63
  HUB_SECRET = os.getenv("HUB_SECRET", "TomyrisUltraSecret2026!")
64
+ TWELVE_DATA_KEY = os.getenv("TWELVE_DATA_KEY", "a5da25be2e4f41bab4cd78ed8461e180")
65
 
66
+ STARTUP_SLEEP = int(os.getenv("STARTUP_SLEEP", "600"))
67
+ AUTO_SEND_INTERVAL = int(os.getenv("AUTO_SEND_INTERVAL", "600"))
 
 
68
 
69
+ logger.info(f"🔗 Хаб: {HUB_URL}")
 
70
 
71
  HISTORY_FILE = "correlation_history.json"
72
  CACHE_TTL = 300
 
74
  # ================= HTTP КЛИЕНТ =================
75
  http_client = httpx.AsyncClient(timeout=15.0)
76
 
 
77
  def hub_headers():
78
+ return {
79
+ "X-Hub-Secret": HUB_SECRET,
80
+ "Content-Type": "application/json"
81
+ }
82
 
83
  # ================= ГЛОБАЛЬНЫЙ КЭШ И BREAKER =================
84
  price_cache = {}
 
113
  DIVERGENCE_HISTORY = deque(maxlen=500)
114
 
115
  def save_history():
116
+ try:
117
+ with open(HISTORY_FILE, 'w') as f:
118
+ json.dump(list(DIVERGENCE_HISTORY), f)
119
+ except:
120
+ pass
121
 
122
  # ================= ЗАГРУЗКА ЦЕН =================
123
  async def fetch_prices_hub(symbol: str, count: int = 100) -> Optional[np.ndarray]:
 
124
  cache_key = f"hub_{symbol}_{count}"
125
  now = time.time()
126
  if cache_key in price_cache and (now - cache_timestamps.get(cache_key, 0)) < CACHE_TTL:
 
146
  return None
147
 
148
  async def fetch_prices_twelvedata(symbol: str, count: int = 100) -> Optional[np.ndarray]:
 
149
  if breaker_open("twelvedata"):
150
  return None
151
 
 
163
  return None
164
 
165
  async def fetch_prices(symbol: str, count: int = 100) -> Optional[np.ndarray]:
 
166
  prices = await fetch_prices_hub(symbol, count)
167
  if prices is None:
168
  prices = await fetch_prices_twelvedata(symbol, count)
 
243
  if symbol not in prices:
244
  return {
245
  "correlation_score": 50.0,
246
+ "signal": "WAIT",
247
  "confidence": 0.0,
248
  "correlations": [],
249
  "divergences": [],
 
288
 
289
  score = max(0, min(100, score))
290
 
291
+ # 🔥 BUY/SELL вместо LONG/SHORT
292
  if score > 60:
293
+ signal = "BUY"
294
+ confidence = score / 100
295
  elif score < 40:
296
+ signal = "SELL"
297
+ confidence = (100 - score) / 100
298
  else:
299
+ signal = "WAIT"
300
+ confidence = 0.0
301
 
302
  if divergences:
303
  DIVERGENCE_HISTORY.append({
 
310
 
311
  return {
312
  "correlation_score": score,
313
+ "signal": signal,
314
  "confidence": round(confidence, 4),
315
  "correlations": correlations,
316
  "divergences": divergences,
 
319
  "active_pairs": len(correlations)
320
  }
321
 
322
+ # ================= ОТПРАВКА В HUB (ИСПРАВЛЕНО) =================
323
+ async def send_signal_to_hub(symbol: str, signal: str, confidence: float, features: Dict = None):
324
+ if features is None:
325
+ features = {}
326
+
327
+ payload = {
328
+ "space_id": SPACE_ID,
329
+ "space_name": SPACE_NAME,
330
+ "symbol": symbol,
331
+ "signal": signal, # ✅ BUY/SELL/WAIT
332
+ "confidence": round(confidence, 4),
333
+ "features": features,
334
+ "metadata": {"version": "3.1"},
335
+ "timestamp": datetime.now().isoformat()
336
+ }
337
+
338
+ for attempt in range(3):
339
+ try:
340
+ headers = hub_headers()
341
+ r = await http_client.post(f"{HUB_URL}/signals", json=payload, timeout=15, headers=headers)
 
 
 
 
 
 
 
 
 
 
 
 
342
  if r.status_code == 200:
343
+ logger.info(f"📤 {symbol}: {signal} conf={confidence:.3f}")
344
+ return
345
+ elif r.status_code == 429:
346
+ wait = 3 * (attempt + 1)
347
+ logger.warning(f"⏳ 429 для {symbol}, жду {wait}с...")
348
+ await asyncio.sleep(wait)
349
  else:
350
+ logger.warning(f"Попытка {attempt+1}: HTTP {r.status_code}")
351
+ await asyncio.sleep(2)
352
+ except Exception as e:
353
+ logger.warning(f"Попытка {attempt+1}: {e}")
354
+ await asyncio.sleep(2)
355
+
356
+ logger.error(f"❌ Не удалось отправить {symbol}")
357
 
358
  # ================= ГЛАВНЫЙ СИГНАЛ =================
359
  async def get_correlation_signal(symbol: str = "XAU/USD") -> Dict[str, Any]:
 
361
  analysis = await analyze_correlations(symbol)
362
  latency = int((time.time() - start) * 1000)
363
 
364
+ features = {
365
+ "correlation_score": analysis['correlation_score'],
366
+ "divergence_count": analysis['divergence_count'],
367
+ "active_pairs": analysis['active_pairs']
368
+ }
369
+ await send_signal_to_hub(symbol, analysis['signal'], analysis['confidence'], features)
370
 
371
+ logger.info(f"🔗 Correlation {symbol}: {analysis['signal']} conf={analysis['confidence']:.3f} | {latency}ms")
372
+ return {
373
+ "space_id": SPACE_ID,
374
  "timestamp": int(time.time()),
375
  "symbol": symbol,
376
+ "signal": analysis['signal'],
377
+ "confidence": analysis['confidence'],
378
+ "correlation_analysis": analysis
 
 
 
 
 
 
 
 
 
 
379
  }
380
 
 
 
 
381
  # ================= АВТО-ОТПРАВКА =================
382
  async def auto_send_loop():
383
+ logger.info(f"⏳ Стартовый сон {STARTUP_SLEEP}с...")
384
  await asyncio.sleep(STARTUP_SLEEP)
385
+ logger.info(f"🔄 Correlation Engine запущен (интервал {AUTO_SEND_INTERVAL}с)")
386
 
387
  while True:
388
  try:
389
  for symbol in SYMBOLS:
390
  await get_correlation_signal(symbol)
391
  await asyncio.sleep(2)
392
+ logger.info("✅ Correlation Engine цикл завершён")
393
  except Exception as e:
394
  logger.error(f"Ошибка авто-отправки: {e}")
395
  await asyncio.sleep(AUTO_SEND_INTERVAL)
396
 
397
  # ================= FASTAPI =================
398
+ app = FastAPI(title="Tomiris Space 25 v3.1 — Correlation Engine")
399
 
400
  @app.on_event("startup")
401
  async def startup():
402
  asyncio.create_task(auto_send_loop())
403
+ logger.info(f"🚀 Space 25 v3.1 ЗАПУЩЕН | Хаб: {HUB_URL}")
404
 
405
  @app.on_event("shutdown")
406
  async def shutdown():
 
409
  @app.get("/health")
410
  async def health():
411
  return {
412
+ "space_id": SPACE_ID,
413
  "status": "operational",
414
+ "version": "3.1",
 
415
  "hub_url": HUB_URL,
 
 
416
  "symbols": SYMBOLS,
417
  "history_length": len(DIVERGENCE_HISTORY)
418
  }
419
 
420
+ @app.head("/health")
421
+ async def health_head():
422
+ return {}
423
+
424
  @app.get("/consilium")
425
  async def consilium(symbol: str = Query("XAU/USD")):
426
  if symbol not in SYMBOLS:
 
456
  async def send_now():
457
  results = {}
458
  for symbol in SYMBOLS:
459
+ sig = await get_correlation_signal(symbol)
460
+ results[symbol] = sig.get("signal", "WAIT")
461
  return {"status": "sent", "results": results}
462
 
463
  @app.get("/")
464
  async def root():
465
+ return {"name": "Correlation Engine v3.1", "space_id": SPACE_ID, "hub": HUB_URL}
 
 
 
 
466
 
467
  if __name__ == "__main__":
468
  import uvicorn
469
  uvicorn.run(app, host="0.0.0.0", port=7860)
470
 
471
+ print("🚀 SPACE 25 v3.1 — CORRELATION ENGINE ГОТОВ К РАБОТЕ!")