tomirisai80 commited on
Commit
d794548
·
verified ·
1 Parent(s): db22eaa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -129
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # ============================================
2
- # 👑 TOMIRIS SPACE 19 v10.2 — SOL/USD MASTER (FULL FIX)
3
  # ============================================
4
  import os, time, threading, warnings, json, asyncio
5
  from typing import Dict, Any, Optional, List, Tuple
@@ -28,7 +28,6 @@ SPACE_NAME = "SOL Master"
28
 
29
  HUB_URL = os.getenv("HUB_URL", "https://pro-3-tomiris-hub.hf.space")
30
  HUB_SECRET = os.getenv("HUB_SECRET", "TomyrisUltraSecret2026!")
31
- TWELVE_DATA_KEY = os.getenv("TWELVE_DATA_KEY", "")
32
 
33
  STARTUP_SLEEP = int(os.getenv("STARTUP_SLEEP", "600"))
34
  AUTO_REPORT_INTERVAL = 600
@@ -40,12 +39,9 @@ SOL_THRESHOLD = 0.52
40
  logger.info(f"🔗 Хаб: {HUB_URL}")
41
 
42
  def hub_headers():
43
- return {
44
- "X-Hub-Secret": HUB_SECRET,
45
- "Content-Type": "application/json"
46
- }
47
 
48
- CACHE_TTL = 300
49
  DATA_CACHE: Dict[str, Dict[str, Any]] = {}
50
  PREDICTION_HISTORY = deque(maxlen=500)
51
  LAST_CONFIDENCE = 0.5
@@ -80,7 +76,7 @@ if HAS_JOBLIB:
80
 
81
  # ================= HTTP СЕССИЯ =================
82
  session = requests.Session()
83
- session.headers.update({"User-Agent": "Tomiris-Space19-v10.2"})
84
 
85
  # ================= УТИЛИТЫ =================
86
  def safe_float(value, default=0.0):
@@ -88,8 +84,7 @@ def safe_float(value, default=0.0):
88
  if isinstance(value, (pd.Series, pd.DataFrame)):
89
  return float(value.iloc[-1]) if len(value) > 0 else default
90
  return float(value) if not pd.isna(float(value)) else default
91
- except:
92
- return default
93
 
94
  def safe_rsi(close, period=14):
95
  try:
@@ -100,24 +95,18 @@ def safe_rsi(close, period=14):
100
  if pd.notna(g_val) and pd.notna(l_val) and l_val > 0:
101
  return float(100 - (100 / (1 + g_val/l_val)))
102
  return 50.0
103
- except:
104
- return 50.0
105
 
106
  def safe_ema(close, span):
107
- try:
108
- return float(close.ewm(span=span, adjust=False).mean().iloc[-1])
109
- except:
110
- return float(close.iloc[-1])
111
 
112
  def hurst_exponent(series, lags=20):
