Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# app.py (
|
| 2 |
import os
|
| 3 |
import sys
|
| 4 |
import traceback
|
|
@@ -32,7 +32,7 @@ try:
|
|
| 32 |
from whale_monitor.core import EnhancedWhaleMonitor
|
| 33 |
from sentiment_news import NewsFetcher
|
| 34 |
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 35 |
-
# [تم الحذف] GuardEngine لم يعد له حاجة
|
| 36 |
from ml_engine.sniper_engine import SniperEngine
|
| 37 |
|
| 38 |
# [ 🧠 الجوهرة ] استيراد الوصي العميق V2
|
|
@@ -287,7 +287,7 @@ async def run_unified_cycle():
|
|
| 287 |
# ============================================================
|
| 288 |
if len(trade_manager.open_positions) > 0:
|
| 289 |
symbol = list(trade_manager.open_positions.keys())[0]
|
| 290 |
-
trade = trade_manager.open_positions[symbol]
|
| 291 |
|
| 292 |
log_and_print(f"🔒 [DeepSteward V2] الصفقة {symbol} نشطة وتحت الحراسة المشددة.")
|
| 293 |
log_and_print(f" -> المراقبة تتم كل 60 ثانية في الخلفية (Multi-Scale Scan).")
|
|
@@ -301,7 +301,7 @@ async def run_unified_cycle():
|
|
| 301 |
return
|
| 302 |
|
| 303 |
# ============================================================
|
| 304 |
-
# 🔍 وضع البحث (Scanning Mode) - Normal Flow
|
| 305 |
# ============================================================
|
| 306 |
|
| 307 |
# --- 1. الغربلة الأولية (L1) ---
|
|
@@ -493,31 +493,87 @@ async def get_full_status():
|
|
| 493 |
}
|
| 494 |
|
| 495 |
# ==============================================================================
|
| 496 |
-
# 📊 [ 💡 GEM-ARCHITECT: NEW UI LOGIC (FIXED) ]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
|
| 499 |
async def manual_close_current_trade():
|
| 500 |
-
"""
|
| 501 |
-
دالة زر الإغلاق اليدوي
|
| 502 |
-
"""
|
| 503 |
if not trade_manager.open_positions:
|
| 504 |
return "⚠️ لا توجد صفقة مفتوحة لإغلاقها."
|
| 505 |
-
|
| 506 |
symbol = list(trade_manager.open_positions.keys())[0]
|
| 507 |
await trade_manager.force_exit_by_manager(symbol, reason="MANUAL_UI_BUTTON")
|
| 508 |
return f"✅ تم إرسال أمر إغلاق فوري لـ {symbol}."
|
| 509 |
|
| 510 |
-
# [جديد] معالج زر التصفير
|
| 511 |
async def reset_stats_handler():
|
| 512 |
-
"""معالج زر التصفير"""
|
| 513 |
if len(trade_manager.open_positions) > 0:
|
| 514 |
return "⚠️ خطأ: يجب إغلاق الصفقات المفتوحة أولاً قبل التصفير!"
|
| 515 |
-
|
| 516 |
success = await r2.reset_all_stats_async()
|
| 517 |
if success: return "✅ تم تصفير الحساب والسجلات بنجاح."
|
| 518 |
else: return "❌ فشل التصفير. راجع السجلات."
|
| 519 |
|
| 520 |
-
# تبديل وضع الطيار الآلي (On/Off)
|
| 521 |
async def toggle_auto_pilot(enable):
|
| 522 |
sys_state.auto_pilot = enable
|
| 523 |
status = "مفعل (ON)" if enable else "متوقف (OFF)"
|
|
@@ -525,24 +581,26 @@ async def toggle_auto_pilot(enable):
|
|
| 525 |
|
| 526 |
async def check_live_pnl_and_status():
|
| 527 |
"""
|
| 528 |
-
تحديث الواجهة الدورية (الرسوم، الحالة، الإحصائيات، المحفظة)
|
| 529 |
"""
|
| 530 |
global trade_manager, data_manager, sys_state, r2
|
| 531 |
|
| 532 |
empty_watchlist = pd.DataFrame(columns=["عملات المراقبة"])
|
| 533 |
|
| 534 |
-
# Default Values
|
| 535 |
wallet_md = "### 💰 جاري التحميل..."
|
| 536 |
history_md = "### 📊 جاري التحميل..."
|
| 537 |
|
| 538 |
if not sys_state.ready:
|
| 539 |
return "النظام قيد التهيئة...", "...", "...", "...", "...", None, empty_watchlist, wallet_md, history_md
|
| 540 |
|
| 541 |
-
# 1. جلب بيانات ال
|
| 542 |
try:
|
| 543 |
portfolio_state = await r2.get_portfolio_state_async()
|
| 544 |
current_capital = portfolio_state.get('current_capital_usd', 0.0)
|
| 545 |
-
initial_capital = portfolio_state.get('initial_capital_usd', 10.0)
|
|
|
|
|
|
|
| 546 |
|
| 547 |
total_trades = portfolio_state.get('total_trades', 0)
|
| 548 |
winning_trades = portfolio_state.get('winning_trades', 0)
|
|
@@ -550,21 +608,22 @@ async def check_live_pnl_and_status():
|
|
| 550 |
total_profit = portfolio_state.get('total_profit_usd', 0.0)
|
| 551 |
total_loss = portfolio_state.get('total_loss_usd', 0.0)
|
| 552 |
|
| 553 |
-
# الحساب اليدوي للخسارة في حال لم تكن موجودة في الملف القديم
|
| 554 |
if losing_trades == 0 and total_trades > 0:
|
| 555 |
losing_trades = total_trades - winning_trades
|
| 556 |
|
| 557 |
win_rate = (winning_trades / total_trades * 100) if total_trades > 0 else 0.0
|
| 558 |
net_profit = total_profit - total_loss
|
| 559 |
|
| 560 |
-
#
|
| 561 |
dynamic_balance = current_capital
|
| 562 |
pnl_unrealized = 0.0
|
| 563 |
-
|
|
|
|
| 564 |
if trade_manager.open_positions:
|
| 565 |
symbol = list(trade_manager.open_positions.keys())[0]
|
| 566 |
trade = trade_manager.open_positions[symbol]
|
| 567 |
entry_price = float(trade.get('entry_price', 0.0))
|
|
|
|
| 568 |
|
| 569 |
curr_price = await data_manager.get_latest_price_async(symbol)
|
| 570 |
if curr_price > 0 and entry_price > 0:
|
|
@@ -572,8 +631,12 @@ async def check_live_pnl_and_status():
|
|
| 572 |
pnl_unrealized = current_capital * pnl_pct
|
| 573 |
dynamic_balance = current_capital + pnl_unrealized
|
| 574 |
|
| 575 |
-
#
|
|
|
|
|
|
|
| 576 |
wallet_color = "#00ff00" if pnl_unrealized >= 0 else "#ff0000"
|
|
|
|
|
|
|
| 577 |
wallet_md = f"""
|
| 578 |
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333;'>
|
| 579 |
<h3 style='margin-top:0; color: #888;'>💰 المحفظة الحية</h3>
|
|
@@ -586,15 +649,29 @@ async def check_live_pnl_and_status():
|
|
| 586 |
<div style='font-size: 12px; color: #666; margin-top:5px;'>
|
| 587 |
الرصيد الأساسي: ${initial_capital:,.2f}
|
| 588 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 589 |
</div>
|
|
|
|
| 590 |
"""
|
| 591 |
|
| 592 |
-
# [
|
| 593 |
ds = trade_manager.ds_stats
|
| 594 |
total_ds = ds['total_exits']
|
| 595 |
ds_accuracy = (ds['good_exits'] / total_ds * 100) if total_ds > 0 else 0.0
|
| 596 |
|
| 597 |
-
# تنسيق عرض الإحصائيات (مع لوحة ذكاء النموذج)
|
| 598 |
history_md = f"""
|
| 599 |
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333;'>
|
| 600 |
<h3 style='margin-top:0; color: #888;'>📊 الأداء التاريخي</h3>
|
|
@@ -622,8 +699,9 @@ async def check_live_pnl_and_status():
|
|
| 622 |
except Exception as e:
|
| 623 |
wallet_md = f"Error: {e}"
|
| 624 |
history_md = "Error loading stats"
|
|
|
|
| 625 |
|
| 626 |
-
# 2. الحالة العامة
|
| 627 |
try:
|
| 628 |
status_text = sys_state.last_cycle_logs
|
| 629 |
trade_count = len(trade_manager.open_positions)
|
|
@@ -641,7 +719,7 @@ async def check_live_pnl_and_status():
|
|
| 641 |
except Exception:
|
| 642 |
return "Error", "...", "...", "...", "...", None, empty_watchlist, wallet_md, history_md
|
| 643 |
|
| 644 |
-
# 3. التحقق من الصفقة المفتوحة (للشارت والـ PnL)
|
| 645 |
if not trade_manager.open_positions:
|
| 646 |
return status_text, status_md, "### 💤 لا توجد صفقة مفتوحة", "---", "---", None, watchlist_df, wallet_md, history_md
|
| 647 |
|
|
@@ -720,8 +798,8 @@ def create_gradio_ui():
|
|
| 720 |
.gradio-container { background-color: #0b0f19; }
|
| 721 |
"""
|
| 722 |
|
| 723 |
-
with gr.Blocks(title="Titan
|
| 724 |
-
gr.Markdown("# 🚀 Titan
|
| 725 |
|
| 726 |
# --- الصف العلوي: الشارت + الإحصائيات الحية ---
|
| 727 |
with gr.Row():
|
|
|
|
| 1 |
+
# app.py (V20.0 - GEM-Architect: Final Production - Full Logic + V2 IQ + Live Timers)
|
| 2 |
import os
|
| 3 |
import sys
|
| 4 |
import traceback
|
|
|
|
| 32 |
from whale_monitor.core import EnhancedWhaleMonitor
|
| 33 |
from sentiment_news import NewsFetcher
|
| 34 |
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 35 |
+
# [تم الحذف] GuardEngine القديم لم يعد له حاجة
|
| 36 |
from ml_engine.sniper_engine import SniperEngine
|
| 37 |
|
| 38 |
# [ 🧠 الجوهرة ] استيراد الوصي العميق V2
|
|
|
|
| 287 |
# ============================================================
|
| 288 |
if len(trade_manager.open_positions) > 0:
|
| 289 |
symbol = list(trade_manager.open_positions.keys())[0]
|
| 290 |
+
# trade = trade_manager.open_positions[symbol]
|
| 291 |
|
| 292 |
log_and_print(f"🔒 [DeepSteward V2] الصفقة {symbol} نشطة وتحت الحراسة المشددة.")
|
| 293 |
log_and_print(f" -> المراقبة تتم كل 60 ثانية في الخلفية (Multi-Scale Scan).")
|
|
|
|
| 301 |
return
|
| 302 |
|
| 303 |
# ============================================================
|
| 304 |
+
# 🔍 وضع البحث (Scanning Mode) - Normal Flow (كامل بدون حذف)
|
| 305 |
# ============================================================
|
| 306 |
|
| 307 |
# --- 1. الغربلة الأولية (L1) ---
|
|
|
|
| 493 |
}
|
| 494 |
|
| 495 |
# ==============================================================================
|
| 496 |
+
# 📊 [ 💡 GEM-ARCHITECT: NEW UI LOGIC (FIXED & FULL) ]
|
| 497 |
+
# ==============================================================================
|
| 498 |
+
|
| 499 |
+
# ==============================================================================
|
| 500 |
+
# 🕒 [جديد] كود جافاسكريبت للعدادات الحية (يتم حقنه في HTML)
|
| 501 |
# ==============================================================================
|
| 502 |
+
LIVE_TIMER_JS = """
|
| 503 |
+
<script>
|
| 504 |
+
function updateLiveTimers() {
|
| 505 |
+
const now = new Date().getTime();
|
| 506 |
+
|
| 507 |
+
// 1. تحديث عداد وقت تشغيل النظام (System Uptime)
|
| 508 |
+
const uptimeElement = document.getElementById('system-uptime-counter');
|
| 509 |
+
if (uptimeElement) {
|
| 510 |
+
const startTimeStr = uptimeElement.getAttribute('data-start-time');
|
| 511 |
+
if (startTimeStr && startTimeStr !== 'None') {
|
| 512 |
+
const startTime = new Date(startTimeStr).getTime();
|
| 513 |
+
const diff = now - startTime;
|
| 514 |
+
|
| 515 |
+
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
| 516 |
+
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
| 517 |
+
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
| 518 |
+
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
|
| 519 |
+
|
| 520 |
+
let timeString = "";
|
| 521 |
+
if (days > 0) timeString += days + " يوم و ";
|
| 522 |
+
timeString += hours.toString().padStart(2, '0') + ":" +
|
| 523 |
+
minutes.toString().padStart(2, '0') + ":" +
|
| 524 |
+
seconds.toString().padStart(2, '0');
|
| 525 |
+
|
| 526 |
+
uptimeElement.innerText = timeString;
|
| 527 |
+
} else {
|
| 528 |
+
uptimeElement.innerText = "في انتظار أول صفقة...";
|
| 529 |
+
}
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
// 2. تحديث عداد مدة الصفقة الحالية (Trade Duration)
|
| 533 |
+
const tradeDurationElement = document.getElementById('trade-duration-counter');
|
| 534 |
+
if (tradeDurationElement) {
|
| 535 |
+
const entryTimeStr = tradeDurationElement.getAttribute('data-entry-time');
|
| 536 |
+
if (entryTimeStr && entryTimeStr !== 'None') {
|
| 537 |
+
const entryTime = new Date(entryTimeStr).getTime();
|
| 538 |
+
const diff = now - entryTime;
|
| 539 |
+
|
| 540 |
+
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
| 541 |
+
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
| 542 |
+
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
|
| 543 |
+
|
| 544 |
+
tradeDurationElement.innerText =
|
| 545 |
+
hours.toString().padStart(2, '0') + ":" +
|
| 546 |
+
minutes.toString().padStart(2, '0') + ":" +
|
| 547 |
+
seconds.toString().padStart(2, '0');
|
| 548 |
+
} else {
|
| 549 |
+
tradeDurationElement.innerText = "--:--:--";
|
| 550 |
+
}
|
| 551 |
+
}
|
| 552 |
+
}
|
| 553 |
+
|
| 554 |
+
// تنظيف المؤقتات القديمة لمنع التكرار عند تحديث غراديو
|
| 555 |
+
if (window.liveTimerInterval) clearInterval(window.liveTimerInterval);
|
| 556 |
+
// تشغيل التحديث كل ثانية
|
| 557 |
+
window.liveTimerInterval = setInterval(updateLiveTimers, 1000);
|
| 558 |
+
// تشغيل فوري لأول مرة
|
| 559 |
+
updateLiveTimers();
|
| 560 |
+
</script>
|
| 561 |
+
"""
|
| 562 |
|
| 563 |
async def manual_close_current_trade():
|
|
|
|
|
|
|
|
|
|
| 564 |
if not trade_manager.open_positions:
|
| 565 |
return "⚠️ لا توجد صفقة مفتوحة لإغلاقها."
|
|
|
|
| 566 |
symbol = list(trade_manager.open_positions.keys())[0]
|
| 567 |
await trade_manager.force_exit_by_manager(symbol, reason="MANUAL_UI_BUTTON")
|
| 568 |
return f"✅ تم إرسال أمر إغلاق فوري لـ {symbol}."
|
| 569 |
|
|
|
|
| 570 |
async def reset_stats_handler():
|
|
|
|
| 571 |
if len(trade_manager.open_positions) > 0:
|
| 572 |
return "⚠️ خطأ: يجب إغلاق الصفقات المفتوحة أولاً قبل التصفير!"
|
|
|
|
| 573 |
success = await r2.reset_all_stats_async()
|
| 574 |
if success: return "✅ تم تصفير الحساب والسجلات بنجاح."
|
| 575 |
else: return "❌ فشل التصفير. راجع السجلات."
|
| 576 |
|
|
|
|
| 577 |
async def toggle_auto_pilot(enable):
|
| 578 |
sys_state.auto_pilot = enable
|
| 579 |
status = "مفعل (ON)" if enable else "متوقف (OFF)"
|
|
|
|
| 581 |
|
| 582 |
async def check_live_pnl_and_status():
|
| 583 |
"""
|
| 584 |
+
تحديث الواجهة الدورية (الرسوم، الحالة، الإحصائيات، المحفظة، والعدادات الحية)
|
| 585 |
"""
|
| 586 |
global trade_manager, data_manager, sys_state, r2
|
| 587 |
|
| 588 |
empty_watchlist = pd.DataFrame(columns=["عملات المراقبة"])
|
| 589 |
|
| 590 |
+
# Default Values
|
| 591 |
wallet_md = "### 💰 جاري التحميل..."
|
| 592 |
history_md = "### 📊 جاري التحميل..."
|
| 593 |
|
| 594 |
if not sys_state.ready:
|
| 595 |
return "النظام قيد التهيئة...", "...", "...", "...", "...", None, empty_watchlist, wallet_md, history_md
|
| 596 |
|
| 597 |
+
# 1. جلب البيانات الأساسية
|
| 598 |
try:
|
| 599 |
portfolio_state = await r2.get_portfolio_state_async()
|
| 600 |
current_capital = portfolio_state.get('current_capital_usd', 0.0)
|
| 601 |
+
initial_capital = portfolio_state.get('initial_capital_usd', 10.0)
|
| 602 |
+
# [ 🕒 جديد] جلب وقت أول صفقة
|
| 603 |
+
first_trade_ts = portfolio_state.get('first_trade_timestamp')
|
| 604 |
|
| 605 |
total_trades = portfolio_state.get('total_trades', 0)
|
| 606 |
winning_trades = portfolio_state.get('winning_trades', 0)
|
|
|
|
| 608 |
total_profit = portfolio_state.get('total_profit_usd', 0.0)
|
| 609 |
total_loss = portfolio_state.get('total_loss_usd', 0.0)
|
| 610 |
|
|
|
|
| 611 |
if losing_trades == 0 and total_trades > 0:
|
| 612 |
losing_trades = total_trades - winning_trades
|
| 613 |
|
| 614 |
win_rate = (winning_trades / total_trades * 100) if total_trades > 0 else 0.0
|
| 615 |
net_profit = total_profit - total_loss
|
| 616 |
|
| 617 |
+
# حسابات المحفظة والصفقة الحالية
|
| 618 |
dynamic_balance = current_capital
|
| 619 |
pnl_unrealized = 0.0
|
| 620 |
+
current_trade_entry_time = None # [ 🕒 جديد] لتخزين وقت دخول الصفقة الحالية
|
| 621 |
+
|
| 622 |
if trade_manager.open_positions:
|
| 623 |
symbol = list(trade_manager.open_positions.keys())[0]
|
| 624 |
trade = trade_manager.open_positions[symbol]
|
| 625 |
entry_price = float(trade.get('entry_price', 0.0))
|
| 626 |
+
current_trade_entry_time = trade.get('entry_time') # [ 🕒 جديد] جلب وقت الدخول
|
| 627 |
|
| 628 |
curr_price = await data_manager.get_latest_price_async(symbol)
|
| 629 |
if curr_price > 0 and entry_price > 0:
|
|
|
|
| 631 |
pnl_unrealized = current_capital * pnl_pct
|
| 632 |
dynamic_balance = current_capital + pnl_unrealized
|
| 633 |
|
| 634 |
+
# ==============================================================================
|
| 635 |
+
# 🎨 بناء واجهة المحفظة مع العدادات الحية
|
| 636 |
+
# ==============================================================================
|
| 637 |
wallet_color = "#00ff00" if pnl_unrealized >= 0 else "#ff0000"
|
| 638 |
+
|
| 639 |
+
# نمرر التوقيتات كـ data-attributes لعناصر HTML ليقرأها الجافاسكريبت
|
| 640 |
wallet_md = f"""
|
| 641 |
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333;'>
|
| 642 |
<h3 style='margin-top:0; color: #888;'>💰 المحفظة الحية</h3>
|
|
|
|
| 649 |
<div style='font-size: 12px; color: #666; margin-top:5px;'>
|
| 650 |
الرصيد الأساسي: ${initial_capital:,.2f}
|
| 651 |
</div>
|
| 652 |
+
|
| 653 |
+
<hr style='border-color:#444; margin: 10px 0;'>
|
| 654 |
+
|
| 655 |
+
<div style='font-size: 13px; color: #ccc;'>
|
| 656 |
+
<div style='display: flex; justify-content: space-between; margin-bottom: 5px;'>
|
| 657 |
+
<span>⏳ وقت التشغيل منذ أول صفقة:</span>
|
| 658 |
+
<span id='system-uptime-counter' data-start-time='{first_trade_ts}' style='color: #00e5ff; font-family: monospace;'>جاري الحساب...</span>
|
| 659 |
+
</div>
|
| 660 |
+
<div style='display: flex; justify-content: space-between;'>
|
| 661 |
+
<span>⏱️ مدة الصفقة الحالية:</span>
|
| 662 |
+
<span id='trade-duration-counter' data-entry-time='{current_trade_entry_time}' style='color: {"#00ff00" if current_trade_entry_time else "#666"}; font-family: monospace;'>--:--:--</span>
|
| 663 |
+
</div>
|
| 664 |
+
</div>
|
| 665 |
+
|
| 666 |
</div>
|
| 667 |
+
{LIVE_TIMER_JS}
|
| 668 |
"""
|
| 669 |
|
| 670 |
+
# [DeepSteward IQ & History Stats] - (كاملة مع الدولار)
|
| 671 |
ds = trade_manager.ds_stats
|
| 672 |
total_ds = ds['total_exits']
|
| 673 |
ds_accuracy = (ds['good_exits'] / total_ds * 100) if total_ds > 0 else 0.0
|
| 674 |
|
|
|
|
| 675 |
history_md = f"""
|
| 676 |
<div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333;'>
|
| 677 |
<h3 style='margin-top:0; color: #888;'>📊 الأداء التاريخي</h3>
|
|
|
|
| 699 |
except Exception as e:
|
| 700 |
wallet_md = f"Error: {e}"
|
| 701 |
history_md = "Error loading stats"
|
| 702 |
+
traceback.print_exc() # طباعة الخطأ لمعرفة السبب
|
| 703 |
|
| 704 |
+
# 2. الحالة العامة (بقية الدالة كما هي تماماً)
|
| 705 |
try:
|
| 706 |
status_text = sys_state.last_cycle_logs
|
| 707 |
trade_count = len(trade_manager.open_positions)
|
|
|
|
| 719 |
except Exception:
|
| 720 |
return "Error", "...", "...", "...", "...", None, empty_watchlist, wallet_md, history_md
|
| 721 |
|
| 722 |
+
# 3. التحقق من الصفقة المفتوحة (للشارت والـ PnL) (بقية الدالة كما هي تماماً)
|
| 723 |
if not trade_manager.open_positions:
|
| 724 |
return status_text, status_md, "### 💤 لا توجد صفقة مفتوحة", "---", "---", None, watchlist_df, wallet_md, history_md
|
| 725 |
|
|
|
|
| 798 |
.gradio-container { background-color: #0b0f19; }
|
| 799 |
"""
|
| 800 |
|
| 801 |
+
with gr.Blocks(title="Titan V20 Pro Dashboard", css=css, theme=gr.themes.Monochrome()) as demo:
|
| 802 |
+
gr.Markdown("# 🚀 Titan V20 Pro Trading Terminal (DeepSteward V2 + Live Timers)")
|
| 803 |
|
| 804 |
# --- الصف العلوي: الشارت + الإحصائيات الحية ---
|
| 805 |
with gr.Row():
|