tomirisai80 commited on
Commit
0cb5acf
·
verified ·
1 Parent(s): b0d61f6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -178
app.py CHANGED
@@ -22,7 +22,7 @@ for module_name, pip_name in REQUIRED_PACKAGES.items():
22
  print(f"✅ {pip_name} установлен!")
23
 
24
  # ============================================
25
- # 👑 TOMIRIS SPACE 20 v1.2 — ETHEREUM L2 & DEFI PULSE (АВТО-ОТПРАВКА)
26
  # ============================================
27
  from fastapi import FastAPI, Query
28
  from typing import Optional, Dict, Any, List
@@ -36,15 +36,27 @@ from collections import deque
36
  import warnings
37
  import os
38
  import json
 
39
 
40
  warnings.filterwarnings('ignore')
41
 
 
 
 
42
  # ================= КОНФИГУРАЦИЯ =================
43
- SYMBOL: str = "ETH/USD"
44
- HUB_URL = os.getenv("SPACE17_URL", "https://tomiris-ai-name5-5.hf.space")
 
 
 
 
 
45
 
46
- # Интервал авто-отправки
47
- AUTO_SEND_INTERVAL = int(os.getenv("AUTO_SEND_INTERVAL", "300"))
 
 
 
48
 
49
  L2_CHAINS: Dict[str, str] = {
50
  "Arbitrum": "Arbitrum",
@@ -61,25 +73,50 @@ DEFI_PROTOCOLS: List[str] = [
61
  # ================= ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ =================
62
  CACHE: Dict[str, Dict[str, Any]] = {}
63
  CACHE_TIMES: Dict[str, float] = {}
64
- FEATURES_STORE: Dict[str, Dict[str, Any]] = {}
65
- MT5_MAX_AGE_SEC: int = 300
 
 
 
 
 
66
 
67
  # ================= ОТПРАВКА В HUB =================
68
- def send_signal_to_hub(symbol: str, direction: str, confidence: float):
69
- try:
70
- resp = requests.post(f"{HUB_URL}/signal", json={
71
- "space": "space_20_l2_defi",
72
- "symbol": symbol,
73
- "direction": direction,
74
- "confidence": confidence,
75
- "raw": json.dumps({"source": "space_20_l2_defi"})
76
- }, timeout=10)
77
- if resp.status_code == 200:
78
- print(f"📤 {symbol}: {direction} conf={confidence:.3f} отправлен в Hub")
79
- else:
80
- print(f"⚠️ Hub вернул {resp.status_code}")
81
- except Exception as e:
82
- print(f"Ошибка отправки в Hub: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  # ================= ЗАГРУЗКА ДАННЫХ DeFiLlama =================
85
  def fetch_chain_tvl(chain: str) -> Optional[Dict[str, Any]]:
@@ -88,22 +125,40 @@ def fetch_chain_tvl(chain: str) -> Optional[Dict[str, Any]]:
88
  return CACHE[cache_key]
89
 
90
  try:
91
- r = requests.get(f"https://api.llama.fi/v2/tvl/{chain}", timeout=10)
92
  if r.status_code == 200:
93
- data = r.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  result = {
95
  'chain': chain,
96
- 'tvl': data.get('tvl', 0),
97
- 'tvl_billions': round(data.get('tvl', 0) / 1e9, 2),
98
- 'change_24h': data.get('change_1d', 0),
99
- 'change_7d': data.get('change_7d', 0),
100
- 'trend': 'UP' if data.get('change_1d', 0) > 0 else 'DOWN'
101
  }
102
  CACHE[cache_key] = result
103
  CACHE_TIMES[cache_key] = time.time()
104
  return result
105
  except Exception as e:
106
- print(f"⚠️ TVL {chain}: {e}")
107
  return None
108
 
109
  def fetch_all_l2_tvl() -> Dict[str, Any]:
@@ -124,7 +179,7 @@ def fetch_all_l2_tvl() -> Dict[str, Any]:
124
 
125
  avg_change = total_change / active_chains if active_chains > 0 else 0
126
 
127
- return {
128
  'chains': l2_data,
129
  'total_l2_tvl': round(total_tvl, 2),
130
  'total_l2_tvl_billions': round(total_tvl / 1e9, 2),
@@ -132,29 +187,20 @@ def fetch_all_l2_tvl() -> Dict[str, Any]:
132
  'trend': 'GROWING' if avg_change > 2 else 'SHRINKING' if avg_change < -2 else 'STABLE',
133
  'signal': 'BULLISH' if avg_change > 2 else 'BEARISH' if avg_change < -2 else 'NEUTRAL'
134
  }
 
 
135
 
136
  def fetch_ethereum_tvl() -> Dict[str, Any]:
137
  cache_key = "tvl_ethereum"
138
  if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
139
  return CACHE[cache_key]
140
 
141
- try:
142
- r = requests.get("https://api.llama.fi/v2/tvl/ethereum", timeout=10)
143
- if r.status_code == 200:
144
- data = r.json()
145
- result = {
146
- 'tvl': data.get('tvl', 0),
147
- 'tvl_billions': round(data.get('tvl', 0) / 1e9, 2),
148
- 'change_24h': data.get('change_1d', 0),
149
- 'change_7d': data.get('change_7d', 0),
150
- 'trend': 'UP' if data.get('change_1d', 0) > 0 else 'DOWN'
151
- }
152
- CACHE[cache_key] = result
153
- CACHE_TIMES[cache_key] = time.time()
154
- return result
155
- except:
156
- pass
157
- return {'tvl': 0, 'trend': 'STABLE'}
158
 
159
  # ================= СТЕЙКИНГ =================
160
  def fetch_staking_metrics() -> Dict[str, Any]:
@@ -164,26 +210,54 @@ def fetch_staking_metrics() -> Dict[str, Any]:
164
 
165
  result: Dict[str, Any] = {}
166
 
 
167
  try:
168
- r = requests.get("https://api.llama.fi/v2/tvl/lido", timeout=10)
169
  if r.status_code == 200:
170
- data = r.json()
171
- result['lido_tvl'] = data.get('tvl', 0)
172
- result['lido_tvl_billions'] = round(data.get('tvl', 0) / 1e9, 2)
173
- result['lido_change_24h'] = data.get('change_1d', 0)
 
 
 
 
 
 
 
 
174
  except:
175
  result['lido_tvl'] = 0
176
 
 
177
  try:
178
- r = requests.get("https://api.llama.fi/v2/tvl/eigenlayer", timeout=10)
179
  if r.status_code == 200:
180
- data = r.json()
181
- result['eigenlayer_tvl'] = data.get('tvl', 0)
182
- result['eigenlayer_change_24h'] = data.get('change_1d', 0)
183
- result['restaking_growth'] = 'HIGH' if data.get('change_1d', 0) > 5 else 'MODERATE' if data.get('change_1d', 0) > 0 else 'DECLINING'
 
 
 
 
 
 
 
 
184
  except:
185
  result['eigenlayer_tvl'] = 0
186
 
 
 
 
 
 
 
 
 
 
 
187
  result['signal'] = 'BULLISH' if result.get('lido_change_24h', 0) > 0 else 'NEUTRAL'
188
 
189
  CACHE[cache_key] = result
@@ -203,18 +277,20 @@ def fetch_dex_volumes() -> Dict[str, Any]:
203
  )
204
  if r.status_code == 200:
205
  data = r.json()
 
 
206
  result = {
207
- 'total_volume_24h': data.get('total24h', 0),
208
- 'volume_billions': round(data.get('total24h', 0) / 1e9, 2),
209
- 'change_24h': data.get('change_1d', 0),
210
- 'trend': 'UP' if data.get('change_1d', 0) > 0 else 'DOWN',
211
- 'signal': 'BULLISH' if data.get('change_1d', 0) > 10 else 'BEARISH' if data.get('change_1d', 0) < -10 else 'NEUTRAL'
212
  }
213
  CACHE[cache_key] = result
214
  CACHE_TIMES[cache_key] = time.time()
215
  return result
216
- except:
217
- pass
218
  return {'total_volume_24h': 0, 'signal': 'NEUTRAL'}
219
 
220
  # ================= СЖИГАНИЕ ETH =================
@@ -236,8 +312,8 @@ def fetch_ultrasound_money() -> Dict[str, Any]:
236
  CACHE[cache_key] = result
237
  CACHE_TIMES[cache_key] = time.time()
238
  return result
239
- except:
240
- pass
241
  return {'is_deflationary': False, 'signal': 'NEUTRAL'}
242
 
243
  # ================= РАЗРАБОТЧИКИ =================
@@ -255,43 +331,6 @@ def fetch_developer_activity() -> Dict[str, Any]:
255
  pass
256
  return {'activity': 'MODERATE'}
257
 
258
- # ================= АНАЛИЗ ИЗ MT5 =================
259
- def analyze_from_mt5(mt5_features: Dict[str, Any]) -> Optional[Dict[str, Any]]:
260
- try:
261
- score = 50.0
262
- signals = []
263
-
264
- vol = mt5_features.get('H1_volume', 0)
265
- if isinstance(vol, (int, float)) and vol > 1000:
266
- signals.append({"signal": "BULLISH", "reason": "Высокий объём на H1"})
267
- score += 5
268
-
269
- ema = mt5_features.get('H1_price_vs_ema_21', 0)
270
- if isinstance(ema, (int, float)):
271
- if ema > 1.0:
272
- score += 10
273
- elif ema < -1.0:
274
- score -= 10
275
-
276
- score = max(0, min(100, score))
277
-
278
- if score > 60:
279
- direction, confidence = "LONG", score / 100
280
- elif score < 40:
281
- direction, confidence = "SHORT", (100 - score) / 100
282
- else:
283
- direction, confidence = "WAIT", 0.0
284
-
285
- return {
286
- "direction": direction,
287
- "confidence": round(confidence, 4),
288
- "ecosystem_score": score,
289
- "signals": signals,
290
- "source": "MT5"
291
- }
292
- except:
293
- return None
294
-
295
  # ================= ГЛАВНЫЙ АНАЛИЗ =================
296
  def analyze_ecosystem() -> Dict[str, Any]:
297
  l2 = fetch_all_l2_tvl()
@@ -340,19 +379,23 @@ def analyze_ecosystem() -> Dict[str, Any]:
340
  score = max(0, min(100, score))
341
 
342
  if score > 60:
343
- direction, confidence = "LONG", score / 100
 
344
  elif score < 40:
345
- direction, confidence = "SHORT", (100 - score) / 100
 
346
  else:
347
- direction, confidence = "WAIT", 0.0
 
348
 
349
  return {
350
  "ecosystem_score": score,
351
- "direction": direction,
352
  "confidence": round(confidence, 4),
353
  "signals": signals,
354
  "metrics": {
355
- "l2": l2,
 
356
  "ethereum_tvl": eth_tvl,
357
  "staking": staking,
358
  "dex": dex,
@@ -364,68 +407,36 @@ def analyze_ecosystem() -> Dict[str, Any]:
364
  # ================= ГЛАВНЫЙ СИГНАЛ =================
365
  def get_ecosystem_signal() -> Dict[str, Any]:
366
  start = time.time()
367
-
368
- if SYMBOL in FEATURES_STORE:
369
- fs = FEATURES_STORE[SYMBOL]
370
- age = time.time() - fs.get("timestamp", 0)
371
- if age < MT5_MAX_AGE_SEC:
372
- mt5_features = fs.get("features", {})
373
- if mt5_features:
374
- mt5_result = analyze_from_mt5(mt5_features)
375
- if mt5_result:
376
- result = {
377
- "space": "space_20_l2_defi_pulse",
378
- "timestamp": int(time.time()),
379
- "symbol": SYMBOL,
380
- "signal": {
381
- "direction": mt5_result["direction"],
382
- "confidence": mt5_result["confidence"]
383
- },
384
- "ecosystem_analysis": {
385
- "score": mt5_result["ecosystem_score"],
386
- "signals": mt5_result["signals"]
387
- },
388
- "data_source": "MT5",
389
- "meta": {"latency_ms": int((time.time() - start) * 1000)}
390
- }
391
- send_signal_to_hub(SYMBOL, mt5_result["direction"], mt5_result["confidence"])
392
- print(f"🔷 L2+DeFi: {mt5_result['direction']} | Score={mt5_result['ecosystem_score']} (MT5)")
393
- return result
394
-
395
  analysis = analyze_ecosystem()
396
- latency = int((time.time() - start) * 1000)
397
-
398
- result = {
399
- "space": "space_20_l2_defi_pulse",
400
- "timestamp": int(time.time()),
 
 
 
 
 
 
 
 
401
  "symbol": SYMBOL,
402
- "signal": {
403
- "direction": analysis['direction'],
404
- "confidence": analysis['confidence']
405
- },
406
- "ecosystem_analysis": {
407
- "score": analysis['ecosystem_score'],
408
- "signals": analysis['signals'],
409
- "metrics": analysis['metrics']
410
- },
411
- "data_source": "DeFiLlama",
412
- "meta": {"latency_ms": latency}
413
  }
414
 
415
- send_signal_to_hub(SYMBOL, analysis['direction'], analysis['confidence'])
416
- print(f"🔷 L2+DeFi v1.2: {analysis['direction']} | Score={analysis['ecosystem_score']} | L2 TVL=${analysis['metrics']['l2'].get('total_l2_tvl_billions', 0)}B")
417
- return result
418
-
419
  # ================= АВТО-ОТПРАВКА =================
420
  async def auto_send_loop():
421
- print(f"🔄 Авто-отправка L2/DeFi запущена (интервал {AUTO_SEND_INTERVAL)")
422
- await asyncio.sleep(30)
 
423
  while True:
424
  try:
425
  get_ecosystem_signal()
426
- print("✅ L2/DeFi авто-отправка завершена")
427
  except Exception as e:
428
- print(f"Ошибка авто-отправки: {e}")
429
  await asyncio.sleep(AUTO_SEND_INTERVAL)
430
 
431
  # ================= KEEP-ALIVE =================
@@ -440,25 +451,27 @@ def keep_alive():
440
  threading.Thread(target=keep_alive, daemon=True).start()
441
 
442
  # ================= FASTAPI =================
443
- app = FastAPI(title="TOMIRIS SPACE 20 v1.2 — L2 & DEFI PULSE (Auto-Hub)")
444
 
445
  @app.on_event("startup")
446
  async def startup():
447
  asyncio.create_task(auto_send_loop())
448
- print("🚀 Space 20 v1.2 запущен с авто-отправкой в Hub")
449
 
450
  @app.get("/health")
451
- @app.head("/health")
452
  async def health():
453
  return {
454
- "space": "Space 20 v1.2 Auto-Hub",
455
  "status": "operational",
456
- "symbol": SYMBOL,
457
  "hub_url": HUB_URL,
458
- "auto_send_interval": AUTO_SEND_INTERVAL,
459
  "l2_chains": list(L2_CHAINS.keys())
460
  }
461
 
 
 
 
 
462
  @app.get("/consilium")
463
  async def consilium():
464
  return get_ecosystem_signal()
@@ -495,21 +508,14 @@ async def full_analysis():
495
  async def send_now():
496
  return get_ecosystem_signal()
497
 
498
- @app.post("/features")
499
- async def receive_features(data: Dict[str, Any]):
500
- symbol = data.get("symbol", SYMBOL)
501
- FEATURES_STORE[symbol] = {
502
- "features": data.get("features", {}),
503
- "price": data.get("price", 0.0),
504
- "timestamp": time.time()
505
- }
506
- print(f"📥 MT5 {symbol}: {len(data.get('features', {}))} признаков")
507
- return {"status": "ok"}
508
 
509
  if __name__ == "__main__":
510
  import uvicorn
511
  uvicorn.run(app, host="0.0.0.0", port=7860)
512
 
513
- print(f"🚀 SPACE 20 v1.2 — L2 & DEFI PULSE (АВТО-ОТПРАВКА В HUB) ЗАПУЩЕН!")
514
  print(f"🔷 Мониторинг: Arbitrum, Optimism, Base, Polygon ZkEVM | DEX | Staking | Ultrasound")
515
  print(f"✅ Готов к бою!")
 
22
  print(f"✅ {pip_name} установлен!")
23
 
24
  # ============================================
25
+ # 👑 TOMIRIS SPACE 20 v1.3 — ETHEREUM L2 & DEFI PULSE
26
  # ============================================
27
  from fastapi import FastAPI, Query
28
  from typing import Optional, Dict, Any, List
 
36
  import warnings
37
  import os
38
  import json
39
+ import logging
40
 
41
  warnings.filterwarnings('ignore')
42
 
43
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
44
+ logger = logging.getLogger("Space20_L2_DeFi")
45
+
46
  # ================= КОНФИГУРАЦИЯ =================
47
+ SPACE_ID = 20
48
+ SPACE_NAME = "L2 & DeFi Pulse"
49
+ SYMBOL = "ETH/USD"
50
+
51
+ # 🔥 ПРАВИЛЬНЫЙ URL ХАБА
52
+ HUB_URL = os.getenv("HUB_URL", "https://pro-3-tomiris-hub.hf.space")
53
+ HUB_SECRET = os.getenv("HUB_SECRET", "TomyrisUltraSecret2026!")
54
 
55
+ AUTO_SEND_INTERVAL = int(os.getenv("AUTO_SEND_INTERVAL", "600"))
56
+ STARTUP_SLEEP = int(os.getenv("STARTUP_SLEEP", "600"))
57
+
58
+ logger.info(f"🔗 Хаб: {HUB_URL}")
59
+ logger.info(f"⏱️ Интервал: {AUTO_SEND_INTERVAL}с | Стартовый сон: {STARTUP_SLEEP}с")
60
 
61
  L2_CHAINS: Dict[str, str] = {
62
  "Arbitrum": "Arbitrum",
 
73
  # ================= ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ =================
74
  CACHE: Dict[str, Dict[str, Any]] = {}
75
  CACHE_TIMES: Dict[str, float] = {}
76
+
77
+ # ================= ЗАГОЛОВКИ ДЛЯ ХАБА =================
78
+ def hub_headers():
79
+ return {
80
+ "X-Hub-Secret": HUB_SECRET,
81
+ "Content-Type": "application/json"
82
+ }
83
 
84
  # ================= ОТПРАВКА В HUB =================
85
+ def send_signal_to_hub(symbol: str, signal: str, confidence: float, features: Dict = None):
86
+ if features is None:
87
+ features = {}
88
+
89
+ payload = {
90
+ "space_id": SPACE_ID,
91
+ "space_name": SPACE_NAME,
92
+ "symbol": symbol,
93
+ "signal": signal,
94
+ "confidence": round(confidence, 4),
95
+ "features": features,
96
+ "metadata": {"version": "1.3"},
97
+ "timestamp": datetime.now().isoformat()
98
+ }
99
+
100
+ for attempt in range(3):
101
+ try:
102
+ headers = hub_headers()
103
+ r = requests.post(f"{HUB_URL}/signals", json=payload, timeout=15, headers=headers)
104
+ if r.status_code == 200:
105
+ logger.info(f"📤 {symbol}: {signal} conf={confidence:.3f}")
106
+ return True
107
+ elif r.status_code == 429:
108
+ wait = 3 * (attempt + 1)
109
+ logger.warning(f"⏳ 429 для {symbol}, жду {wait}с...")
110
+ time.sleep(wait)
111
+ else:
112
+ logger.warning(f"Попытка {attempt+1}: HTTP {r.status_code}")
113
+ time.sleep(2)
114
+ except Exception as e:
115
+ logger.warning(f"Попытка {attempt+1}: {e}")
116
+ time.sleep(2)
117
+
118
+ logger.error(f"❌ Не удалось отправить {symbol}")
119
+ return False
120
 
121
  # ================= ЗАГРУЗКА ДАННЫХ DeFiLlama =================
122
  def fetch_chain_tvl(chain: str) -> Optional[Dict[str, Any]]:
 
125
  return CACHE[cache_key]
126
 
127
  try:
128
+ r = requests.get(f"https://api.llama.fi/tvl/{chain}", timeout=10)
129
  if r.status_code == 200:
130
+ text = r.text.strip()
131
+ if not text:
132
+ return None
133
+ try:
134
+ data = r.json()
135
+ except:
136
+ return None
137
+
138
+ if isinstance(data, (int, float)):
139
+ tvl = float(data)
140
+ change_24h = 0
141
+ change_7d = 0
142
+ elif isinstance(data, dict):
143
+ tvl = data.get('tvl', 0)
144
+ change_24h = data.get('change_1d', 0)
145
+ change_7d = data.get('change_7d', 0)
146
+ else:
147
+ return None
148
+
149
  result = {
150
  'chain': chain,
151
+ 'tvl': tvl,
152
+ 'tvl_billions': round(tvl / 1e9, 2),
153
+ 'change_24h': change_24h,
154
+ 'change_7d': change_7d,
155
+ 'trend': 'UP' if change_24h > 0 else 'DOWN'
156
  }
157
  CACHE[cache_key] = result
158
  CACHE_TIMES[cache_key] = time.time()
159
  return result
160
  except Exception as e:
161
+ logger.warning(f"⚠️ TVL {chain}: {e}")
162
  return None
163
 
164
  def fetch_all_l2_tvl() -> Dict[str, Any]:
 
179
 
180
  avg_change = total_change / active_chains if active_chains > 0 else 0
181
 
182
+ result = {
183
  'chains': l2_data,
184
  'total_l2_tvl': round(total_tvl, 2),
185
  'total_l2_tvl_billions': round(total_tvl / 1e9, 2),
 
187
  'trend': 'GROWING' if avg_change > 2 else 'SHRINKING' if avg_change < -2 else 'STABLE',
188
  'signal': 'BULLISH' if avg_change > 2 else 'BEARISH' if avg_change < -2 else 'NEUTRAL'
189
  }
190
+ logger.info(f"✅ L2 TVL: ${result['total_l2_tvl_billions']}B ({result['trend']})")
191
+ return result
192
 
193
  def fetch_ethereum_tvl() -> Dict[str, Any]:
194
  cache_key = "tvl_ethereum"
195
  if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
196
  return CACHE[cache_key]
197
 
198
+ data = fetch_chain_tvl("ethereum")
199
+ if data:
200
+ CACHE[cache_key] = data
201
+ CACHE_TIMES[cache_key] = time.time()
202
+ return data
203
+ return {'tvl': 0, 'tvl_billions': 0, 'change_24h': 0, 'trend': 'STABLE'}
 
 
 
 
 
 
 
 
 
 
 
204
 
205
  # ================= СТЕЙКИНГ =================
206
  def fetch_staking_metrics() -> Dict[str, Any]:
 
210
 
211
  result: Dict[str, Any] = {}
212
 
213
+ # Lido TVL
214
  try:
215
+ r = requests.get("https://api.llama.fi/tvl/lido", timeout=10)
216
  if r.status_code == 200:
217
+ text = r.text.strip()
218
+ if text:
219
+ try:
220
+ data = r.json()
221
+ if isinstance(data, (int, float)):
222
+ result['lido_tvl'] = float(data)
223
+ result['lido_change_24h'] = 0
224
+ elif isinstance(data, dict):
225
+ result['lido_tvl'] = data.get('tvl', 0)
226
+ result['lido_change_24h'] = data.get('change_1d', 0)
227
+ except:
228
+ pass
229
  except:
230
  result['lido_tvl'] = 0
231
 
232
+ # EigenLayer TVL
233
  try:
234
+ r = requests.get("https://api.llama.fi/tvl/eigenlayer", timeout=10)
235
  if r.status_code == 200:
236
+ text = r.text.strip()
237
+ if text:
238
+ try:
239
+ data = r.json()
240
+ if isinstance(data, (int, float)):
241
+ result['eigenlayer_tvl'] = float(data)
242
+ result['eigenlayer_change_24h'] = 0
243
+ elif isinstance(data, dict):
244
+ result['eigenlayer_tvl'] = data.get('tvl', 0)
245
+ result['eigenlayer_change_24h'] = data.get('change_1d', 0)
246
+ except:
247
+ pass
248
  except:
249
  result['eigenlayer_tvl'] = 0
250
 
251
+ result['lido_tvl_billions'] = round(result.get('lido_tvl', 0) / 1e9, 2)
252
+
253
+ eigen_change = result.get('eigenlayer_change_24h', 0) or 0
254
+ if eigen_change > 5:
255
+ result['restaking_growth'] = 'HIGH'
256
+ elif eigen_change > 0:
257
+ result['restaking_growth'] = 'MODERATE'
258
+ else:
259
+ result['restaking_growth'] = 'DECLINING'
260
+
261
  result['signal'] = 'BULLISH' if result.get('lido_change_24h', 0) > 0 else 'NEUTRAL'
262
 
263
  CACHE[cache_key] = result
 
277
  )
278
  if r.status_code == 200:
279
  data = r.json()
280
+ total24h = data.get('total24h', 0)
281
+ change24h = data.get('change_1d', 0)
282
  result = {
283
+ 'total_volume_24h': total24h,
284
+ 'volume_billions': round(total24h / 1e9, 2),
285
+ 'change_24h': change24h,
286
+ 'trend': 'UP' if change24h > 0 else 'DOWN',
287
+ 'signal': 'BULLISH' if change24h > 10 else 'BEARISH' if change24h < -10 else 'NEUTRAL'
288
  }
289
  CACHE[cache_key] = result
290
  CACHE_TIMES[cache_key] = time.time()
291
  return result
292
+ except Exception as e:
293
+ logger.warning(f"DEX error: {e}")
294
  return {'total_volume_24h': 0, 'signal': 'NEUTRAL'}
295
 
296
  # ================= СЖИГАНИЕ ETH =================
 
312
  CACHE[cache_key] = result
313
  CACHE_TIMES[cache_key] = time.time()
314
  return result
315
+ except Exception as e:
316
+ logger.warning(f"Ultrasound error: {e}")
317
  return {'is_deflationary': False, 'signal': 'NEUTRAL'}
318
 
319
  # ================= РАЗРАБОТЧИКИ =================
 
331
  pass
332
  return {'activity': 'MODERATE'}
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  # ================= ГЛАВНЫЙ АНАЛИЗ =================
335
  def analyze_ecosystem() -> Dict[str, Any]:
336
  l2 = fetch_all_l2_tvl()
 
379
  score = max(0, min(100, score))
380
 
381
  if score > 60:
382
+ signal = "BUY"
383
+ confidence = score / 100
384
  elif score < 40:
385
+ signal = "SELL"
386
+ confidence = (100 - score) / 100
387
  else:
388
+ signal = "WAIT"
389
+ confidence = 0.0
390
 
391
  return {
392
  "ecosystem_score": score,
393
+ "signal": signal,
394
  "confidence": round(confidence, 4),
395
  "signals": signals,
396
  "metrics": {
397
+ "l2": {k: v for k, v in l2.items() if k != 'chains'},
398
+ "l2_chains": l2.get('chains', {}),
399
  "ethereum_tvl": eth_tvl,
400
  "staking": staking,
401
  "dex": dex,
 
407
  # ================= ГЛАВНЫЙ СИГНАЛ =================
408
  def get_ecosystem_signal() -> Dict[str, Any]:
409
  start = time.time()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  analysis = analyze_ecosystem()
411
+
412
+ features = {
413
+ "ecosystem_score": analysis['ecosystem_score'],
414
+ "l2_tvl": analysis['metrics'].get('l2', {}).get('total_l2_tvl_billions', 0),
415
+ "eth_tvl_change": analysis['metrics'].get('ethereum_tvl', {}).get('change_24h', 0)
416
+ }
417
+ send_signal_to_hub(SYMBOL, analysis['signal'], analysis['confidence'], features)
418
+
419
+ elapsed = int((time.time() - start) * 1000)
420
+ logger.info(f"🔷 L2+DeFi: {analysis['signal']} | Score={analysis['ecosystem_score']} | L2 TVL=${analysis['metrics'].get('l2', {}).get('total_l2_tvl_billions', 0)}B | {elapsed}ms")
421
+
422
+ return {
423
+ "space_id": SPACE_ID,
424
  "symbol": SYMBOL,
425
+ "signal": analysis['signal'],
426
+ "confidence": analysis['confidence'],
427
+ "ecosystem_score": analysis['ecosystem_score']
 
 
 
 
 
 
 
 
428
  }
429
 
 
 
 
 
430
  # ================= АВТО-ОТПРАВКА =================
431
  async def auto_send_loop():
432
+ logger.info(f" Стартовый сон {STARTUP_SLEEP...")
433
+ await asyncio.sleep(STARTUP_SLEEP)
434
+ logger.info(f"🔄 Авто-отправка L2/DeFi (интервал {AUTO_SEND_INTERVAL}с)")
435
  while True:
436
  try:
437
  get_ecosystem_signal()
 
438
  except Exception as e:
439
+ logger.error(f"Ошибка авто-отправки: {e}")
440
  await asyncio.sleep(AUTO_SEND_INTERVAL)
441
 
442
  # ================= KEEP-ALIVE =================
 
451
  threading.Thread(target=keep_alive, daemon=True).start()
452
 
453
  # ================= FASTAPI =================
454
+ app = FastAPI(title="TOMIRIS SPACE 20 v1.3 — L2 & DEFI PULSE")
455
 
456
  @app.on_event("startup")
457
  async def startup():
458
  asyncio.create_task(auto_send_loop())
459
+ logger.info(f"🚀 Space 20 v1.3 ЗАПУЩЕН | Хаб: {HUB_URL}")
460
 
461
  @app.get("/health")
 
462
  async def health():
463
  return {
464
+ "space_id": SPACE_ID,
465
  "status": "operational",
466
+ "version": "1.3",
467
  "hub_url": HUB_URL,
 
468
  "l2_chains": list(L2_CHAINS.keys())
469
  }
470
 
471
+ @app.head("/health")
472
+ async def health_head():
473
+ return {}
474
+
475
  @app.get("/consilium")
476
  async def consilium():
477
  return get_ecosystem_signal()
 
508
  async def send_now():
509
  return get_ecosystem_signal()
510
 
511
+ @app.get("/")
512
+ async def root():
513
+ return {"name": "L2 & DeFi Pulse v1.3", "space_id": SPACE_ID, "hub": HUB_URL}
 
 
 
 
 
 
 
514
 
515
  if __name__ == "__main__":
516
  import uvicorn
517
  uvicorn.run(app, host="0.0.0.0", port=7860)
518
 
519
+ print(f"🚀 SPACE 20 v1.3 — L2 & DEFI PULSE ЗАПУЩЕН!")
520
  print(f"🔷 Мониторинг: Arbitrum, Optimism, Base, Polygon ZkEVM | DEX | Staking | Ultrasound")
521
  print(f"✅ Готов к бою!")