113
- if len(series) < lags * 2:
114
- return 0.5
115
  lags_range = range(2, min(lags, len(series)//2))
116
  tau = [np.std(np.subtract(series.values[lag:], series.values[:-lag])) for lag in lags_range]
117
- try:
118
- return float(np.polyfit(np.log(list(lags_range)), np.log(tau), 1)[0] * 2.0)
119
- except:
120
- return 0.5
121
 
122
  def smooth_confidence(current):
123
  global LAST_CONFIDENCE
@@ -130,13 +119,11 @@ def detect_market_regime(features):
130
  adx = features.get("adx", 20.0)
131
  volatility = features.get("volatility_1h", 0.0)
132
  hurst = features.get("hurst_exponent", 0.5)
133
- if adx > 30 and hurst > 0.55:
134
- return "TREND"
135
- if volatility > 0.04:
136
- return "VOLATILE"
137
  return "RANGE"
138
 
139
- # ================= ЗАГРУЗКА ДАННЫХ =================
140
  def fetch_ohlc_hub(symbol, tf, limit=200):
141
  cache_key = f"hub_{symbol}_{tf}"
142
  if cache_key in DATA_CACHE and time.time() - DATA_CACHE[cache_key].get("timestamp", 0) < CACHE_TTL:
@@ -146,7 +133,7 @@ def fetch_ohlc_hub(symbol, tf, limit=200):
146
  r = session.get(
147
  f"{HUB_URL}/candles",
148
  params={"symbol": symbol, "interval": tf, "limit": limit},
149
- timeout=20,
150
  headers=hub_headers()
151
  )
152
  if r.status_code == 200:
@@ -161,48 +148,23 @@ def fetch_ohlc_hub(symbol, tf, limit=200):
161
  if len(df) >= 30:
162
  DATA_CACHE[cache_key] = {"df": df, "timestamp": time.time()}
163
  return df
 
 
164
  except Exception as e:
165
  logger.warning(f"Hub {symbol} {tf}: {e}")
166
  return None
167
 
168
- def fetch_twelvedata_sol(tf="1h"):
169
- if not TWELVE_DATA_KEY:
170
- return None
171
- cache_key = f"td_sol_{tf}"
172
- if cache_key in DATA_CACHE and time.time() - DATA_CACHE[cache_key].get("timestamp", 0) < CACHE_TTL:
173
- return DATA_CACHE[cache_key]["df"]
174
-
175
- try:
176
- url = f"https://api.twelvedata.com/time_series?symbol=SOL/USD&interval={tf}&outputsize=200&apikey={TWELVE_DATA_KEY}"
177
- r = session.get(url, timeout=15)
178
- if r.status_code == 200 and "values" in r.json():
179
- df = pd.DataFrame(r.json()["values"]).iloc[::-1].reset_index(drop=True)
180
- for col in ["close","high","low","open"]:
181
- df[col] = pd.to_numeric(df[col], errors="coerce")
182
- df["volume"] = pd.to_numeric(df.get("volume", 0), errors="coerce").fillna(0)
183
- if len(df) >= 30:
184
- DATA_CACHE[cache_key] = {"df": df, "timestamp": time.time()}
185
- return df
186
- except:
187
- pass
188
- return None
189
-
190
  def fetch_ohlc(symbol, tf="1h"):
191
- df = fetch_ohlc_hub(symbol, tf)
192
- if df is None:
193
- logger.info(f" 🔄 Хаб недоступен для {symbol} {tf}, пробую Twelve Data...")
194
- df = fetch_twelvedata_sol(tf)
195
- return df
196
 
197
  def fetch_solana_onchain():
198
- """🔥 ФИКС: Правильные эндпоинты DefiLlama"""
199
  cache_key = "solana_onchain"
200
- if cache_key in DATA_CACHE and time.time() - DATA_CACHE[cache_key].get("timestamp", 0) < 300:
201
  return DATA_CACHE[cache_key]["data"]
202
 
203
  result = {}
204
-
205
- # TVL — правильный эндпоинт
206
  try:
207
  r = session.get("https://api.llama.fi/tvl/solana", timeout=10)
208
  if r.status_code == 200:
@@ -216,35 +178,23 @@ def fetch_solana_onchain():
216
  elif isinstance(data, dict):
217
  result['tvl'] = data.get('tvl', 0)
218
  result['tvl_change_24h'] = data.get('change_1d', 0)
219
- except:
220
- pass
221
- if 'tvl' not in result:
222
- result['tvl'] = 0
223
- result['tvl_change_24h'] = 0
224
- except Exception as e:
225
- logger.warning(f"Solana TVL error: {e}")
226
- result['tvl'] = 0
227
- result['tvl_change_24h'] = 0
228
 
 
 
229
  result['tvl_trend'] = 'UP' if result.get('tvl_change_24h', 0) > 0 else 'DOWN'
230
 
231
- # DEX volumes — правильный эндпоинт
232
  try:
233
- r = session.get(
234
- "https://api.llama.fi/overview/dexs/solana?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true",
235
- timeout=10
236
- )
237
  if r.status_code == 200:
238
  data = r.json()
239
  result['dex_volume_24h'] = data.get('total24h', 0)
240
  result['dex_change_24h'] = data.get('change_1d', 0)
241
- else:
242
- result['dex_volume_24h'] = 0
243
- result['dex_change_24h'] = 0
244
- except Exception as e:
245
- logger.warning(f"Solana DEX error: {e}")
246
- result['dex_volume_24h'] = 0
247
- result['dex_change_24h'] = 0
248
 
249
  DATA_CACHE[cache_key] = {"data": result, "timestamp": time.time()}
250
  return result
@@ -260,14 +210,12 @@ def fetch_binance_sol():
260
  result['funding_rate'] = fr
261
  result['funding_signal'] = 'BEARISH' if fr > 0.001 else 'BULLISH' if fr < -0.001 else 'NEUTRAL'
262
  break
263
- except:
264
- pass
265
  try:
266
  r = session.get("https://fapi.binance.com/fapi/v1/openInterest?symbol=SOLUSDT", timeout=10)
267
  if r.status_code == 200:
268
  result['open_interest'] = float(r.json().get('openInterest', 0))
269
- except:
270
- pass
271
  return result
272
 
273
  # ================= ПОСТРОЕНИЕ ПРИЗНАКОВ =================
@@ -308,15 +256,10 @@ def build_sol_features(df, onchain_data=None, derivatives=None):
308
 
309
  if len(close) >= 14:
310
  prev_close = close.shift(1)
311
- tr = pd.DataFrame({
312
- "tr1": high-low,
313
- "tr2": (high-prev_close).abs(),
314
- "tr3": (low-prev_close).abs()
315
- }).max(axis=1)
316
  features["atr_14"] = safe_float(tr.rolling(14, min_periods=14).mean().iloc[-1])
317
  features["atr_pct"] = (features["atr_14"] / (close.iloc[-1] + 1e-10)) * 100
318
 
319
- # ADX
320
  features["adx"] = 20.0
321
 
322
  if onchain_data:
@@ -336,9 +279,8 @@ def build_sol_features(df, onchain_data=None, derivatives=None):
336
 
337
  return features
338
 
339
- # ================= ОТПРАВКА СИГНАЛА (ИСПРАВЛЕНО) =================
340
  def send_signal_to_hub(signal: str, confidence: float, features: Dict = None):
341
- """🔥 ИСПРАВЛЕНО: signal вместо direction, space_id вместо space"""
342
  if features is None:
343
  features = {}
344
 
@@ -346,30 +288,30 @@ def send_signal_to_hub(signal: str, confidence: float, features: Dict = None):
346
  "space_id": SPACE_ID,
347
  "space_name": SPACE_NAME,
348
  "symbol": SYMBOL,
349
- "signal": signal, # ✅ BUY/SELL/WAIT
350
  "confidence": round(confidence, 4),
351
  "features": features,
352
- "metadata": {"version": "10.2"},
353
  "timestamp": datetime.now().isoformat()
354
  }
355
 
356
  for attempt in range(3):
357
  try:
358
  headers = hub_headers()
359
- r = session.post(f"{HUB_URL}/signals", json=payload, timeout=15, headers=headers)
360
  if r.status_code == 200:
361
  logger.info(f"📤 {SYMBOL}: {signal} conf={confidence:.3f}")
362
  return True
363
  elif r.status_code == 429:
364
- wait = 3 * (attempt + 1)
365
  logger.warning(f"⏳ 429, жду {wait}с...")
366
  time.sleep(wait)
367
  else:
368
  logger.warning(f"Попытка {attempt+1}: HTTP {r.status_code}")
369
- time.sleep(2)
370
  except Exception as e:
371
  logger.warning(f"Попытка {attempt+1}: {e}")
372
- time.sleep(2)
373
 
374
  logger.error("❌ Не удалось отправить сигнал после 3 попыток")
375
  return False
@@ -419,8 +361,7 @@ def get_sol_signal():
419
  proba = MODELS[mk].predict_proba(X)[0]
420
  probs.append(float(proba[1] if len(proba) > 1 else proba[0]))
421
  models_used += 1
422
- except Exception as e:
423
- logger.warning(f" ⚠️ Ошибка {mk}: {e}")
424
 
425
  if MODELS.get("lgb"):
426
  try:
@@ -428,12 +369,10 @@ def get_sol_signal():
428
  lgb_prob = float(proba[1] if len(proba) > 1 else proba[0])
429
  xgb_prob = (sum(probs)/len(probs) * 0.6 + lgb_prob * 0.4) if probs else lgb_prob
430
  models_used += 1
431
- except:
432
- pass
433
  elif probs:
434
  xgb_prob = sum(probs) / len(probs)
435
- except Exception as e:
436
- logger.warning(f" ⚠️ Ошибка предсказания: {e}")
437
 
438
  # Мульти-ТФ
439
  confirmations, total_tf = 0, 0
@@ -455,24 +394,19 @@ def get_sol_signal():
455
 
456
  deriv_norm = 0.7 if binance_data.get("funding_signal") == "BULLISH" else 0.3 if binance_data.get("funding_signal") == "BEARISH" else 0.5
457
 
458
- # Динамические веса
459
  base = REGIME_WEIGHTS.get(regime, REGIME_WEIGHTS["RANGE"])
460
- model_w = base["model"] * (COMPONENT_PERF["model"]["correct"] / max(COMPONENT_PERF["model"]["total"], 1)) * COMPONENT_PERF["model"]["sharpe"]
461
- tf_w = base["tf"] * (COMPONENT_PERF["tf"]["correct"] / max(COMPONENT_PERF["tf"]["total"], 1)) * COMPONENT_PERF["tf"]["sharpe"]
462
  remaining = 1.0 - (model_w + tf_w)
463
  onchain_w = remaining * 0.6
464
  deriv_w = remaining * 0.4
465
  total_w = model_w + tf_w + onchain_w + deriv_w
466
  if total_w > 0:
467
- model_w /= total_w
468
- tf_w /= total_w
469
- onchain_w /= total_w
470
- deriv_w /= total_w
471
 
472
  final_score = xgb_prob * model_w + tf_norm * tf_w + meta_sol_score * onchain_w + deriv_norm * deriv_w
473
  confidence = smooth_confidence(final_score)
474
 
475
- # 🔥 BUY/SELL вместо LONG/SHORT
476
  if confidence > SOL_THRESHOLD + 0.08:
477
  signal = "BUY"
478
  elif confidence < SOL_THRESHOLD - 0.08:
@@ -480,13 +414,7 @@ def get_sol_signal():
480
  else:
481
  signal = "WAIT"
482
 
483
- features_out = {
484
- "ml_prob": xgb_prob,
485
- "tf_norm": tf_norm,
486
- "meta_sol_score": meta_sol_score,
487
- "regime": regime,
488
- "models_used": models_used
489
- }
490
  send_signal_to_hub(signal, confidence, features_out)
491
 
492
  logger.info(f"🥉 SOL/USD: {signal} | conf={confidence:.3f} | models={models_used} | regime={regime}")
@@ -505,17 +433,11 @@ def auto_report():
505
 
506
  threading.Thread(target=auto_report, daemon=True).start()
507
 
508
- app = FastAPI(title="SOL Master v10.2")
509
 
510
  @app.get("/health")
511
  async def health():
512
- return {
513
- "space_id": SPACE_ID,
514
- "status": "ok",
515
- "version": "10.2",
516
- "symbol": SYMBOL,
517
- "models": sum(1 for m in MODELS.values() if m is not None)
518
- }
519
 
520
  @app.head("/health")
521
  async def health_head():
@@ -530,10 +452,10 @@ async def consilium():
530
 
531
  @app.get("/")
532
  async def root():
533
- return {"name": "SOL Master v10.2", "space_id": SPACE_ID, "hub": HUB_URL}
534
 
535
  if __name__ == "__main__":
536
  import uvicorn
537
  uvicorn.run(app, host="0.0.0.0", port=7860)
538
 
539
- print("🚀 SPACE 19 v10.2SOL/USD MASTER ГОТОВ К РАБОТЕ!")
 
1
  # ============================================
2
+ # 👑 TOMIRIS SPACE 19 v10.3 — SOL/USD MASTER (LIGHT)
3
  # ============================================
4
  import os, time, threading, warnings, json, asyncio
5
  from typing import Dict, Any, Optional, List, Tuple
 
28
 
29
  HUB_URL = os.getenv("HUB_URL", "https://pro-3-tomiris-hub.hf.space")
30
  HUB_SECRET = os.getenv("HUB_SECRET", "TomyrisUltraSecret2026!")
 
31
 
32
  STARTUP_SLEEP = int(os.getenv("STARTUP_SLEEP", "600"))
33
  AUTO_REPORT_INTERVAL = 600
 
39
  logger.info(f"🔗 Хаб: {HUB_URL}")
40
 
41
  def hub_headers():
42
+ return {"X-Hub-Secret": HUB_SECRET, "Content-Type": "application/json"}
 
 
 
43
 
44
+ CACHE_TTL = 600 # 🔥 10 минут кэш!
45
  DATA_CACHE: Dict[str, Dict[str, Any]] = {}
46
  PREDICTION_HISTORY = deque(maxlen=500)
47
  LAST_CONFIDENCE = 0.5
 
76
 
77
  # ================= HTTP СЕССИЯ =================
78
  session = requests.Session()
79
+ session.headers.update({"User-Agent": "Tomiris-Space19-v10.3"})
80
 
81
  # ================= УТИЛИТЫ =================
82
  def safe_float(value, default=0.0):
 
84
  if isinstance(value, (pd.Series, pd.DataFrame)):
85
  return float(value.iloc[-1]) if len(value) > 0 else default
86
  return float(value) if not pd.isna(float(value)) else default
87
+ except: return default
 
88
 
89
  def safe_rsi(close, period=14):
90
  try:
 
95
  if pd.notna(g_val) and pd.notna(l_val) and l_val > 0:
96
  return float(100 - (100 / (1 + g_val/l_val)))
97
  return 50.0
98
+ except: return 50.0
 
99
 
100
  def safe_ema(close, span):
101
+ try: return float(close.ewm(span=span, adjust=False).mean().iloc[-1])
102
+ except: return float(close.iloc[-1])
 
 
103
 
104
  def hurst_exponent(series, lags=20):
105
+ if len(series) < lags * 2: return 0.5
 
106
  lags_range = range(2, min(lags, len(series)//2))
107
  tau = [np.std(np.subtract(series.values[lag:], series.values[:-lag])) for lag in lags_range]
108
+ try: return float(np.polyfit(np.log(list(lags_range)), np.log(tau), 1)[0] * 2.0)
109
+ except: return 0.5
 
 
110
 
111
  def smooth_confidence(current):
112
  global LAST_CONFIDENCE
 
119
  adx = features.get("adx", 20.0)
120
  volatility = features.get("volatility_1h", 0.0)
121
  hurst = features.get("hurst_exponent", 0.5)
122
+ if adx > 30 and hurst > 0.55: return "TREND"
123
+ if volatility > 0.04: return "VOLATILE"
 
 
124
  return "RANGE"
125
 
126
+ # ================= ЗАГРУЗКА ДАННЫХ (ТОЛЬКО ХАБ!) =================
127
  def fetch_ohlc_hub(symbol, tf, limit=200):
128
  cache_key = f"hub_{symbol}_{tf}"
129
  if cache_key in DATA_CACHE and time.time() - DATA_CACHE[cache_key].get("timestamp", 0) < CACHE_TTL:
 
133
  r = session.get(
134
  f"{HUB_URL}/candles",
135
  params={"symbol": symbol, "interval": tf, "limit": limit},
136
+ timeout=30, # 🔥 Увеличен таймаут
137
  headers=hub_headers()
138
  )
139
  if r.status_code == 200:
 
148
  if len(df) >= 30:
149
  DATA_CACHE[cache_key] = {"df": df, "timestamp": time.time()}
150
  return df
151
+ else:
152
+ logger.warning(f"Hub {symbol} {tf}: HTTP {r.status_code}")
153
  except Exception as e:
154
  logger.warning(f"Hub {symbol} {tf}: {e}")
155
  return None
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  def fetch_ohlc(symbol, tf="1h"):
158
+ # 🔥 ТОЛЬКО ХАБ! Без Twelve Data!
159
+ return fetch_ohlc_hub(symbol, tf)
 
 
 
160
 
161
  def fetch_solana_onchain():
162
+ """Ончейн данные Solana"""
163
  cache_key = "solana_onchain"
164
+ if cache_key in DATA_CACHE and time.time() - DATA_CACHE[cache_key].get("timestamp", 0) < CACHE_TTL:
165
  return DATA_CACHE[cache_key]["data"]
166
 
167
  result = {}
 
 
168
  try:
169
  r = session.get("https://api.llama.fi/tvl/solana", timeout=10)
170
  if r.status_code == 200:
 
178
  elif isinstance(data, dict):
179
  result['tvl'] = data.get('tvl', 0)
180
  result['tvl_change_24h'] = data.get('change_1d', 0)
181
+ except: pass
182
+ except: pass
 
 
 
 
 
 
 
183
 
184
+ result['tvl'] = result.get('tvl', 0)
185
+ result['tvl_change_24h'] = result.get('tvl_change_24h', 0)
186
  result['tvl_trend'] = 'UP' if result.get('tvl_change_24h', 0) > 0 else 'DOWN'
187
 
 
188
  try:
189
+ r = session.get("https://api.llama.fi/overview/dexs/solana?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true", timeout=10)
 
 
 
190
  if r.status_code == 200:
191
  data = r.json()
192
  result['dex_volume_24h'] = data.get('total24h', 0)
193
  result['dex_change_24h'] = data.get('change_1d', 0)
194
+ except: pass
195
+
196
+ result['dex_volume_24h'] = result.get('dex_volume_24h', 0)
197
+ result['dex_change_24h'] = result.get('dex_change_24h', 0)
 
 
 
198
 
199
  DATA_CACHE[cache_key] = {"data": result, "timestamp": time.time()}
200
  return result
 
210
  result['funding_rate'] = fr
211
  result['funding_signal'] = 'BEARISH' if fr > 0.001 else 'BULLISH' if fr < -0.001 else 'NEUTRAL'
212
  break
213
+ except: pass
 
214
  try:
215
  r = session.get("https://fapi.binance.com/fapi/v1/openInterest?symbol=SOLUSDT", timeout=10)
216
  if r.status_code == 200:
217
  result['open_interest'] = float(r.json().get('openInterest', 0))
218
+ except: pass
 
219
  return result
220
 
221
  # ================= ПОСТРОЕНИЕ ПРИЗНАКОВ =================
 
256
 
257
  if len(close) >= 14:
258
  prev_close = close.shift(1)
259
+ tr = pd.DataFrame({"tr1": high-low, "tr2": (high-prev_close).abs(), "tr3": (low-prev_close).abs()}).max(axis=1)
 
 
 
 
260
  features["atr_14"] = safe_float(tr.rolling(14, min_periods=14).mean().iloc[-1])
261
  features["atr_pct"] = (features["atr_14"] / (close.iloc[-1] + 1e-10)) * 100
262
 
 
263
  features["adx"] = 20.0
264
 
265
  if onchain_data:
 
279
 
280
  return features
281
 
282
+ # ================= ОТПРАВКА СИГНАЛА =================
283
  def send_signal_to_hub(signal: str, confidence: float, features: Dict = None):
 
284
  if features is None:
285
  features = {}
286
 
 
288
  "space_id": SPACE_ID,
289
  "space_name": SPACE_NAME,
290
  "symbol": SYMBOL,
291
+ "signal": signal,
292
  "confidence": round(confidence, 4),
293
  "features": features,
294
+ "metadata": {"version": "10.3"},
295
  "timestamp": datetime.now().isoformat()
296
  }
297
 
298
  for attempt in range(3):
299
  try:
300
  headers = hub_headers()
301
+ r = session.post(f"{HUB_URL}/signals", json=payload, timeout=30, headers=headers)
302
  if r.status_code == 200:
303
  logger.info(f"📤 {SYMBOL}: {signal} conf={confidence:.3f}")
304
  return True
305
  elif r.status_code == 429:
306
+ wait = 5 * (attempt + 1)
307
  logger.warning(f"⏳ 429, жду {wait}с...")
308
  time.sleep(wait)
309
  else:
310
  logger.warning(f"Попытка {attempt+1}: HTTP {r.status_code}")
311
+ time.sleep(3)
312
  except Exception as e:
313
  logger.warning(f"Попытка {attempt+1}: {e}")
314
+ time.sleep(3)
315
 
316
  logger.error("❌ Не удалось отправить сигнал после 3 попыток")
317
  return False
 
361
  proba = MODELS[mk].predict_proba(X)[0]
362
  probs.append(float(proba[1] if len(proba) > 1 else proba[0]))
363
  models_used += 1
364
+ except: pass
 
365
 
366
  if MODELS.get("lgb"):
367
  try:
 
369
  lgb_prob = float(proba[1] if len(proba) > 1 else proba[0])
370
  xgb_prob = (sum(probs)/len(probs) * 0.6 + lgb_prob * 0.4) if probs else lgb_prob
371
  models_used += 1
372
+ except: pass
 
373
  elif probs:
374
  xgb_prob = sum(probs) / len(probs)
375
+ except: pass
 
376
 
377
  # Мульти-ТФ
378
  confirmations, total_tf = 0, 0
 
394
 
395
  deriv_norm = 0.7 if binance_data.get("funding_signal") == "BULLISH" else 0.3 if binance_data.get("funding_signal") == "BEARISH" else 0.5
396
 
 
397
  base = REGIME_WEIGHTS.get(regime, REGIME_WEIGHTS["RANGE"])
398
+ model_w = base["model"] * (COMPONENT_PERF["model"]["correct"] / max(COMPONENT_PERF["model"]["total"], 1))
399
+ tf_w = base["tf"] * (COMPONENT_PERF["tf"]["correct"] / max(COMPONENT_PERF["tf"]["total"], 1))
400
  remaining = 1.0 - (model_w + tf_w)
401
  onchain_w = remaining * 0.6
402
  deriv_w = remaining * 0.4
403
  total_w = model_w + tf_w + onchain_w + deriv_w
404
  if total_w > 0:
405
+ model_w /= total_w; tf_w /= total_w; onchain_w /= total_w; deriv_w /= total_w
 
 
 
406
 
407
  final_score = xgb_prob * model_w + tf_norm * tf_w + meta_sol_score * onchain_w + deriv_norm * deriv_w
408
  confidence = smooth_confidence(final_score)
409
 
 
410
  if confidence > SOL_THRESHOLD + 0.08:
411
  signal = "BUY"
412
  elif confidence < SOL_THRESHOLD - 0.08:
 
414
  else:
415
  signal = "WAIT"
416
 
417
+ features_out = {"ml_prob": xgb_prob, "tf_norm": tf_norm, "meta_sol_score": meta_sol_score, "regime": regime, "models_used": models_used}
 
 
 
 
 
 
418
  send_signal_to_hub(signal, confidence, features_out)
419
 
420
  logger.info(f"🥉 SOL/USD: {signal} | conf={confidence:.3f} | models={models_used} | regime={regime}")
 
433
 
434
  threading.Thread(target=auto_report, daemon=True).start()
435
 
436
+ app = FastAPI(title="SOL Master v10.3 LIGHT")
437
 
438
  @app.get("/health")
439
  async def health():
440
+ return {"space_id": SPACE_ID, "status": "ok", "version": "10.3", "symbol": SYMBOL, "models": sum(1 for m in MODELS.values() if m is not None)}
 
 
 
 
 
 
441
 
442
  @app.head("/health")
443
  async def health_head():
 
452
 
453
  @app.get("/")
454
  async def root():
455
+ return {"name": "SOL Master v10.3 LIGHT", "space_id": SPACE_ID, "hub": HUB_URL}
456
 
457
  if __name__ == "__main__":
458
  import uvicorn
459
  uvicorn.run(app, host="0.0.0.0", port=7860)
460
 
461
+ print("🚀 SPACE 19 v10.3 LIGHT — ГОТОВ!")