Tradtesting / app.py
Riy777's picture
Update app.py
2167505 verified
raw
history blame
34 kB
# app.py (V23.2 - GEM-Architect: Full Enterprise Edition)
# هذه النسخة شاملة لكل الوظائف والعناصر البصرية دون أي حذف.
import os
import sys
import traceback
import asyncio
import gc
import time
import json
from datetime import datetime, timedelta
from contextlib import asynccontextmanager, redirect_stdout, redirect_stderr
from io import StringIO
from typing import List, Dict, Any
# مكتبات الواجهة والخادم
from fastapi import FastAPI, HTTPException, BackgroundTasks
import gradio as gr
import pandas as pd
import plotly.graph_objects as go
# ==============================================================================
# 📥 استيراد الوحدات الأساسية (Core Imports)
# ==============================================================================
try:
# 1. خدمات البنية التحتية والبيانات
from r2 import R2Service
from ml_engine.data_manager import DataManager
from whale_monitor.core import EnhancedWhaleMonitor
# 2. خدمات التحليل الأساسي (News/Sentiment)
from sentiment_news import NewsFetcher
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
# 3. ⚡ المحرك المركزي (The Brain) ⚡
# (يدير Titan, Oracle, Sniper, Patterns, Guardian)
from ml_engine.processor import MLProcessor
# 4. مدير التداول (The Executor)
from trade_manager import TradeManager
except ImportError as e:
# إيقاف النظام في حال فقدان أي ملف جوهري
sys.exit(f"❌ [FATAL ERROR] Failed to import core modules: {e}")
# ==============================================================================
# 🌐 المتغيرات العامة (Global Instances)
# ==============================================================================
r2: R2Service = None
data_manager: DataManager = None
ml_processor: MLProcessor = None
trade_manager: TradeManager = None
whale_monitor: EnhancedWhaleMonitor = None
news_fetcher: NewsFetcher = None
senti_analyzer: SentimentIntensityAnalyzer = None
sys_state: 'SystemState' = None
# ==============================================================================
# 🔄 حالة النظام (System State Tracker)
# ==============================================================================
class SystemState:
"""تتبع حالة النظام والطيار الآلي"""
def __init__(self):
self.ready = False
self.cycle_running = False
self.auto_pilot = True # التشغيل التلقائي مفعل افتراضياً
self.last_cycle_time: datetime = None
self.last_cycle_error = None
self.app_start_time = datetime.now()
self.last_cycle_logs = "النظام قيد التهيئة... يرجى الانتظار."
def set_ready(self):
self.ready = True
self.last_cycle_logs = "✅ النظام جاهز. الطيار الآلي مفعل (ON)."
def set_cycle_start(self):
self.cycle_running = True
self.last_cycle_logs = "🌀 [Cycle START] جاري البحث والتحليل..."
def set_cycle_end(self, error=None, logs=None):
self.cycle_running = False
self.last_cycle_time = datetime.now()
self.last_cycle_error = str(error) if error else None
if logs:
self.last_cycle_logs = logs
elif error:
self.last_cycle_logs = f"❌ [Cycle ERROR] {error}"
else:
self.last_cycle_logs = f"✅ [Cycle END] {datetime.now().strftime('%H:%M:%S')}. انتهت الدورة."
sys_state = SystemState()
# ==============================================================================
# 🛠️ دوال مساعدة (Utilities)
# ==============================================================================
def format_crypto_price(price):
"""تنسيق السعر لإزالة الأصفار الزائدة."""
if price is None: return "0.0"
try:
p = float(price)
if p == 0: return "0.0"
return "{:.8f}".format(p).rstrip('0').rstrip('.')
except:
return str(price)
def calculate_duration_str(timestamp_str):
"""حساب المدة الزمنية (Uptime / Trade Duration)."""
if not timestamp_str:
return "--:--:--"
try:
if isinstance(timestamp_str, str):
try:
start_time = datetime.fromisoformat(timestamp_str)
except ValueError:
start_time = datetime.strptime(timestamp_str, "%Y-%m-%dT%H:%M:%S.%f")
else:
start_time = timestamp_str
now = datetime.now()
diff = now - start_time
total_seconds = int(diff.total_seconds())
days = total_seconds // 86400
hours = (total_seconds % 86400) // 3600
minutes = (total_seconds % 3600) // 60
seconds = total_seconds % 60
if days > 0:
return f"{days}d {hours:02}:{minutes:02}:{seconds:02}"
return f"{hours:02}:{minutes:02}:{seconds:02}"
except Exception:
return "--:--:--"
# ==============================================================================
# 🤖 Auto-Pilot Daemon (المحرك الخلفي)
# ==============================================================================
async def auto_pilot_loop():
"""
مراقب الخلفية: يفحص النظام كل 10 ثواني ويبدأ دورة البحث إذا كان الوضع آمناً.
"""
print("🤖 [Auto-Pilot] Daemon started running in background...")
while True:
try:
# فاصل زمني لحماية الموارد
await asyncio.sleep(10)
# التحقق من جاهزية النظام
if not sys_state.ready: continue
# منطق التشغيل:
# 1. الطيار الآلي مفعل
# 2. لا توجد دورة تعمل حالياً
# 3. لا توجد صفقات مفتوحة (لأن النظام يركز على إدارة الصفقة المفتوحة تلقائياً عبر الحارس)
if sys_state.auto_pilot and not sys_state.cycle_running:
if trade_manager and len(trade_manager.open_positions) == 0:
asyncio.create_task(run_unified_cycle())
# انتظار إضافي لمنع التداخل
await asyncio.sleep(5)
else:
# في حال وجود صفقة، النظام في وضع "الحراسة" (Sentry Mode) ولا يحتاج لإطلاق دورة بحث جديدة
pass
except Exception as e:
print(f"⚠️ [Auto-Pilot Error] {e}")
# في حال الخطأ ننتظر فترة أطول
await asyncio.sleep(30)
# ==============================================================================
# 🚀 Lifespan (بدء وإيقاف النظام)
# ==============================================================================
@asynccontextmanager
async def lifespan(app: FastAPI):
global r2, data_manager, ml_processor, trade_manager, whale_monitor, news_fetcher, senti_analyzer, sys_state
print("\n🚀 [System] Startup Sequence Initiated (Titan V23.2 Enterprise)...")
print("------------------------------------------------------")
try:
# 1. تهيئة طبقة البيانات والاتصال
print(" [1/6] Initializing R2 & Data Services...")
r2 = R2Service()
data_manager = DataManager(contracts_db={}, whale_monitor=None, r2_service=r2)
await data_manager.initialize()
await data_manager.load_contracts_from_r2()
# 2. الخدمات المساعدة
print(" [2/6] Starting Auxiliary Services (Whales/News)...")
whale_monitor = EnhancedWhaleMonitor(contracts_db=data_manager.get_contracts_db(), r2_service=r2)
news_fetcher = NewsFetcher()
senti_analyzer = SentimentIntensityAnalyzer()
data_manager.whale_monitor = whale_monitor
# 3. ⚡ تهيئة المعالج المركزي (Brain) ⚡
print(" [3/6] Initializing Central ML Processor (Titan/Oracle/Sniper/Guardian)...")
ml_processor = MLProcessor(data_manager=data_manager)
await ml_processor.initialize()
# 4. تهيئة مدير التداول
print(" [4/6] Initializing Trade Manager...")
trade_manager = TradeManager(
r2_service=r2,
data_manager=data_manager,
processor=ml_processor # نمرر المعالج فقط، وهو يدير الذكاء الاصطناعي
)
await trade_manager.initialize_sentry_exchanges()
# إعادة تشغيل حراسة الصفقات المفتوحة (إن وجدت)
await trade_manager.start_sentry_loops()
# 5. تشغيل الطيار الآلي
print(" [5/6] Launching Auto-Pilot Daemon...")
sys_state.set_ready()
asyncio.create_task(auto_pilot_loop())
print("------------------------------------------------------")
print("✅ [System READY] All modules operational.")
print("------------------------------------------------------")
yield
except Exception as e:
print(f"❌ [FATAL STARTUP ERROR] {e}")
traceback.print_exc()
finally:
print("\n🛑 [System] Shutdown Sequence Initiated...")
sys_state.ready = False
if trade_manager: await trade_manager.stop_sentry_loops()
if data_manager: await data_manager.close()
print("✅ [System] Shutdown Complete.")
# ==============================================================================
# 🧠 Helper Task: Analyze Single Symbol
# ==============================================================================
async def _analyze_symbol_task(symbol: str) -> Dict[str, Any]:
"""
مهمة لجلب بيانات عملة واحدة وإرسالها للمعالج (Processor) للحصول على التقييم المركب.
"""
global data_manager, ml_processor
try:
required_tfs = ["5m", "15m", "1h", "4h", "1d"]
data_tasks = [data_manager.get_latest_ohlcv(symbol, tf, limit=250) for tf in required_tfs]
all_data = await asyncio.gather(*data_tasks)
ohlcv_data = {}
for tf, data in zip(required_tfs, all_data):
if data and len(data) > 0: ohlcv_data[tf] = data
# التحقق من توفر البيانات الأساسية
if '5m' not in ohlcv_data or '15m' not in ohlcv_data or '1h' not in ohlcv_data:
return None
current_price = await data_manager.get_latest_price_async(symbol)
raw_data = {'symbol': symbol, 'ohlcv': ohlcv_data, 'current_price': current_price}
# ⚡ طلب التحليل من المعالج المركزي (L1/L2 Analysis) ⚡
return await ml_processor.process_compound_signal(raw_data)
except Exception:
return None
# ==============================================================================
# 🚀 Unified Smart Cycle (Logic Flow)
# ==============================================================================
async def run_unified_cycle():
"""
دورة العمل الرئيسية:
1. مزامنة الحالة.
2. إدارة الصفقات المفتوحة (إن وجدت).
3. البحث (Screening).
4. التحليل (Analysis).
5. الاستشارة (Oracle).
6. التنفيذ (Sniper).
"""
log_buffer = StringIO()
def log_and_print(message):
print(message)
log_buffer.write(message + '\n')
# التحقق من حالة الدورة
if sys_state.cycle_running:
log_and_print("⚠️ [Cycle] الدورة قيد التشغيل بالفعل. تم تجاهل الطلب.")
return
if not sys_state.ready:
log_and_print("⚠️ [Cycle] النظام غير جاهز بعد.")
return
sys_state.set_cycle_start()
log_and_print(f"\n🌀 [Cycle START] {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
try:
# 0. مزامنة الحالة مع R2
await trade_manager.sync_internal_state_with_r2()
# 1. التحقق من الصفقات المفتوحة (Priority Management)
if len(trade_manager.open_positions) > 0:
symbol = list(trade_manager.open_positions.keys())[0]
trade = trade_manager.open_positions[symbol]
log_and_print(f"🔒 [Guardian Mode] صفقة نشطة: {symbol}. تخطي البحث للتركيز على الإدارة.")
# عرض تقرير الحارس (للمعلومات فقط، التنفيذ يتم في الخلفية)
try:
t1 = data_manager.get_latest_ohlcv(symbol, '1m', 300)
t5 = data_manager.get_latest_ohlcv(symbol, '5m', 200)
t15 = data_manager.get_latest_ohlcv(symbol, '15m', 100)
d1, d5, d15 = await asyncio.gather(t1, t5, t15)
if d1 and d5 and d15:
entry_p = trade['entry_price']
# ⚡ استشارة الحارس ⚡
decision = ml_processor.consult_guardian(d1, d5, d15, entry_p)
scores = decision.get('scores', {})
log_and_print(f" 📊 [Guardian Report] Status: {decision.get('action')}")
log_and_print(f" • V2 (Radar): {scores.get('v2',0):.4f}")
log_and_print(f" • V3 (Sniper): {scores.get('v3',0):.4f}")
log_and_print(f" • Reason: {decision.get('reason')}")
except Exception as e:
log_and_print(f" ⚠️ تعذر جلب تقرير الحارس المباشر: {e}")
sys_state.set_cycle_end(logs=log_buffer.getvalue())
return
# 2. البحث الأولي (L1 Screening)
log_and_print(" [1/4] 🔍 L1 Screening (Volume & Liquidity)...")
candidates = await data_manager.layer1_rapid_screening()
if not candidates:
log_and_print("⚠️ [Cycle] لم يتم العثور على أي عملات تلبي شروط L1.")
sys_state.set_cycle_end(logs=log_buffer.getvalue()); return
# 3. التحليل المعمق (L2 Analysis - Titan/Patterns)
log_and_print(f" [2/4] 🧠 L2 Deep Analysis for {len(candidates)} candidates...")
analysis_start = time.time()
tasks = [_analyze_symbol_task(c['symbol']) for c in candidates]
results = await asyncio.gather(*tasks)
valid_l2 = [res for res in results if res is not None]
# ترتيب حسب الدرجة النهائية المعززة
top_10 = sorted(valid_l2, key=lambda x: x.get('enhanced_final_score', 0.0), reverse=True)[:10]
log_and_print(f" -> اكتمل التحليل في {time.time() - analysis_start:.2f} ثانية.")
if not top_10:
log_and_print("⚠️ [Cycle] لم تنجح أي عملة في تجاوز L2.")
sys_state.set_cycle_end(logs=log_buffer.getvalue()); return
# عرض الجدول
log_and_print("\n" + "="*80)
log_and_print(f"{'SYMBOL':<10} | {'FINAL SCORE':<12} | {'TITAN':<8} | {'PATT':<8} | {'MC':<8}")
log_and_print("-" * 80)
for c in top_10:
comps = c.get('components', {})
log_and_print(f"{c['symbol']:<10} | {c['enhanced_final_score']:.4f} | {comps.get('titan_score',0):.2f} | {comps.get('patterns_score',0):.2f} | {comps.get('mc_score',0):.2f}")
log_and_print("="*80 + "\n")
# 4. العقل الاحتمالي (L3 Oracle)
log_and_print(f" [3/4] 🔮 L3 Oracle Consultation (Probabilistic Check)...")
approved_signals = []
for sig in top_10:
# تصفية أولية
if sig['enhanced_final_score'] < 0.60: continue
# ⚡ استشارة Oracle عبر المعالج ⚡
oracle_dec = await ml_processor.consult_oracle(sig)
if oracle_dec.get('action') == 'WATCH':
conf = oracle_dec.get('confidence', 0.0)
log_and_print(f" ✅ APPROVED: {sig['symbol']} (Conf: {conf:.2f})")
# إضافة الأهداف المقترحة
sig['tp_price'] = oracle_dec.get('tp_price')
sig['sl_price'] = oracle_dec.get('sl_price')
approved_signals.append(sig)
else:
log_and_print(f" ❌ REJECTED: {sig['symbol']} ({oracle_dec.get('reason')})")
# 5. القناص (L4 Sniper Execution)
if approved_signals:
log_and_print(f" [4/4] 🎯 L4 Sniper Execution Batch ({len(approved_signals)} signals)...")
# التقاط مخرجات TradeManager لإضافتها للسجل
tm_log_buffer = StringIO()
with redirect_stdout(tm_log_buffer), redirect_stderr(tm_log_buffer):
# TradeManager يستدعي القناص داخلياً عبر المعالج
await trade_manager.select_and_execute_best_signal(approved_signals)
tm_logs = tm_log_buffer.getvalue()
print(tm_logs)
log_buffer.write(tm_logs + '\n')
else:
log_and_print(" -> 🛑 لا توجد إشارات معتمدة من Oracle لإرسالها للقناص.")
# تنظيف الذاكرة
gc.collect()
log_and_print(f"🌀 [Cycle END] {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
sys_state.set_cycle_end(logs=log_buffer.getvalue())
except Exception as e:
err_msg = f"❌ [Cycle ERROR] {e}\n{traceback.format_exc()}"
log_and_print(err_msg)
sys_state.set_cycle_end(error=e, logs=log_buffer.getvalue())
# ==============================================================================
# 📊 [UI Logic] منطق العرض والتفاعل (Full Stats Restored)
# ==============================================================================
async def manual_close_current_trade():
"""زر الإغلاق اليدوي"""
if not trade_manager or not trade_manager.open_positions:
return "⚠️ لا توجد صفقة مفتوحة لإغلاقها."
symbol = list(trade_manager.open_positions.keys())[0]
await trade_manager.force_exit_by_manager(symbol, reason="MANUAL_UI_BUTTON")
return f"✅ تم إرسال أمر إغلاق فوري لـ {symbol}."
async def reset_stats_handler():
"""زر تصفير الإحصائيات"""
if trade_manager and len(trade_manager.open_positions) > 0:
return "⚠️ لا يمكن التصفير أثناء وجود صفقة مفتوحة. أغلقها أولاً."
success = await r2.reset_all_stats_async()
if success: return "✅ تم تصفير الحساب والسجلات بنجاح."
else: return "❌ فشل عملية التصفير."
async def toggle_auto_pilot(enable):
"""زر تبديل الطيار الآلي"""
sys_state.auto_pilot = enable
status = "مفعل (ON)" if enable else "متوقف (OFF)"
return f"تم تغيير وضع الطيار الآلي إلى: {status}"
async def run_cycle_from_gradio():
"""زر التشغيل اليدوي"""
if sys_state.cycle_running: return "الدورة تعمل بالفعل."
# تشغيل في الخلفية لعدم تجميد الواجهة
asyncio.create_task(run_unified_cycle())
return "🚀 تم إطلاق الدورة يدوياً... راجع السجلات."
async def check_live_pnl_and_status(selected_view="Hybrid System"):
"""
تحديث دوري للواجهة.
يتم استدعاء هذه الدالة كل 3 ثواني لتحديث الشارت والأرقام.
"""
# القيم الافتراضية
empty_chart = go.Figure()
empty_chart.update_layout(
template="plotly_dark", paper_bgcolor="#0b0f19", plot_bgcolor="#0b0f19",
xaxis={'visible': False}, yaxis={'visible': False},
annotations=[dict(text="Waiting for Signal...", x=0.5, y=0.5, showarrow=False, font=dict(color="gray", size=20))]
)
wl_df_empty = pd.DataFrame(columns=["Coin", "Score"])
if not sys_state.ready:
return "Initializing...", "...", empty_chart, "0.0", "0.0", "0.0", "0.0", "0.0%", wl_df_empty, "Loading...", "Loading..."
try:
# 1. جلب بيانات المحفظة من R2
portfolio = await r2.get_portfolio_state_async()
curr_cap = portfolio.get('current_capital_usd', 100.0)
first_ts = portfolio.get('first_trade_timestamp')
# حساب وقت التشغيل
uptime_str = calculate_duration_str(first_ts)
total_t = portfolio.get('total_trades', 0)
wins = portfolio.get('winning_trades', 0)
losses = portfolio.get('losing_trades', 0)
if losses == 0 and total_t > 0: losses = total_t - wins
tot_prof = portfolio.get('total_profit_usd', 0.0)
tot_loss = portfolio.get('total_loss_usd', 0.0)
net_prof = tot_prof - tot_loss
win_rate = (wins / total_t * 100) if total_t > 0 else 0.0
# 2. بيانات الصفقة النشطة (إن وجدت)
symbol = None
entry_p = 0.0; tp_p = 0.0; sl_p = 0.0; curr_p = 0.0
pnl_val = 0.0; pnl_pct = 0.0
trade_dur_str = "--:--:--"
if trade_manager.open_positions:
symbol = list(trade_manager.open_positions.keys())[0]
trade = trade_manager.open_positions[symbol]
entry_p = float(trade.get('entry_price', 0.0))
tp_p = float(trade.get('tp_price', 0.0))
sl_p = float(trade.get('sl_price', 0.0))
trade_dur_str = calculate_duration_str(trade.get('entry_time'))
curr_p = await data_manager.get_latest_price_async(symbol)
if curr_p > 0 and entry_p > 0:
pnl_pct = ((curr_p - entry_p) / entry_p) * 100
pnl_val = curr_cap * (pnl_pct / 100)
final_bal = curr_cap + pnl_val
wallet_color = "#00ff00" if pnl_val >= 0 else "#ff0000"
# 3. HTML المحفظة (Wallet Box)
wallet_md = f"""
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333; text-align:center;'>
<h3 style='margin:0; color:#888; font-size:14px;'>💰 Live Wallet</h3>
<div style='font-size: 26px; font-weight: bold; color: white; margin: 5px 0;'>
${final_bal:,.2f}
</div>
<div style='font-size: 14px; color: {wallet_color};'>
({pnl_val:+,.2f} USD)
</div>
<hr style='border-color:#444; margin: 10px 0;'>
<div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc;'>
<span>⏳ Uptime:</span>
<span style='color: white; font-family: monospace;'>{uptime_str}</span>
</div>
<div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
<span>⏱️ Trade Time:</span>
<span style='color: #00e5ff; font-family: monospace;'>{trade_dur_str}</span>
</div>
</div>
"""
# 4. إحصائيات الذكاء الاصطناعي (Stats Box)
# تحديد المفتاح بناءً على القائمة المنسدلة
key_map = {
"Hybrid System": "hybrid",
"Model V2 (Radar)": "v2",
"Model V3 (Sniper)": "v3"
}
target_key = key_map.get(selected_view, "hybrid")
stats_data = trade_manager.ai_stats.get(target_key, {"total":0, "good":0, "saved":0.0, "missed":0.0})
tot_ds = stats_data['total']
ds_acc = (stats_data['good'] / tot_ds * 100) if tot_ds > 0 else 0.0
# العنوان الديناميكي
title_map = {
"hybrid": "🧠 Hybrid Guardian IQ",
"v2": "📡 Model V2 (Radar)",
"v3": "🎯 Model V3 (Sniper)"
}
stats_title = title_map.get(target_key, "DeepSteward IQ")
history_md = f"""
<div style='background-color: #1a1a1a; padding: 10px; border-radius: 8px; border: 1px solid #333; font-size: 12px;'>
<h3 style='margin:0 0 5px 0; color:#888; font-size:14px;'>📊 Performance</h3>
<table style='width:100%; color:white; border-collapse: collapse;'>
<tr><td style='padding:2px;'>Total Trades:</td><td style='text-align:right; font-weight:bold;'>{total_t}</td></tr>
<tr><td style='padding:2px;'>Win Rate:</td><td style='text-align:right; color:{"#00ff00" if win_rate>=50 else "#ff0000"};'>{win_rate:.1f}%</td></tr>
<tr><td style='padding:2px;'>Wins:</td><td style='text-align:right; color:#00ff00;'>{wins} (+${tot_prof:,.2f})</td></tr>
<tr><td style='padding:2px;'>Losses:</td><td style='text-align:right; color:#ff0000;'>{losses} (-${tot_loss:,.2f})</td></tr>
<tr><td style='border-top:1px solid #444; padding-top:5px;'>Net Profit:</td><td style='border-top:1px solid #444; text-align:right; padding-top:5px; color:{"#00ff00" if net_prof>=0 else "#ff0000"};'>${net_prof:,.2f}</td></tr>
</table>
<hr style='border-color:#444; margin: 8px 0;'>
<h3 style='margin:0 0 5px 0; color: #00e5ff; font-size:14px;'>{stats_title}</h3>
<table style='width:100%; color:white;'>
<tr><td>Exits:</td><td style='text-align:right;'>{tot_ds}</td></tr>
<tr><td>Accuracy:</td><td style='text-align:right; color:#00e5ff;'>{ds_acc:.1f}%</td></tr>
<tr><td>Saved Loss:</td><td style='text-align:right; color:#00ff00;'>${stats_data['saved']:.2f}</td></tr>
<tr><td>Missed Profit:</td><td style='text-align:right; color:#ff0000;'>${stats_data['missed']:.2f}</td></tr>
</table>
</div>
"""
# 5. الرسم البياني (Chart)
fig = empty_chart
if symbol and curr_p > 0:
ohlcv = await data_manager.get_latest_ohlcv(symbol, '5m', 120)
if ohlcv and len(ohlcv) > 0:
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms')
fig = go.Figure(data=[go.Candlestick(
x=df['datetime'],
open=df['open'], high=df['high'], low=df['low'], close=df['close'],
increasing_line_color='#00ff00', decreasing_line_color='#ff0000',
name=symbol
)])
# خطوط المستويات
fig.add_hline(y=entry_p, line_dash="dash", line_color="white", opacity=0.5, annotation_text="Entry")
fig.add_hline(y=tp_p, line_color="#00ff00", line_width=1, annotation_text="TP")
fig.add_hline(y=sl_p, line_color="#ff0000", line_width=1, annotation_text="SL")
fig.update_layout(
template="plotly_dark",
paper_bgcolor="#0b0f19",
plot_bgcolor="#0b0f19",
margin=dict(l=0, r=50, t=30, b=0),
height=400,
xaxis_rangeslider_visible=False,
title=dict(text=f"{symbol} (5m)", x=0.05, font=dict(color="white", size=14)),
yaxis=dict(side='right', gridcolor='#222')
)
# 6. قائمة المراقبة (Watchlist)
wl_data = [[k, f"{v.get('final_total_score',0):.2f}"] for k, v in trade_manager.watchlist.items()]
wl_df = pd.DataFrame(wl_data, columns=["Coin", "Score"])
status_txt = sys_state.last_cycle_logs
status_line = f"Status: {'SCANNING' if sys_state.cycle_running else 'IDLE'} | Auto-Pilot: {'ON' if sys_state.auto_pilot else 'OFF'}"
return (
status_txt,
status_line,
fig,
f"{curr_p:.6f}",
f"{entry_p:.6f}",
f"{tp_p:.6f}",
f"{sl_p:.6f}",
f"{pnl_pct:+.2f}%",
wl_df,
wallet_md,
history_md
)
except Exception:
traceback.print_exc()
return "Error", "Error", empty_chart, "0", "0", "0", "0", "0%", wl_df_empty, "Err", "Err"
# ==============================================================================
# 🚀 Gradio UI Definition (The Dashboard)
# ==============================================================================
def create_gradio_ui():
css = """
.gradio-container { background-color: #0b0f19; }
.dataframe { color: white !important; background-color: #1a1a1a !important; }
thead th { background-color: #333 !important; color: white !important; }
.html-box { min-height: 180px; }
"""
with gr.Blocks(title="Titan V23.2 Pro Dashboard", css=css, theme=gr.themes.Monochrome()) as demo:
gr.Markdown("# 🚀 Titan V23.2 Enterprise (Full Architecture)")
# --- الصف العلوي: الشارت + الإحصائيات ---
with gr.Row():
# العمود الأيسر: الشارت + تفاصيل السعر
with gr.Column(scale=3):
live_chart_plot = gr.Plot(label="Live Chart", container=True)
with gr.Row():
t_price = gr.Textbox(label="Current Price", interactive=False)
t_pnl = gr.Textbox(label="PnL %", interactive=False)
with gr.Row():
t_entry = gr.Textbox(label="Entry", interactive=False)
t_tp = gr.Textbox(label="Target (TP)", interactive=False)
t_sl = gr.Textbox(label="Stop (SL)", interactive=False)
# العمود الأيمن: المحفظة والإحصائيات
with gr.Column(scale=1):
wallet_output = gr.HTML(label="Wallet", elem_classes="html-box")
stats_dropdown = gr.Dropdown(
choices=["Hybrid System", "Model V2 (Radar)", "Model V3 (Sniper)"],
value="Hybrid System",
label="Select AI View",
interactive=True
)
history_output = gr.HTML(label="Stats", elem_classes="html-box")
watchlist_output = gr.DataFrame(label="Watchlist", interactive=False)
gr.HTML("<hr style='border-color: #333;'>")
# --- الصف السفلي: التحكم والسجلات ---
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("## 🎮 Controls")
auto_pilot_checkbox = gr.Checkbox(
label="✈️ Auto-Pilot",
value=True
)
with gr.Row():
run_cycle_btn = gr.Button("🚀 Scan Now", variant="primary")
close_trade_btn = gr.Button("🚨 Panic Close", variant="stop")
reset_stats_btn = gr.Button("🗑️ Reset Stats", variant="secondary")
status_markdown = gr.Markdown("Initializing...")
alert_box = gr.Textbox(label="Alerts", interactive=False, visible=True)
with gr.Column(scale=3):
gr.Markdown("## 📜 System Logs")
cycle_logs_output = gr.Textbox(
lines=12,
autoscroll=True,
max_lines=50,
value="Waiting for logs..."
)
# --- التفاعلات (Events) ---
run_cycle_btn.click(fn=run_cycle_from_gradio, inputs=None, outputs=alert_box)
close_trade_btn.click(fn=manual_close_current_trade, inputs=None, outputs=alert_box)
reset_stats_btn.click(fn=reset_stats_handler, inputs=None, outputs=alert_box)
auto_pilot_checkbox.change(fn=toggle_auto_pilot, inputs=auto_pilot_checkbox, outputs=alert_box)
# المؤقت الدوري (كل 3 ثواني)
timer = gr.Timer(3)
timer.tick(
fn=check_live_pnl_and_status,
inputs=[stats_dropdown],
outputs=[
cycle_logs_output,
status_markdown,
live_chart_plot,
t_price,
t_entry,
t_tp,
t_sl,
t_pnl,
watchlist_output,
wallet_output,
history_output
]
)
return demo
# ==============================================================================
# 🏁 تشغيل الخادم
# ==============================================================================
app = FastAPI(
lifespan=lifespan,
title="Titan V23.2 Pro",
description="Titan Enterprise Trading System"
)
gradio_dashboard = create_gradio_ui()
app = gr.mount_gradio_app(app, gradio_dashboard, path="/")
if __name__ == "__main__":
import uvicorn
# التشغيل على كل الواجهات
uvicorn.run(app, host="0.0.0.0", port=7860)