tomirisai80 commited on
Commit
a34e07e
·
verified ·
1 Parent(s): af18f19

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +491 -0
app.py ADDED
@@ -0,0 +1,491 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ============================================
2
+ # АВТО-УСТАНОВКА ПАКЕТОВ
3
+ # ============================================
4
+ import subprocess
5
+ import sys
6
+ import importlib
7
+
8
+ REQUIRED_PACKAGES = {
9
+ 'numpy': 'numpy',
10
+ 'pandas': 'pandas',
11
+ 'requests': 'requests'
12
+ }
13
+
14
+ for module_name, pip_name in REQUIRED_PACKAGES.items():
15
+ try:
16
+ importlib.import_module(module_name)
17
+ except ImportError:
18
+ print(f"📦 Устанавливаю {pip_name}...")
19
+ subprocess.check_call([sys.executable, "-m", "pip", "install", pip_name])
20
+ print(f"✅ {pip_name} установлен!")
21
+
22
+ # ============================================
23
+ # 👑 TOMIRIS SPACE 20 v1.0 — ETHEREUM L2 & DEFI PULSE
24
+ # ============================================
25
+ # Мониторит L2-сети (Arbitrum, Optimism, Base, zkSync) и DeFi-метрики.
26
+ # TVL, DEX-объёмы, активность разработчиков, стейкинг, сжигание ETH.
27
+ # Сигнализирует о трендах в экосистеме Ethereum.
28
+ # ============================================
29
+
30
+ from fastapi import FastAPI, Query
31
+ from typing import Optional, Dict, Any, List
32
+ import time
33
+ import requests
34
+ import threading
35
+ import numpy as np
36
+ from datetime import datetime
37
+ from collections import deque
38
+ import warnings
39
+ warnings.filterwarnings('ignore')
40
+
41
+ # ================= КОНФИГУРАЦИЯ =================
42
+ SYMBOL: str = "ETH/USD"
43
+
44
+ L2_CHAINS: Dict[str, str] = {
45
+ "Arbitrum": "Arbitrum",
46
+ "Optimism": "Optimism",
47
+ "Base": "Base",
48
+ "Polygon ZkEVM": "Polygon ZkEVM"
49
+ }
50
+
51
+ DEFI_PROTOCOLS: List[str] = [
52
+ "Lido", "MakerDAO", "Aave", "Uniswap", "Curve",
53
+ "EigenLayer", "Rocket Pool"
54
+ ]
55
+
56
+ SPACE_18_ARBITER: str = "https://tomiris-ai-name6-6.hf.space"
57
+
58
+ # ================= ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ =================
59
+ CACHE: Dict[str, Dict[str, Any]] = {}
60
+ CACHE_TIMES: Dict[str, float] = {}
61
+ FEATURES_STORE: Dict[str, Dict[str, Any]] = {}
62
+ MT5_MAX_AGE_SEC: int = 300
63
+
64
+ def send_to_arbiter(signal_data: Dict[str, Any]) -> None:
65
+ try:
66
+ requests.post(
67
+ f"{SPACE_18_ARBITER}/log_signal",
68
+ json={'space': 'space_20_l2_defi', 'symbol': SYMBOL, 'signal': signal_data.get('signal', {})},
69
+ timeout=5
70
+ )
71
+ except:
72
+ pass
73
+
74
+ # ================= ЗАГРУЗКА ДАННЫХ DeFiLlama =================
75
+ def fetch_chain_tvl(chain: str) -> Optional[Dict[str, Any]]:
76
+ cache_key = f"tvl_{chain}"
77
+ if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
78
+ return CACHE[cache_key]
79
+
80
+ try:
81
+ r = requests.get(f"https://api.llama.fi/v2/tvl/{chain}", timeout=10)
82
+ if r.status_code == 200:
83
+ data = r.json()
84
+ result = {
85
+ 'chain': chain,
86
+ 'tvl': data.get('tvl', 0),
87
+ 'tvl_billions': round(data.get('tvl', 0) / 1e9, 2),
88
+ 'change_24h': data.get('change_1d', 0),
89
+ 'change_7d': data.get('change_7d', 0),
90
+ 'trend': 'UP' if data.get('change_1d', 0) > 0 else 'DOWN'
91
+ }
92
+ CACHE[cache_key] = result
93
+ CACHE_TIMES[cache_key] = time.time()
94
+ return result
95
+ except Exception as e:
96
+ print(f"⚠️ TVL {chain}: {e}")
97
+ return None
98
+
99
+ def fetch_all_l2_tvl() -> Dict[str, Any]:
100
+ l2_data: Dict[str, Any] = {}
101
+ total_tvl = 0.0
102
+ total_change = 0.0
103
+ active_chains = 0
104
+
105
+ for chain, name in L2_CHAINS.items():
106
+ data = fetch_chain_tvl(chain)
107
+ if data:
108
+ l2_data[chain] = data
109
+ total_tvl += data['tvl']
110
+ total_change += data['change_24h']
111
+ active_chains += 1
112
+ else:
113
+ l2_data[chain] = {"error": "no_data"}
114
+
115
+ avg_change = total_change / active_chains if active_chains > 0 else 0
116
+
117
+ return {
118
+ 'chains': l2_data,
119
+ 'total_l2_tvl': round(total_tvl, 2),
120
+ 'total_l2_tvl_billions': round(total_tvl / 1e9, 2),
121
+ 'avg_change_24h': round(avg_change, 2),
122
+ 'trend': 'GROWING' if avg_change > 2 else 'SHRINKING' if avg_change < -2 else 'STABLE',
123
+ 'signal': 'BULLISH' if avg_change > 2 else 'BEARISH' if avg_change < -2 else 'NEUTRAL'
124
+ }
125
+
126
+ def fetch_ethereum_tvl() -> Dict[str, Any]:
127
+ cache_key = "tvl_ethereum"
128
+ if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
129
+ return CACHE[cache_key]
130
+
131
+ try:
132
+ r = requests.get("https://api.llama.fi/v2/tvl/ethereum", timeout=10)
133
+ if r.status_code == 200:
134
+ data = r.json()
135
+ result = {
136
+ 'tvl': data.get('tvl', 0),
137
+ 'tvl_billions': round(data.get('tvl', 0) / 1e9, 2),
138
+ 'change_24h': data.get('change_1d', 0),
139
+ 'change_7d': data.get('change_7d', 0),
140
+ 'trend': 'UP' if data.get('change_1d', 0) > 0 else 'DOWN'
141
+ }
142
+ CACHE[cache_key] = result
143
+ CACHE_TIMES[cache_key] = time.time()
144
+ return result
145
+ except:
146
+ pass
147
+ return {'tvl': 0, 'trend': 'STABLE'}
148
+
149
+ # ================= СТЕЙКИНГ =================
150
+ def fetch_staking_metrics() -> Dict[str, Any]:
151
+ """Доля ETH в стейкинге, APR, ликвидный стейкинг."""
152
+ cache_key = "staking"
153
+ if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
154
+ return CACHE[cache_key]
155
+
156
+ result: Dict[str, Any] = {}
157
+
158
+ # Lido TVL как прокси ликвидного стейкинга
159
+ try:
160
+ r = requests.get("https://api.llama.fi/v2/tvl/lido", timeout=10)
161
+ if r.status_code == 200:
162
+ data = r.json()
163
+ result['lido_tvl'] = data.get('tvl', 0)
164
+ result['lido_tvl_billions'] = round(data.get('tvl', 0) / 1e9, 2)
165
+ result['lido_change_24h'] = data.get('change_1d', 0)
166
+ except:
167
+ result['lido_tvl'] = 0
168
+
169
+ # EigenLayer TVL
170
+ try:
171
+ r = requests.get("https://api.llama.fi/v2/tvl/eigenlayer", timeout=10)
172
+ if r.status_code == 200:
173
+ data = r.json()
174
+ result['eigenlayer_tvl'] = data.get('tvl', 0)
175
+ result['eigenlayer_change_24h'] = data.get('change_1d', 0)
176
+ result['restaking_growth'] = 'HIGH' if data.get('change_1d', 0) > 5 else 'MODERATE' if data.get('change_1d', 0) > 0 else 'DECLINING'
177
+ except:
178
+ result['eigenlayer_tvl'] = 0
179
+
180
+ result['signal'] = 'BULLISH' if result.get('lido_change_24h', 0) > 0 else 'NEUTRAL'
181
+
182
+ CACHE[cache_key] = result
183
+ CACHE_TIMES[cache_key] = time.time()
184
+ return result
185
+
186
+ # ================= DEX ОБЪЁМЫ =================
187
+ def fetch_dex_volumes() -> Dict[str, Any]:
188
+ cache_key = "dex_eth"
189
+ if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
190
+ return CACHE[cache_key]
191
+
192
+ try:
193
+ r = requests.get(
194
+ "https://api.llama.fi/overview/dexs/ethereum?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true",
195
+ timeout=10
196
+ )
197
+ if r.status_code == 200:
198
+ data = r.json()
199
+ result = {
200
+ 'total_volume_24h': data.get('total24h', 0),
201
+ 'volume_billions': round(data.get('total24h', 0) / 1e9, 2),
202
+ 'change_24h': data.get('change_1d', 0),
203
+ 'trend': 'UP' if data.get('change_1d', 0) > 0 else 'DOWN',
204
+ 'signal': 'BULLISH' if data.get('change_1d', 0) > 10 else 'BEARISH' if data.get('change_1d', 0) < -10 else 'NEUTRAL'
205
+ }
206
+ CACHE[cache_key] = result
207
+ CACHE_TIMES[cache_key] = time.time()
208
+ return result
209
+ except:
210
+ pass
211
+ return {'total_volume_24h': 0, 'signal': 'NEUTRAL'}
212
+
213
+ # ================= СЖИГАНИЕ ETH =================
214
+ def fetch_ultrasound_money() -> Dict[str, Any]:
215
+ cache_key = "ultrasound"
216
+ if cache_key in CACHE and time.time() - CACHE_TIMES.get(cache_key, 0) < 300:
217
+ return CACHE[cache_key]
218
+
219
+ try:
220
+ r = requests.get("https://ultrasound.money/api/overview", timeout=10)
221
+ if r.status_code == 200:
222
+ data = r.json()
223
+ result = {
224
+ 'burn_24h': data.get("burn24h", 0),
225
+ 'supply_growth_24h': data.get("supplyGrowth24h", 0),
226
+ 'is_deflationary': data.get("supplyGrowth24h", 0) < 0,
227
+ 'signal': 'BULLISH' if data.get("supplyGrowth24h", 0) < 0 else 'BEARISH'
228
+ }
229
+ CACHE[cache_key] = result
230
+ CACHE_TIMES[cache_key] = time.time()
231
+ return result
232
+ except:
233
+ pass
234
+ return {'is_deflationary': False, 'signal': 'NEUTRAL'}
235
+
236
+ # ================= РАЗРАБОТЧИКИ =================
237
+ def fetch_developer_activity() -> Dict[str, Any]:
238
+ """Активность разработчиков через Electric Capital (заглушка)."""
239
+ try:
240
+ r = requests.get("https://api.coingecko.com/api/v3/coins/ethereum?developer_data=true", timeout=10)
241
+ if r.status_code == 200:
242
+ dev = r.json().get('developer_data', {})
243
+ return {
244
+ 'stars': dev.get('stars', 0),
245
+ 'commits_4w': dev.get('commit_count_4_weeks', 0),
246
+ 'activity': 'HIGH' if dev.get('commit_count_4_weeks', 0) > 100 else 'MODERATE'
247
+ }
248
+ except:
249
+ pass
250
+ return {'activity': 'MODERATE'}
251
+
252
+ # ================= АНАЛИЗ ИЗ MT5 =================
253
+ def analyze_from_mt5(mt5_features: Dict[str, Any]) -> Optional[Dict[str, Any]]:
254
+ try:
255
+ score = 50.0
256
+ signals = []
257
+
258
+ vol = mt5_features.get('H1_volume', 0)
259
+ if isinstance(vol, (int, float)) and vol > 1000:
260
+ signals.append({"signal": "BULLISH", "reason": "Высокий объём на H1"})
261
+ score += 5
262
+
263
+ ema = mt5_features.get('H1_price_vs_ema_21', 0)
264
+ if isinstance(ema, (int, float)):
265
+ if ema > 1.0:
266
+ score += 10
267
+ elif ema < -1.0:
268
+ score -= 10
269
+
270
+ score = max(0, min(100, score))
271
+
272
+ if score > 60:
273
+ direction, confidence = "LONG", score / 100
274
+ elif score < 40:
275
+ direction, confidence = "SHORT", (100 - score) / 100
276
+ else:
277
+ direction, confidence = "WAIT", 0.0
278
+
279
+ return {
280
+ "direction": direction,
281
+ "confidence": round(confidence, 4),
282
+ "ecosystem_score": score,
283
+ "signals": signals,
284
+ "source": "MT5"
285
+ }
286
+ except:
287
+ return None
288
+
289
+ # ================= ГЛАВНЫЙ АНАЛИЗ =================
290
+ def analyze_ecosystem() -> Dict[str, Any]:
291
+ l2 = fetch_all_l2_tvl()
292
+ eth_tvl = fetch_ethereum_tvl()
293
+ staking = fetch_staking_metrics()
294
+ dex = fetch_dex_volumes()
295
+ ultrasound = fetch_ultrasound_money()
296
+ dev = fetch_developer_activity()
297
+
298
+ signals = []
299
+ score = 50.0
300
+
301
+ # L2 тренд
302
+ if l2.get('trend') == 'GROWING':
303
+ signals.append({"signal": "BULLISH", "reason": f"L2 растёт (+{l2.get('avg_change_24h', 0):.1f}%)"})
304
+ score += 15
305
+ elif l2.get('trend') == 'SHRINKING':
306
+ signals.append({"signal": "BEARISH", "reason": "L2 падает"})
307
+ score -= 15
308
+
309
+ # TVL Ethereum
310
+ if eth_tvl.get('trend') == 'UP' and eth_tvl.get('change_24h', 0) > 2:
311
+ signals.append({"signal": "BULLISH", "reason": "TVL ETH растёт"})
312
+ score += 10
313
+ elif eth_tvl.get('trend') == 'DOWN' and eth_tvl.get('change_24h', 0) < -2:
314
+ signals.append({"signal": "BEARISH", "reason": "TVL ETH падает"})
315
+ score -= 10
316
+
317
+ # Стейкинг
318
+ if staking.get('restaking_growth') == 'HIGH':
319
+ signals.append({"signal": "BULLISH", "reason": "Рестейкинг растёт"})
320
+ score += 5
321
+
322
+ # DEX
323
+ if dex.get('signal') == 'BULLISH':
324
+ signals.append({"signal": "BULLISH", "reason": "DEX объёмы растут"})
325
+ score += 8
326
+ elif dex.get('signal') == 'BEARISH':
327
+ signals.append({"signal": "BEARISH", "reason": "DEX объёмы падают"})
328
+ score -= 8
329
+
330
+ # Ultrasound
331
+ if ultrasound.get('is_deflationary'):
332
+ signals.append({"signal": "BULLISH", "reason": "ETH дефляционный"})
333
+ score += 8
334
+
335
+ # Разработчики
336
+ if dev.get('activity') == 'HIGH':
337
+ signals.append({"signal": "BULLISH", "reason": "Высокая активность разработчиков"})
338
+ score += 3
339
+
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,
359
+ "ultrasound": ultrasound,
360
+ "developer_activity": dev
361
+ }
362
+ }
363
+
364
+ # ================= ГЛАВНЫЙ СИГНАЛ =================
365
+ def get_ecosystem_signal() -> Dict[str, Any]:
366
+ start = time.time()
367
+
368
+ # Проверка MT5
369
+ if SYMBOL in FEATURES_STORE:
370
+ fs = FEATURES_STORE[SYMBOL]
371
+ age = time.time() - fs.get("timestamp", 0)
372
+ if age < MT5_MAX_AGE_SEC:
373
+ mt5_features = fs.get("features", {})
374
+ if mt5_features:
375
+ mt5_result = analyze_from_mt5(mt5_features)
376
+ if mt5_result:
377
+ result = {
378
+ "space": "space_20_l2_defi_pulse",
379
+ "timestamp": int(time.time()),
380
+ "symbol": SYMBOL,
381
+ "signal": {
382
+ "direction": mt5_result["direction"],
383
+ "confidence": mt5_result["confidence"]
384
+ },
385
+ "ecosystem_analysis": {
386
+ "score": mt5_result["ecosystem_score"],
387
+ "signals": mt5_result["signals"]
388
+ },
389
+ "data_source": "MT5",
390
+ "meta": {"latency_ms": int((time.time() - start) * 1000)}
391
+ }
392
+ send_to_arbiter(result)
393
+ print(f"🔷 L2+DeFi: {mt5_result['direction']} | Score={mt5_result['ecosystem_score']} (MT5)")
394
+ return result
395
+
396
+ # Fallback
397
+ analysis = analyze_ecosystem()
398
+ latency = int((time.time() - start) * 1000)
399
+
400
+ result = {
401
+ "space": "space_20_l2_defi_pulse",
402
+ "timestamp": int(time.time()),
403
+ "symbol": SYMBOL,
404
+ "signal": {
405
+ "direction": analysis['direction'],
406
+ "confidence": analysis['confidence']
407
+ },
408
+ "ecosystem_analysis": {
409
+ "score": analysis['ecosystem_score'],
410
+ "signals": analysis['signals'],
411
+ "metrics": analysis['metrics']
412
+ },
413
+ "data_source": "DeFiLlama",
414
+ "meta": {"latency_ms": latency}
415
+ }
416
+
417
+ send_to_arbiter(result)
418
+ print(f"🔷 L2+DeFi v1: {analysis['direction']} | Score={analysis['ecosystem_score']} | L2 TVL=${analysis['metrics']['l2'].get('total_l2_tvl_billions', 0)}B")
419
+ return result
420
+
421
+ # ================= KEEP-ALIVE =================
422
+ def keep_alive():
423
+ while True:
424
+ time.sleep(840)
425
+ try:
426
+ requests.get("http://localhost:7860/health", timeout=5)
427
+ except:
428
+ pass
429
+
430
+ threading.Thread(target=keep_alive, daemon=True).start()
431
+
432
+ # ================= FASTAPI =================
433
+ app = FastAPI(title="TOMIRIS SPACE 20 v1.0 — ETHEREUM L2 & DEFI PULSE")
434
+
435
+ @app.get("/health")
436
+ @app.head("/health")
437
+ async def health():
438
+ return {
439
+ "space": "Space 20 - Ethereum L2 & DeFi Pulse v1.0",
440
+ "status": "operational",
441
+ "symbol": SYMBOL,
442
+ "l2_chains": list(L2_CHAINS.keys()),
443
+ "features": ["L2 TVL", "Ethereum TVL", "Staking", "DEX Volumes", "Ultrasound Money", "Developer Activity"]
444
+ }
445
+
446
+ @app.get("/consilium")
447
+ async def consilium():
448
+ return get_ecosystem_signal()
449
+
450
+ @app.get("/l2")
451
+ async def l2_status():
452
+ return fetch_all_l2_tvl()
453
+
454
+ @app.get("/tvl")
455
+ async def tvl():
456
+ return fetch_ethereum_tvl()
457
+
458
+ @app.get("/staking")
459
+ async def staking():
460
+ return fetch_staking_metrics()
461
+
462
+ @app.get("/dex")
463
+ async def dex():
464
+ return fetch_dex_volumes()
465
+
466
+ @app.get("/ultrasound")
467
+ async def ultrasound():
468
+ return fetch_ultrasound_money()
469
+
470
+ @app.get("/developers")
471
+ async def developers():
472
+ return fetch_developer_activity()
473
+
474
+ @app.get("/full")
475
+ async def full_analysis():
476
+ return analyze_ecosystem()
477
+
478
+ @app.post("/features")
479
+ async def receive_features(data: Dict[str, Any]):
480
+ symbol = data.get("symbol", SYMBOL)
481
+ FEATURES_STORE[symbol] = {
482
+ "features": data.get("features", {}),
483
+ "price": data.get("price", 0.0),
484
+ "timestamp": time.time()
485
+ }
486
+ print(f"📥 MT5 {symbol}: {len(data.get('features', {}))} признаков")
487
+ return {"status": "ok"}
488
+
489
+ print(f"🚀 SPACE 20 v1.0 — ETHEREUM L2 & DEFI PULSE ЗАПУЩЕН!")
490
+ print(f"🔷 Мониторинг: Arbitrum, Optimism, Base, Polygon ZkEVM | DEX | Staking | Ultrasound")
491
+ print(f"✅ Готов к бою!")