Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
| 1 |
-
# app.py (V22.
|
|
|
|
|
|
|
| 2 |
import os
|
| 3 |
import sys
|
| 4 |
import traceback
|
|
@@ -31,7 +33,8 @@ try:
|
|
| 31 |
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 32 |
from ml_engine.sniper_engine import SniperEngine
|
| 33 |
|
| 34 |
-
# [ 🧠 الجوهرة ] استيراد الحارس الهجين
|
|
|
|
| 35 |
from ml_engine.hybrid_guardian import HybridDeepSteward
|
| 36 |
|
| 37 |
except ImportError as e:
|
|
@@ -58,7 +61,8 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
| 58 |
SHARED_GUARD_MODELS_DIR = os.path.join(BASE_DIR, "ml_models", "guard_v2")
|
| 59 |
UNIFIED_MODELS_DIR = os.path.join(BASE_DIR, "ml_models", "Unified_Models_V1")
|
| 60 |
|
| 61 |
-
# [ 🧠 ] مسارات النماذج
|
|
|
|
| 62 |
V2_MODEL_PATH = os.path.join(BASE_DIR, "ml_models", "DeepSteward_Production_V1.json")
|
| 63 |
V3_MODEL_PATH = os.path.join(BASE_DIR, "ml_models", "DeepSteward_V3_Production.json")
|
| 64 |
V3_FEATURES_PATH = os.path.join(BASE_DIR, "ml_models", "DeepSteward_V3_Features.json")
|
|
@@ -98,7 +102,7 @@ class SystemState:
|
|
| 98 |
sys_state = SystemState()
|
| 99 |
|
| 100 |
# ==============================================================================
|
| 101 |
-
# 🛠️ Helper Functions
|
| 102 |
# ==============================================================================
|
| 103 |
def format_crypto_price(price):
|
| 104 |
"""
|
|
@@ -115,13 +119,16 @@ def format_crypto_price(price):
|
|
| 115 |
def calculate_duration_str(timestamp_str):
|
| 116 |
"""
|
| 117 |
دالة لحساب المدة الزمنية (Uptime/Trade Duration) داخل بايثون
|
|
|
|
| 118 |
"""
|
| 119 |
if not timestamp_str:
|
| 120 |
return "--:--:--"
|
| 121 |
try:
|
|
|
|
| 122 |
try:
|
| 123 |
start_time = datetime.fromisoformat(str(timestamp_str))
|
| 124 |
except ValueError:
|
|
|
|
| 125 |
start_time = datetime.strptime(str(timestamp_str), "%Y-%m-%dT%H:%M:%S.%f")
|
| 126 |
|
| 127 |
now = datetime.now()
|
|
@@ -155,13 +162,18 @@ async def auto_pilot_loop():
|
|
| 155 |
if not sys_state.ready: continue
|
| 156 |
|
| 157 |
# الشروط الثلاثة للتشغيل التلقائي:
|
|
|
|
|
|
|
|
|
|
| 158 |
if sys_state.auto_pilot and not sys_state.cycle_running:
|
| 159 |
if trade_manager and len(trade_manager.open_positions) == 0:
|
| 160 |
-
# تشغيل الدورة
|
| 161 |
asyncio.create_task(run_unified_cycle())
|
| 162 |
-
|
|
|
|
| 163 |
await asyncio.sleep(5)
|
| 164 |
else:
|
|
|
|
| 165 |
pass
|
| 166 |
|
| 167 |
except Exception as e:
|
|
@@ -205,17 +217,19 @@ async def lifespan(app: FastAPI):
|
|
| 205 |
await sniper_engine.initialize()
|
| 206 |
sniper_engine.set_entry_threshold(0.35)
|
| 207 |
|
| 208 |
-
# [ 🧠 ] تهيئة
|
| 209 |
-
|
|
|
|
| 210 |
deep_steward = HybridDeepSteward(
|
| 211 |
v2_model_path=V2_MODEL_PATH,
|
| 212 |
v3_model_path=V3_MODEL_PATH,
|
| 213 |
v3_features_map_path=V3_FEATURES_PATH
|
| 214 |
)
|
|
|
|
| 215 |
if deep_steward.initialize():
|
| 216 |
-
print(" ✅ [Hybrid Guardian] جاهز للعمل:
|
| 217 |
else:
|
| 218 |
-
print(" ⚠️ [Hybrid Guardian] فشل التحميل!
|
| 219 |
|
| 220 |
print(" [FINAL] تهيئة TradeManager...")
|
| 221 |
trade_manager = TradeManager(
|
|
@@ -223,7 +237,7 @@ async def lifespan(app: FastAPI):
|
|
| 223 |
data_manager=data_manager,
|
| 224 |
titan_engine=ml_processor.titan,
|
| 225 |
pattern_engine=ml_processor.pattern_engine,
|
| 226 |
-
guard_engine=None,
|
| 227 |
sniper_engine=sniper_engine,
|
| 228 |
deep_steward=deep_steward # تمرير الحارس الهجين
|
| 229 |
)
|
|
@@ -277,7 +291,7 @@ async def _analyze_symbol_task(symbol: str) -> Dict[str, Any]:
|
|
| 277 |
return None
|
| 278 |
|
| 279 |
# ==============================================================================
|
| 280 |
-
# [ 🚀 🚀 🚀 ] الدورة الموحدة (كاملة بدون حذف)
|
| 281 |
# ==============================================================================
|
| 282 |
async def run_unified_cycle():
|
| 283 |
|
|
@@ -313,15 +327,40 @@ async def run_unified_cycle():
|
|
| 313 |
log_and_print(f" -> المراقبة تتم كل 60 ثانية في الخلفية (V2 Radar + V3 Sniper).")
|
| 314 |
log_and_print(f" -> باقي نماذج البحث (L1/L2/L3) في وضع السكون لتوفير الموارد.")
|
| 315 |
|
| 316 |
-
# فحص طوارئ سريع (فقط للتأكيد)
|
| 317 |
current_price = await data_manager.get_latest_price_async(symbol)
|
| 318 |
log_and_print(f" -> السعر الحالي: {format_crypto_price(current_price)}")
|
| 319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
sys_state.set_cycle_end(logs=log_buffer.getvalue())
|
| 321 |
return
|
| 322 |
|
| 323 |
# ============================================================
|
| 324 |
-
# 🔍 وضع البحث (Scanning Mode) - Normal Flow
|
| 325 |
# ============================================================
|
| 326 |
|
| 327 |
# --- 1. الغربلة الأولية (L1) ---
|
|
@@ -487,7 +526,7 @@ async def run_unified_cycle():
|
|
| 487 |
# ==============================================================================
|
| 488 |
app = FastAPI(
|
| 489 |
lifespan=lifespan,
|
| 490 |
-
title="Titan V22.
|
| 491 |
description="نظام تداول آلي هجين (L1/L2/L3-ML) مع حارس ذكي مزدوج وواجهة Gradio مدمجة"
|
| 492 |
)
|
| 493 |
|
|
@@ -607,7 +646,7 @@ async def check_live_pnl_and_status(selected_view="Hybrid System"):
|
|
| 607 |
final_bal = curr_cap + pnl_val
|
| 608 |
wallet_color = "#00ff00" if pnl_val >= 0 else "#ff0000"
|
| 609 |
|
| 610 |
-
# 3. 🎨 Wallet HTML
|
| 611 |
wallet_md = f"""
|
| 612 |
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333; text-align:center;'>
|
| 613 |
<h3 style='margin:0; color:#888; font-size:14px;'>💰 Live Wallet</h3>
|
|
@@ -631,6 +670,7 @@ async def check_live_pnl_and_status(selected_view="Hybrid System"):
|
|
| 631 |
"""
|
| 632 |
|
| 633 |
# 4. 🧠 [Dynamic Stats] جلب الإحصائيات بناءً على ال��ائمة المنسدلة
|
|
|
|
| 634 |
key_map = {
|
| 635 |
"Hybrid System": "hybrid",
|
| 636 |
"Model V2 (Radar)": "v2",
|
|
@@ -642,12 +682,13 @@ async def check_live_pnl_and_status(selected_view="Hybrid System"):
|
|
| 642 |
if hasattr(trade_manager, 'ai_stats'):
|
| 643 |
stats_data = trade_manager.ai_stats.get(target_key, {"total":0, "good":0, "saved":0.0, "missed":0.0})
|
| 644 |
else:
|
|
|
|
| 645 |
stats_data = {"total":0, "good":0, "saved":0.0, "missed":0.0}
|
| 646 |
|
| 647 |
tot_ds = stats_data['total']
|
| 648 |
ds_acc = (stats_data['good'] / tot_ds * 100) if tot_ds > 0 else 0.0
|
| 649 |
|
| 650 |
-
# Dynamic Title
|
| 651 |
title_map = {
|
| 652 |
"hybrid": "🧠 Hybrid Guardian IQ",
|
| 653 |
"v2": "📡 Model V2 (Radar)",
|
|
@@ -703,7 +744,7 @@ async def check_live_pnl_and_status(selected_view="Hybrid System"):
|
|
| 703 |
paper_bgcolor="#0b0f19",
|
| 704 |
plot_bgcolor="#0b0f19",
|
| 705 |
margin=dict(l=0, r=50, t=30, b=0),
|
| 706 |
-
height=400,
|
| 707 |
xaxis_rangeslider_visible=False,
|
| 708 |
title=dict(text=f"{symbol} (5m)", x=0.05, font=dict(color="white", size=14)),
|
| 709 |
yaxis=dict(side='right', gridcolor='#222')
|
|
@@ -752,16 +793,18 @@ def create_gradio_ui():
|
|
| 752 |
.html-box { min-height: 180px; }
|
| 753 |
"""
|
| 754 |
|
| 755 |
-
with gr.Blocks(title="Titan V22.
|
| 756 |
|
| 757 |
-
gr.Markdown("# 🚀 Titan V22.
|
| 758 |
|
| 759 |
# --- الصف العلوي: الشارت + الإحصائيات ---
|
| 760 |
with gr.Row():
|
| 761 |
-
# العمود الأيسر: الشارت + تفاصيل السعر
|
| 762 |
with gr.Column(scale=3):
|
|
|
|
| 763 |
live_chart_plot = gr.Plot(label="Live Chart", container=True)
|
| 764 |
|
|
|
|
| 765 |
with gr.Row():
|
| 766 |
t_price = gr.Textbox(label="Current Price", interactive=False, elem_classes="text-yellow")
|
| 767 |
t_pnl = gr.Textbox(label="PnL %", interactive=False)
|
|
@@ -822,7 +865,7 @@ def create_gradio_ui():
|
|
| 822 |
reset_stats_btn.click(fn=reset_stats_handler, inputs=None, outputs=alert_box)
|
| 823 |
auto_pilot_checkbox.change(fn=toggle_auto_pilot, inputs=auto_pilot_checkbox, outputs=alert_box)
|
| 824 |
|
| 825 |
-
# المؤقت الدوري (كل 3 ثواني) -
|
| 826 |
timer = gr.Timer(3)
|
| 827 |
timer.tick(
|
| 828 |
fn=check_live_pnl_and_status,
|
|
@@ -830,7 +873,7 @@ def create_gradio_ui():
|
|
| 830 |
outputs=[
|
| 831 |
cycle_logs_output,
|
| 832 |
status_markdown,
|
| 833 |
-
live_chart_plot,
|
| 834 |
t_price,
|
| 835 |
t_entry,
|
| 836 |
t_tp,
|
|
|
|
| 1 |
+
# app.py (V22.3 - GEM-Architect: Full Source Code - Hybrid Guardian Edition)
|
| 2 |
+
# Based on Original V21.3 logic with V4 Dual Brain Integration
|
| 3 |
+
|
| 4 |
import os
|
| 5 |
import sys
|
| 6 |
import traceback
|
|
|
|
| 33 |
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 34 |
from ml_engine.sniper_engine import SniperEngine
|
| 35 |
|
| 36 |
+
# [ 🧠 الجوهرة ] استيراد الحارس الهجين (V4 Dual Brain)
|
| 37 |
+
# تم استبدال الاستيراد القديم بهذا الجديد
|
| 38 |
from ml_engine.hybrid_guardian import HybridDeepSteward
|
| 39 |
|
| 40 |
except ImportError as e:
|
|
|
|
| 61 |
SHARED_GUARD_MODELS_DIR = os.path.join(BASE_DIR, "ml_models", "guard_v2")
|
| 62 |
UNIFIED_MODELS_DIR = os.path.join(BASE_DIR, "ml_models", "Unified_Models_V1")
|
| 63 |
|
| 64 |
+
# [ 🧠 ] مسارات النماذج للحارس الهجين
|
| 65 |
+
# تأكد من وجود هذه الملفات في مجلد ml_models
|
| 66 |
V2_MODEL_PATH = os.path.join(BASE_DIR, "ml_models", "DeepSteward_Production_V1.json")
|
| 67 |
V3_MODEL_PATH = os.path.join(BASE_DIR, "ml_models", "DeepSteward_V3_Production.json")
|
| 68 |
V3_FEATURES_PATH = os.path.join(BASE_DIR, "ml_models", "DeepSteward_V3_Features.json")
|
|
|
|
| 102 |
sys_state = SystemState()
|
| 103 |
|
| 104 |
# ==============================================================================
|
| 105 |
+
# 🛠️ Helper Functions (تمت إضافة دالة الوقت هنا لحل مشكلة العداد)
|
| 106 |
# ==============================================================================
|
| 107 |
def format_crypto_price(price):
|
| 108 |
"""
|
|
|
|
| 119 |
def calculate_duration_str(timestamp_str):
|
| 120 |
"""
|
| 121 |
دالة لحساب المدة الزمنية (Uptime/Trade Duration) داخل بايثون
|
| 122 |
+
لحل مشكلة توقف العدادات في الواجهة.
|
| 123 |
"""
|
| 124 |
if not timestamp_str:
|
| 125 |
return "--:--:--"
|
| 126 |
try:
|
| 127 |
+
# محاولة قراءة التوقيت بأكثر من صيغة محتملة
|
| 128 |
try:
|
| 129 |
start_time = datetime.fromisoformat(str(timestamp_str))
|
| 130 |
except ValueError:
|
| 131 |
+
# تنسيق احتياطي إذا فشل ISO
|
| 132 |
start_time = datetime.strptime(str(timestamp_str), "%Y-%m-%dT%H:%M:%S.%f")
|
| 133 |
|
| 134 |
now = datetime.now()
|
|
|
|
| 162 |
if not sys_state.ready: continue
|
| 163 |
|
| 164 |
# الشروط الثلاثة للتشغيل التلقائي:
|
| 165 |
+
# 1. الطيار الآلي مفعل (Checkbox Checked)
|
| 166 |
+
# 2. لا توجد دورة تعمل حالياً
|
| 167 |
+
# 3. لا توجد صفقات مفتوحة
|
| 168 |
if sys_state.auto_pilot and not sys_state.cycle_running:
|
| 169 |
if trade_manager and len(trade_manager.open_positions) == 0:
|
| 170 |
+
# تشغيل الدورة (دون انتظارها لتنتهي هنا، نطلقها فقط)
|
| 171 |
asyncio.create_task(run_unified_cycle())
|
| 172 |
+
|
| 173 |
+
# ننتظر فترة أطول قليلاً بعد إطلاق الدورة لمنع التكرار الفوري
|
| 174 |
await asyncio.sleep(5)
|
| 175 |
else:
|
| 176 |
+
# إذا كانت هناك صفقة، الطيار الآلي يراقب فقط ولا يتدخل في الدورة
|
| 177 |
pass
|
| 178 |
|
| 179 |
except Exception as e:
|
|
|
|
| 217 |
await sniper_engine.initialize()
|
| 218 |
sniper_engine.set_entry_threshold(0.35)
|
| 219 |
|
| 220 |
+
# [ 🧠 ] تهيئة الحارس الهجين (Hybrid Deep Steward)
|
| 221 |
+
# هذا هو التغيير الجوهري لدمج النظامين V2 و V3
|
| 222 |
+
print(f" [8/8] تهيئة Hybrid Guardian (V2 + V3 Dual Brain)...")
|
| 223 |
deep_steward = HybridDeepSteward(
|
| 224 |
v2_model_path=V2_MODEL_PATH,
|
| 225 |
v3_model_path=V3_MODEL_PATH,
|
| 226 |
v3_features_map_path=V3_FEATURES_PATH
|
| 227 |
)
|
| 228 |
+
|
| 229 |
if deep_steward.initialize():
|
| 230 |
+
print(" ✅ [Hybrid Guardian] جاهز للعمل: V2 (Radar) + V3 (Sniper).")
|
| 231 |
else:
|
| 232 |
+
print(" ⚠️ [Hybrid Guardian] فشل التحميل! تأكد من وجود ملفات النماذج.")
|
| 233 |
|
| 234 |
print(" [FINAL] تهيئة TradeManager...")
|
| 235 |
trade_manager = TradeManager(
|
|
|
|
| 237 |
data_manager=data_manager,
|
| 238 |
titan_engine=ml_processor.titan,
|
| 239 |
pattern_engine=ml_processor.pattern_engine,
|
| 240 |
+
guard_engine=None, # تم إلغاء الحارس القديم
|
| 241 |
sniper_engine=sniper_engine,
|
| 242 |
deep_steward=deep_steward # تمرير الحارس الهجين
|
| 243 |
)
|
|
|
|
| 291 |
return None
|
| 292 |
|
| 293 |
# ==============================================================================
|
| 294 |
+
# [ 🚀 🚀 🚀 ] الدورة الموحدة (كاملة بدون حذف - منطق المسح والبحث)
|
| 295 |
# ==============================================================================
|
| 296 |
async def run_unified_cycle():
|
| 297 |
|
|
|
|
| 327 |
log_and_print(f" -> المراقبة تتم كل 60 ثانية في الخلفية (V2 Radar + V3 Sniper).")
|
| 328 |
log_and_print(f" -> باقي نماذج البحث (L1/L2/L3) في وضع السكون لتوفير الموارد.")
|
| 329 |
|
|
|
|
| 330 |
current_price = await data_manager.get_latest_price_async(symbol)
|
| 331 |
log_and_print(f" -> السعر الحالي: {format_crypto_price(current_price)}")
|
| 332 |
|
| 333 |
+
# --- [NEW] استشارة الحارس وعرض الطوابع في السجلات ---
|
| 334 |
+
# هذا الكود مضاف لكي ترى النتائج في الواجهة عند ضغط زر Scan
|
| 335 |
+
try:
|
| 336 |
+
log_and_print(" -> 📡 جاري طلب تقرير الحارس المباشر (Consultation Scan)...")
|
| 337 |
+
|
| 338 |
+
# جلب البيانات اللازمة للتحليل
|
| 339 |
+
t1 = data_manager.get_latest_ohlcv(symbol, '1m', 120)
|
| 340 |
+
t5 = data_manager.get_latest_ohlcv(symbol, '5m', 100)
|
| 341 |
+
t15 = data_manager.get_latest_ohlcv(symbol, '15m', 50)
|
| 342 |
+
|
| 343 |
+
d1, d5, d15 = await asyncio.gather(t1, t5, t15)
|
| 344 |
+
|
| 345 |
+
# تحليل استشاري (لا ينفذ خروجاً هنا، فقط يعرض الرأي)
|
| 346 |
+
if d1 and d5 and d15 and len(d1) >= 64:
|
| 347 |
+
decision = deep_steward.analyze_position(d1, d5, d15, float(trade['entry_price']))
|
| 348 |
+
scores = decision.get('scores', {'v2': 0.0, 'v3': 0.0})
|
| 349 |
+
|
| 350 |
+
log_and_print(f"\n 📊 [GUARDIAN LIVE REPORT]")
|
| 351 |
+
log_and_print(f" • Decision: {decision.get('action')} ({decision.get('reason')})")
|
| 352 |
+
log_and_print(f" • V2 (Radar): {scores.get('v2', 0.0):.4f} [Safe < {deep_steward.V2_SAFE_LIMIT} | Panic > {deep_steward.V2_PANIC_TRIGGER}]")
|
| 353 |
+
log_and_print(f" • V3 (Sniper): {scores.get('v3', 0.0):.4f} [Hard > {deep_steward.V3_HARD_EXIT} | Ultra > {deep_steward.V3_ULTRA_CONF}]")
|
| 354 |
+
else:
|
| 355 |
+
log_and_print(" ⚠️ بيانات السوق غير كافية للتحليل اللحظي الآن.")
|
| 356 |
+
except Exception as e:
|
| 357 |
+
log_and_print(f" ⚠️ تعذر عرض تقرير الحارس: {e}")
|
| 358 |
+
|
| 359 |
sys_state.set_cycle_end(logs=log_buffer.getvalue())
|
| 360 |
return
|
| 361 |
|
| 362 |
# ============================================================
|
| 363 |
+
# 🔍 وضع البحث (Scanning Mode) - Normal Flow (كامل بدون حذف)
|
| 364 |
# ============================================================
|
| 365 |
|
| 366 |
# --- 1. الغربلة الأولية (L1) ---
|
|
|
|
| 526 |
# ==============================================================================
|
| 527 |
app = FastAPI(
|
| 528 |
lifespan=lifespan,
|
| 529 |
+
title="Titan V22.3 Pro (Hybrid Guardian + MultiStats)",
|
| 530 |
description="نظام تداول آلي هجين (L1/L2/L3-ML) مع حارس ذكي مزدوج وواجهة Gradio مدمجة"
|
| 531 |
)
|
| 532 |
|
|
|
|
| 646 |
final_bal = curr_cap + pnl_val
|
| 647 |
wallet_color = "#00ff00" if pnl_val >= 0 else "#ff0000"
|
| 648 |
|
| 649 |
+
# 3. 🎨 Wallet HTML (مع توقيتات بايثون)
|
| 650 |
wallet_md = f"""
|
| 651 |
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333; text-align:center;'>
|
| 652 |
<h3 style='margin:0; color:#888; font-size:14px;'>💰 Live Wallet</h3>
|
|
|
|
| 670 |
"""
|
| 671 |
|
| 672 |
# 4. 🧠 [Dynamic Stats] جلب الإحصائيات بناءً على ال��ائمة المنسدلة
|
| 673 |
+
# Mapping selection to dict keys
|
| 674 |
key_map = {
|
| 675 |
"Hybrid System": "hybrid",
|
| 676 |
"Model V2 (Radar)": "v2",
|
|
|
|
| 682 |
if hasattr(trade_manager, 'ai_stats'):
|
| 683 |
stats_data = trade_manager.ai_stats.get(target_key, {"total":0, "good":0, "saved":0.0, "missed":0.0})
|
| 684 |
else:
|
| 685 |
+
# Fallback for old versions just in case
|
| 686 |
stats_data = {"total":0, "good":0, "saved":0.0, "missed":0.0}
|
| 687 |
|
| 688 |
tot_ds = stats_data['total']
|
| 689 |
ds_acc = (stats_data['good'] / tot_ds * 100) if tot_ds > 0 else 0.0
|
| 690 |
|
| 691 |
+
# Dynamic Title based on selection
|
| 692 |
title_map = {
|
| 693 |
"hybrid": "🧠 Hybrid Guardian IQ",
|
| 694 |
"v2": "📡 Model V2 (Radar)",
|
|
|
|
| 744 |
paper_bgcolor="#0b0f19",
|
| 745 |
plot_bgcolor="#0b0f19",
|
| 746 |
margin=dict(l=0, r=50, t=30, b=0),
|
| 747 |
+
height=400, # ارتفاع مناسب
|
| 748 |
xaxis_rangeslider_visible=False,
|
| 749 |
title=dict(text=f"{symbol} (5m)", x=0.05, font=dict(color="white", size=14)),
|
| 750 |
yaxis=dict(side='right', gridcolor='#222')
|
|
|
|
| 793 |
.html-box { min-height: 180px; }
|
| 794 |
"""
|
| 795 |
|
| 796 |
+
with gr.Blocks(title="Titan V22.3 Pro Dashboard", css=css, theme=gr.themes.Monochrome()) as demo:
|
| 797 |
|
| 798 |
+
gr.Markdown("# 🚀 Titan V22.3 Pro (Hybrid Guardian Edition)")
|
| 799 |
|
| 800 |
# --- الصف العلوي: الشارت + الإحصائيات ---
|
| 801 |
with gr.Row():
|
| 802 |
+
# العمود الأيسر: الشارت + تفاصيل السعر (لتقليل الوميض نفصلها)
|
| 803 |
with gr.Column(scale=3):
|
| 804 |
+
# 🌟 استخدام gr.Plot هو الحل الجذري لمشكلة الشارت
|
| 805 |
live_chart_plot = gr.Plot(label="Live Chart", container=True)
|
| 806 |
|
| 807 |
+
# صف التفاصيل الحية (تحديث نصوص فقط = لا وميض)
|
| 808 |
with gr.Row():
|
| 809 |
t_price = gr.Textbox(label="Current Price", interactive=False, elem_classes="text-yellow")
|
| 810 |
t_pnl = gr.Textbox(label="PnL %", interactive=False)
|
|
|
|
| 865 |
reset_stats_btn.click(fn=reset_stats_handler, inputs=None, outputs=alert_box)
|
| 866 |
auto_pilot_checkbox.change(fn=toggle_auto_pilot, inputs=auto_pilot_checkbox, outputs=alert_box)
|
| 867 |
|
| 868 |
+
# المؤقت الدوري (كل 3 ثواني) - يغذي الخانات المنفصلة
|
| 869 |
timer = gr.Timer(3)
|
| 870 |
timer.tick(
|
| 871 |
fn=check_live_pnl_and_status,
|
|
|
|
| 873 |
outputs=[
|
| 874 |
cycle_logs_output,
|
| 875 |
status_markdown,
|
| 876 |
+
live_chart_plot, # التحديث هنا ذكي ولا يسبب وميض
|
| 877 |
t_price,
|
| 878 |
t_entry,
|
| 879 |
t_tp,
|