Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# app.py (Fully updated to V8.
|
| 2 |
import os
|
| 3 |
import traceback
|
| 4 |
import signal
|
|
@@ -260,7 +260,7 @@ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches,
|
|
| 260 |
|
| 261 |
async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
| 262 |
"""
|
| 263 |
-
(معدل V8.
|
| 264 |
"""
|
| 265 |
layer1_candidates = []
|
| 266 |
layer2_candidates = []
|
|
@@ -334,9 +334,10 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 334 |
success_item['layer1_score'] = l1_data.get('layer1_score', 0)
|
| 335 |
|
| 336 |
success_item['whale_data'] = {'data_available': False, 'reason': 'Not fetched yet'}
|
| 337 |
-
# (V8.
|
| 338 |
success_item['news_text'] = ""
|
| 339 |
-
success_item['
|
|
|
|
| 340 |
|
| 341 |
layer2_candidates.append(success_item)
|
| 342 |
|
|
@@ -349,7 +350,7 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 349 |
|
| 350 |
final_layer2_candidates = layer2_candidates[:target_count]
|
| 351 |
|
| 352 |
-
# 🔴 --- START OF CHANGE (V8.
|
| 353 |
print(f"\n🐋📰 Layer 1.4 (Optimized): Fetching Whale Data & News for top {len(final_layer2_candidates)} candidates...")
|
| 354 |
|
| 355 |
# (دالة مساعدة لجلب الحيتان)
|
|
@@ -370,7 +371,7 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 370 |
symbol = candidate.get('symbol', 'UNKNOWN')
|
| 371 |
if not news_fetcher_global or not VADER_ANALYZER:
|
| 372 |
candidate['news_text'] = "News analysis disabled."
|
| 373 |
-
candidate['
|
| 374 |
return
|
| 375 |
|
| 376 |
try:
|
|
@@ -378,20 +379,17 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 378 |
news_text = await news_fetcher_global.get_news_for_symbol(symbol)
|
| 379 |
candidate['news_text'] = news_text
|
| 380 |
|
| 381 |
-
# 2. حساب درجة VADER
|
| 382 |
-
# (سيتم تمرير النص الكامل للـ LLM، ولكننا نستخدم الدرجة للترتيب الداخلي)
|
| 383 |
if "No specific news found" in news_text or not news_text:
|
| 384 |
-
candidate['
|
| 385 |
else:
|
| 386 |
vader_score = VADER_ANALYZER.polarity_scores(news_text)
|
| 387 |
-
candidate['
|
| 388 |
|
| 389 |
-
# print(f" ✅ [News Fetch] {symbol} - Score: {candidate['news_score']:.2f}")
|
| 390 |
-
|
| 391 |
except Exception as e:
|
| 392 |
print(f" ❌ [News Fetch] {symbol} - Error: {e}")
|
| 393 |
candidate['news_text'] = f"Error fetching news: {e}"
|
| 394 |
-
candidate['
|
| 395 |
|
| 396 |
# (تنفيذ المهام بالتوازي)
|
| 397 |
tasks = []
|
|
@@ -402,18 +400,28 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 402 |
await asyncio.gather(*tasks)
|
| 403 |
print(" ✅ Whale data and News data fetched for top candidates.")
|
| 404 |
|
| 405 |
-
print(" 🔄 Re-calculating enhanced scores with new Whale & News data...")
|
| 406 |
for candidate in final_layer2_candidates:
|
| 407 |
try:
|
| 408 |
-
# (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 409 |
new_score = ml_processor._calculate_enhanced_final_score(candidate)
|
| 410 |
candidate['enhanced_final_score'] = new_score
|
| 411 |
except Exception as e:
|
| 412 |
print(f" ❌ [Score Recalc] {candidate.get('symbol')} - Error: {e}")
|
| 413 |
|
| 414 |
final_layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
|
| 415 |
-
print(" ✅ Top scores updated (with News+Whale) and re-sorted.")
|
| 416 |
-
# 🔴 --- END OF CHANGE (V8.
|
| 417 |
|
| 418 |
|
| 419 |
print(f"\n🔬 Layer 1.5: Running Advanced MC (GARCH+LGBM) on top {len(final_layer2_candidates)} candidates...")
|
|
@@ -463,23 +471,9 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 463 |
|
| 464 |
candidate['sentiment_data'] = await data_manager_global.get_market_context_async()
|
| 465 |
|
| 466 |
-
# (V8.
|
| 467 |
-
#
|
| 468 |
-
|
| 469 |
-
# (يجب أن نمرر الأخبار التي جلبناها)
|
| 470 |
-
|
| 471 |
-
# (تعديل: الدالة في LLM.py تستقبل 'news_text' من الـ payload)
|
| 472 |
-
# (سير العمل الحالي في LLM.py يعتمد على NewsFetcher الداخلي)
|
| 473 |
-
|
| 474 |
-
# --- (تصحيح المنطق V8.1) ---
|
| 475 |
-
# سنعتمد على NewsFetcher الداخلي في LLMService لضمان جلب أحدث الأخبار
|
| 476 |
-
# (لكن LLM.py الحالي لا يفعل ذلك، بل يتوقعها في الـ payload)
|
| 477 |
-
# (سنقوم بتعديل بسيط هنا لضمان تمريرها)
|
| 478 |
-
|
| 479 |
-
# (سنستخدم الأخبار التي جلبناها بالفعل)
|
| 480 |
-
# (لا حاجة لاستدعاء llm_service_global.news_fetcher.get_news_for_symbol)
|
| 481 |
-
|
| 482 |
-
llm_analysis = await llm_service_global.get_trading_decision(candidate) # (candidate يحتوي 'news_text')
|
| 483 |
|
| 484 |
if llm_analysis and llm_analysis.get('action') in ['WATCH']:
|
| 485 |
strategy_to_watch = llm_analysis.get('strategy_to_watch', 'GENERIC')
|
|
@@ -550,7 +544,7 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
|
| 550 |
|
| 551 |
|
| 552 |
async def re_analyze_open_trade_async(trade_data):
|
| 553 |
-
"""(V8.
|
| 554 |
symbol = trade_data.get('symbol')
|
| 555 |
try:
|
| 556 |
async with state_manager.trade_analysis_lock:
|
|
@@ -597,8 +591,25 @@ async def re_analyze_open_trade_async(trade_data):
|
|
| 597 |
processed_data['ohlcv'] = processed_data['raw_ohlcv']
|
| 598 |
processed_data['sentiment_data'] = market_context
|
| 599 |
|
| 600 |
-
#
|
| 601 |
-
# (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
re_analysis_decision = await llm_service_global.re_analyze_trade_async(trade_data, processed_data)
|
| 603 |
|
| 604 |
if re_analysis_decision:
|
|
|
|
| 1 |
+
# app.py (Fully updated to V8.2 - Statistical VADER Scoring)
|
| 2 |
import os
|
| 3 |
import traceback
|
| 4 |
import signal
|
|
|
|
| 260 |
|
| 261 |
async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
|
| 262 |
"""
|
| 263 |
+
(معدل V8.2) - استخدام درجة الأخبار الإحصائية
|
| 264 |
"""
|
| 265 |
layer1_candidates = []
|
| 266 |
layer2_candidates = []
|
|
|
|
| 334 |
success_item['layer1_score'] = l1_data.get('layer1_score', 0)
|
| 335 |
|
| 336 |
success_item['whale_data'] = {'data_available': False, 'reason': 'Not fetched yet'}
|
| 337 |
+
# (V8.2) إضافة قيم افتراضية للأخبار
|
| 338 |
success_item['news_text'] = ""
|
| 339 |
+
success_item['news_score_raw'] = 0.0 # درجة VADER الخام
|
| 340 |
+
success_item['statistical_news_pnl'] = 0.0 # الدرجة المتعلمة
|
| 341 |
|
| 342 |
layer2_candidates.append(success_item)
|
| 343 |
|
|
|
|
| 350 |
|
| 351 |
final_layer2_candidates = layer2_candidates[:target_count]
|
| 352 |
|
| 353 |
+
# 🔴 --- START OF CHANGE (V8.2) --- 🔴
|
| 354 |
print(f"\n🐋📰 Layer 1.4 (Optimized): Fetching Whale Data & News for top {len(final_layer2_candidates)} candidates...")
|
| 355 |
|
| 356 |
# (دالة مساعدة لجلب الحيتان)
|
|
|
|
| 371 |
symbol = candidate.get('symbol', 'UNKNOWN')
|
| 372 |
if not news_fetcher_global or not VADER_ANALYZER:
|
| 373 |
candidate['news_text'] = "News analysis disabled."
|
| 374 |
+
candidate['news_score_raw'] = 0.0
|
| 375 |
return
|
| 376 |
|
| 377 |
try:
|
|
|
|
| 379 |
news_text = await news_fetcher_global.get_news_for_symbol(symbol)
|
| 380 |
candidate['news_text'] = news_text
|
| 381 |
|
| 382 |
+
# 2. حساب درجة VADER الخام
|
|
|
|
| 383 |
if "No specific news found" in news_text or not news_text:
|
| 384 |
+
candidate['news_score_raw'] = 0.0 # محايد
|
| 385 |
else:
|
| 386 |
vader_score = VADER_ANALYZER.polarity_scores(news_text)
|
| 387 |
+
candidate['news_score_raw'] = vader_score.get('compound', 0.0) # النتيجة (-1 إلى +1)
|
| 388 |
|
|
|
|
|
|
|
| 389 |
except Exception as e:
|
| 390 |
print(f" ❌ [News Fetch] {symbol} - Error: {e}")
|
| 391 |
candidate['news_text'] = f"Error fetching news: {e}"
|
| 392 |
+
candidate['news_score_raw'] = 0.0
|
| 393 |
|
| 394 |
# (تنفيذ المهام بالتوازي)
|
| 395 |
tasks = []
|
|
|
|
| 400 |
await asyncio.gather(*tasks)
|
| 401 |
print(" ✅ Whale data and News data fetched for top candidates.")
|
| 402 |
|
| 403 |
+
print(" 🔄 Re-calculating enhanced scores with new Whale & Statistical News data...")
|
| 404 |
for candidate in final_layer2_candidates:
|
| 405 |
try:
|
| 406 |
+
# (V8.2) جلب درجة VADER الخام
|
| 407 |
+
raw_vader_score = candidate.get('news_score_raw', 0.0)
|
| 408 |
+
|
| 409 |
+
# (V8.2) جلب الربح/الخسارة الإحصائي المرتبط بهذه الدرجة من محور التعلم
|
| 410 |
+
if learning_hub_global:
|
| 411 |
+
statistical_pnl = await learning_hub_global.get_statistical_news_score(raw_vader_score)
|
| 412 |
+
candidate['statistical_news_pnl'] = statistical_pnl
|
| 413 |
+
else:
|
| 414 |
+
candidate['statistical_news_pnl'] = 0.0 # (الوضع الآمن)
|
| 415 |
+
|
| 416 |
+
# (هذه الدالة في processor.py تم تعديلها لتقبل statistical_news_pnl)
|
| 417 |
new_score = ml_processor._calculate_enhanced_final_score(candidate)
|
| 418 |
candidate['enhanced_final_score'] = new_score
|
| 419 |
except Exception as e:
|
| 420 |
print(f" ❌ [Score Recalc] {candidate.get('symbol')} - Error: {e}")
|
| 421 |
|
| 422 |
final_layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
|
| 423 |
+
print(" ✅ Top scores updated (with Stat. News + Whale) and re-sorted.")
|
| 424 |
+
# 🔴 --- END OF CHANGE (V8.2) --- 🔴
|
| 425 |
|
| 426 |
|
| 427 |
print(f"\n🔬 Layer 1.5: Running Advanced MC (GARCH+LGBM) on top {len(final_layer2_candidates)} candidates...")
|
|
|
|
| 471 |
|
| 472 |
candidate['sentiment_data'] = await data_manager_global.get_market_context_async()
|
| 473 |
|
| 474 |
+
# (V8.2) النموذج الضخم سيحصل على 'news_text' (النص الخام)
|
| 475 |
+
# ولن يرى 'statistical_news_pnl' (الدرجة المتعلمة)
|
| 476 |
+
llm_analysis = await llm_service_global.get_trading_decision(candidate)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 477 |
|
| 478 |
if llm_analysis and llm_analysis.get('action') in ['WATCH']:
|
| 479 |
strategy_to_watch = llm_analysis.get('strategy_to_watch', 'GENERIC')
|
|
|
|
| 544 |
|
| 545 |
|
| 546 |
async def re_analyze_open_trade_async(trade_data):
|
| 547 |
+
"""(V8.2) إضافة جلب الأخبار ودرجة VADER لـ Reflector"""
|
| 548 |
symbol = trade_data.get('symbol')
|
| 549 |
try:
|
| 550 |
async with state_manager.trade_analysis_lock:
|
|
|
|
| 591 |
processed_data['ohlcv'] = processed_data['raw_ohlcv']
|
| 592 |
processed_data['sentiment_data'] = market_context
|
| 593 |
|
| 594 |
+
# 🔴 --- START OF CHANGE (V8.2) --- 🔴
|
| 595 |
+
# (جلب الأخبار ودرجة VADER الخام لتمريرها إلى Reflector لاحقاً)
|
| 596 |
+
if news_fetcher_global and VADER_ANALYZER:
|
| 597 |
+
try:
|
| 598 |
+
news_text = await news_fetcher_global.get_news_for_symbol(symbol)
|
| 599 |
+
processed_data['news_text'] = news_text
|
| 600 |
+
|
| 601 |
+
vader_score = VADER_ANALYZER.polarity_scores(news_text)
|
| 602 |
+
processed_data['news_score'] = vader_score.get('compound', 0.0)
|
| 603 |
+
except Exception as e:
|
| 604 |
+
print(f" ❌ [Re-Analyze News] {symbol} - Error: {e}")
|
| 605 |
+
processed_data['news_text'] = "News analysis failed."
|
| 606 |
+
processed_data['news_score'] = 0.0
|
| 607 |
+
else:
|
| 608 |
+
processed_data['news_text'] = "News analysis disabled."
|
| 609 |
+
processed_data['news_score'] = 0.0
|
| 610 |
+
# 🔴 --- END OF CHANGE --- 🔴
|
| 611 |
+
|
| 612 |
+
# (LLMService سيستخدم NewsFetcher الخاص به لجلب أحدث الأخبار لتحليلها)
|
| 613 |
re_analysis_decision = await llm_service_global.re_analyze_trade_async(trade_data, processed_data)
|
| 614 |
|
| 615 |
if re_analysis_decision:
|