Spaces:
Running
Running
| # app.py | |
| import os | |
| import traceback | |
| import signal | |
| import sys | |
| import uvicorn | |
| import asyncio | |
| import json | |
| import time | |
| from contextlib import asynccontextmanager | |
| from fastapi import FastAPI, HTTPException | |
| from datetime import datetime | |
| from r2 import R2Service | |
| from LLM import LLMService | |
| from data_manager import DataManager | |
| from ML import MLProcessor as FeatureProcessor | |
| from learning_engine import LearningEngine | |
| from sentiment_news import SentimentAnalyzer | |
| from trade_manager import TradeManager | |
| import state | |
| from helpers import safe_float_conversion, _apply_patience_logic, local_analyze_opportunity, local_re_analyze_trade, validate_candidate_data_enhanced | |
| r2_service_global = None | |
| data_manager_global = None | |
| llm_service_global = None | |
| learning_engine_global = None | |
| trade_manager_global = None | |
| sentiment_analyzer_global = None | |
| symbol_whale_monitor_global = None | |
| class StateManager: | |
| def __init__(self): | |
| self.market_analysis_lock = asyncio.Lock() | |
| self.trade_analysis_lock = asyncio.Lock() | |
| self.initialization_complete = False | |
| self.services_initialized = { | |
| 'r2_service': False, | |
| 'data_manager': False, | |
| 'llm_service': False, | |
| 'learning_engine': False, | |
| 'trade_manager': False, | |
| 'sentiment_analyzer': False, | |
| 'symbol_whale_monitor': False | |
| } | |
| async def wait_for_initialization(self, timeout=30): | |
| start_time = time.time() | |
| while not self.initialization_complete and (time.time() - start_time) < timeout: | |
| await asyncio.sleep(1) | |
| return self.initialization_complete | |
| def set_service_initialized(self, service_name): | |
| self.services_initialized[service_name] = True | |
| if all(self.services_initialized.values()): | |
| self.initialization_complete = True | |
| state_manager = StateManager() | |
| async def monitor_market_async(): | |
| """مراقبة السوق بدون نظام الحيتان العام""" | |
| global data_manager_global, sentiment_analyzer_global | |
| if not await state_manager.wait_for_initialization(): | |
| print("❌ فشل تهيئة الخدمات - إيقاف مراقبة السوق") | |
| return | |
| while True: | |
| try: | |
| async with state_manager.market_analysis_lock: | |
| market_context = await sentiment_analyzer_global.get_market_sentiment() | |
| if not market_context: | |
| state.MARKET_STATE_OK = True | |
| await asyncio.sleep(60) | |
| continue | |
| bitcoin_sentiment = market_context.get('btc_sentiment') | |
| fear_greed_index = market_context.get('fear_and_greed_index') | |
| should_halt_trading, halt_reason = False, "" | |
| if bitcoin_sentiment == 'BEARISH' and (fear_greed_index is not None and fear_greed_index < 30): | |
| should_halt_trading, halt_reason = True, "ظروف سوق هابطة" | |
| if should_halt_trading: | |
| state.MARKET_STATE_OK = False | |
| await r2_service_global.save_system_logs_async({"market_halt": True, "reason": halt_reason}) | |
| else: | |
| if not state.MARKET_STATE_OK: | |
| print("✅ تحسنت ظروف السوق. استئناف العمليات العادية.") | |
| state.MARKET_STATE_OK = True | |
| await asyncio.sleep(60) | |
| except Exception as error: | |
| print(f"❌ خطأ أثناء مراقبة السوق: {error}") | |
| state.MARKET_STATE_OK = True | |
| await asyncio.sleep(60) | |
| async def analyze_market_strategy(market_context): | |
| """تحليل استراتيجية السوق بدون اعتماد على الحيتان العامة""" | |
| try: | |
| prompt = f"Analyze current market conditions and determine trading strategy.\n\nMarket Data:\n- BTC Sentiment: {market_context.get('btc_sentiment')}\n- Fear & Greed Index: {market_context.get('fear_and_greed_index')}\n\nOutput JSON:\n{{\"primary_strategy\": \"STRATEGY_NAME\",\"reasoning\": \"Brief reasoning\",\"risk_tolerance\": 5,\"optimal_scan_count\": 100}}" | |
| response = await llm_service_global._call_llm(prompt) | |
| try: | |
| from helpers import parse_json_from_response | |
| json_str = parse_json_from_response(response) | |
| strategy_data = json.loads(json_str) | |
| except: | |
| strategy_data = { | |
| "primary_strategy": "GENERIC", | |
| "reasoning": "Fallback strategy due to analysis error", | |
| "risk_tolerance": 5, | |
| "optimal_scan_count": 100 | |
| } | |
| return strategy_data | |
| except Exception as error: | |
| print(f"❌ فشل تحليل استراتيجية السوق: {error}") | |
| return { | |
| "primary_strategy": "GENERIC", | |
| "reasoning": "Fallback due to analysis error", | |
| "risk_tolerance": 5, | |
| "optimal_scan_count": 100 | |
| } | |
| async def find_strategy_specific_candidates(strategy, scan_count): | |
| """البحث عن مرشحين متوافقين مع الاستراتيجية""" | |
| try: | |
| all_candidates = await data_manager_global.find_high_potential_candidates(scan_count * 2) | |
| if not all_candidates: | |
| return [] | |
| market_context = await data_manager_global.get_market_context_async() | |
| if not market_context: | |
| return [] | |
| feature_processor = FeatureProcessor(market_context, data_manager_global, learning_engine_global) | |
| processed_candidates = [] | |
| for candidate in all_candidates[:30]: | |
| try: | |
| symbol_with_reasons = [{'symbol': candidate['symbol'], 'reasons': candidate.get('reasons', [])}] | |
| ohlcv_data = await data_manager_global.get_fast_pass_data_async(symbol_with_reasons) | |
| if ohlcv_data and ohlcv_data[0]: | |
| processed = await feature_processor.process_and_score_symbol_enhanced(ohlcv_data[0]) | |
| if processed: | |
| processed_candidates.append(processed) | |
| except Exception as e: | |
| print(f"❌ Failed to process {candidate.get('symbol')}: {e}") | |
| if not processed_candidates: | |
| return [] | |
| if strategy != 'GENERIC': | |
| strategy_candidates = [] | |
| for candidate in processed_candidates: | |
| base_scores = candidate.get('base_strategy_scores', {}) | |
| strategy_score = base_scores.get(strategy, 0) | |
| if strategy_score > 0.2: | |
| candidate['strategy_match_score'] = strategy_score | |
| strategy_candidates.append(candidate) | |
| sorted_candidates = sorted(strategy_candidates, key=lambda x: x.get('strategy_match_score', 0), reverse=True) | |
| top_candidates = sorted_candidates[:15] | |
| else: | |
| sorted_candidates = sorted(processed_candidates, key=lambda x: x.get('enhanced_final_score', 0), reverse=True) | |
| top_candidates = sorted_candidates[:15] | |
| return top_candidates | |
| except Exception as error: | |
| print(f"❌ Advanced filtering failed: {error}") | |
| return [] | |
| async def enhanced_llm_analysis_with_whale_data(candidate): | |
| """تحليل محسن يشمل بيانات حيتان للمرشحين النهائيين""" | |
| global symbol_whale_monitor_global | |
| try: | |
| print(f"🧠 بدء التحليل المتقدم لـ {candidate['symbol']}...") | |
| # 1. الحصول على تحليل النموذج الضخم الأساسي | |
| llm_analysis = await llm_service_global.get_trading_decision(candidate) | |
| if not llm_analysis: | |
| print(f"❌ فشل التحليل الأساسي لـ {candidate['symbol']}") | |
| return None | |
| # 2. إضافة بيانات الحيتان للمرشحين النهائيين فقط | |
| print(f"🐋 جلب بيانات الحيتان لـ {candidate['symbol']}...") | |
| whale_analysis = await symbol_whale_monitor_global.get_symbol_whale_activity( | |
| candidate['symbol'], | |
| candidate.get('contract_address') | |
| ) | |
| # 3. دمج النتائج | |
| enhanced_analysis = { | |
| **llm_analysis, | |
| 'whale_analysis': whale_analysis.get('llm_friendly_summary', {}), | |
| 'combined_confidence': await calculate_combined_confidence( | |
| llm_analysis.get('confidence_level', 0.5), | |
| whale_analysis.get('trading_signal', {}).get('confidence', 0.5) | |
| ), | |
| 'analysis_timestamp': datetime.now().isoformat(), | |
| 'analysis_source': 'enhanced_with_whale_data' | |
| } | |
| # 4. تطبيق قواعد السلامة بناء على نشاط الحيتان | |
| if whale_analysis.get('trading_signal', {}).get('critical_alert'): | |
| enhanced_analysis = apply_whale_safety_filters(enhanced_analysis, whale_analysis) | |
| print(f"✅ اكتمل التحليل المتقدم لـ {candidate['symbol']}") | |
| return enhanced_analysis | |
| except Exception as error: | |
| print(f"❌ خطأ في التحليل المتقدم لـ {candidate.get('symbol')}: {error}") | |
| # العودة للتحليل الأساسي في حالة الخطأ | |
| return await llm_service_global.get_trading_decision(candidate) | |
| async def calculate_combined_confidence(llm_confidence, whale_confidence): | |
| """حساب الثقة المجمعة مع إعطاء وزن أكبر لبيانات الحيتان""" | |
| combined = (llm_confidence * 0.4) + (whale_confidence * 0.6) | |
| return min(combined, 0.95) | |
| def apply_whale_safety_filters(analysis, whale_analysis): | |
| """تطبيق فلاتر السلامة بناء على نشاط الحيتان الحرج""" | |
| whale_signal = whale_analysis.get('trading_signal', {}) | |
| if whale_signal.get('action') in ['STRONG_SELL', 'SELL']: | |
| if analysis.get('action') == 'BUY': | |
| analysis.update({ | |
| 'action': 'HOLD', | |
| 'reasoning': f"{analysis.get('reasoning', '')} | تصحيح بسبب نشاط الحيتان: {whale_signal.get('reason', '')}", | |
| 'confidence_level': analysis.get('confidence_level', 0.5) * 0.7 | |
| }) | |
| elif analysis.get('action') == 'HOLD': | |
| analysis['confidence_level'] = analysis.get('confidence_level', 0.5) * 0.9 | |
| elif whale_signal.get('action') in ['STRONG_BUY', 'BUY']: | |
| if analysis.get('action') == 'BUY': | |
| analysis['confidence_level'] = min(analysis.get('confidence_level', 0.5) * 1.2, 0.95) | |
| analysis['reasoning'] = f"{analysis.get('reasoning', '')} | تعزيز بسبب نشاط الحيتان الإيجابي" | |
| return analysis | |
| async def find_new_opportunities_async(): | |
| """البحث عن فرص تداول جديدة مع دمج بيانات الحيتان للمرشحين النهائيين""" | |
| try: | |
| print("🎯 بدء البحث عن فرص تداول جديدة...") | |
| await r2_service_global.save_system_logs_async({"opportunity_scan_started": True}) | |
| market_context = await data_manager_global.get_market_context_async() | |
| if not market_context: | |
| print("❌ فشل جلب سياق السوق") | |
| return | |
| strategy_decision = await analyze_market_strategy(market_context) | |
| print(f"📊 استراتيجية السوق: {strategy_decision['primary_strategy']}") | |
| high_potential_candidates = await find_strategy_specific_candidates( | |
| strategy_decision['primary_strategy'], | |
| strategy_decision.get('optimal_scan_count', 100) | |
| ) | |
| if not high_potential_candidates: | |
| print("⚠️ لم يتم العثور على مرشحين متوافقين مع الاستراتيجية، البحث عن مرشحين عامين") | |
| high_potential_candidates = await data_manager_global.find_high_potential_candidates(20) | |
| if high_potential_candidates: | |
| for candidate in high_potential_candidates: | |
| candidate['target_strategy'] = 'GENERIC' | |
| else: | |
| print("❌ لم يتم العثور على أي مرشحين") | |
| return | |
| print(f"✅ تم العثور على {len(high_potential_candidates)} مرشح محتمل") | |
| all_processed_candidates = [] | |
| CHUNK_SIZE = 5 | |
| for index in range(0, len(high_potential_candidates), CHUNK_SIZE): | |
| chunk = high_potential_candidates[index:index+CHUNK_SIZE] | |
| print(f"🔍 معالجة مجموعة {index//CHUNK_SIZE + 1} من {len(high_potential_candidates)//CHUNK_SIZE + 1}") | |
| chunk_data = await data_manager_global.get_fast_pass_data_async(chunk) | |
| updated_market_context = await data_manager_global.get_market_context_async() | |
| if not updated_market_context: | |
| updated_market_context = market_context | |
| feature_processor = FeatureProcessor(updated_market_context, data_manager_global, learning_engine_global) | |
| processed_chunk = await asyncio.gather(*[ | |
| feature_processor.process_and_score_symbol_enhanced(data) for data in chunk_data | |
| ]) | |
| all_processed_candidates.extend([c for c in processed_chunk if c is not None]) | |
| print(f"✅ تم معالجة {len([c for c in processed_chunk if c is not None])} مرشح في هذه المجموعة") | |
| await asyncio.sleep(1) | |
| if not all_processed_candidates: | |
| print("❌ فشل معالجة أي مرشح") | |
| return | |
| print(f"📊 إجمالي المرشحين المعالجين: {len(all_processed_candidates)}") | |
| updated_market_context = await data_manager_global.get_market_context_async() | |
| if not updated_market_context: | |
| updated_market_context = market_context | |
| feature_processor = FeatureProcessor(updated_market_context, data_manager_global, learning_engine_global) | |
| OPPORTUNITY_COUNT = 10 | |
| top_candidates = feature_processor.filter_top_candidates(all_processed_candidates, OPPORTUNITY_COUNT) | |
| print(f"🎖️ أفضل {len(top_candidates)} مرشح:") | |
| for i, candidate in enumerate(top_candidates): | |
| score = candidate.get('enhanced_final_score', 0) | |
| print(f" {i+1}. {candidate['symbol']}: {score:.3f}") | |
| await r2_service_global.save_candidates_data_async( | |
| candidates_data=top_candidates, | |
| reanalysis_data={ | |
| "strategy_used": strategy_decision, | |
| "market_conditions": market_context | |
| } | |
| ) | |
| if not top_candidates: | |
| print("❌ لا توجد مرشحات نهائية") | |
| return | |
| print("🤖 بدء تحليل النموذج الضخم المحسن للمرشحين...") | |
| for candidate in top_candidates: | |
| try: | |
| if not validate_candidate_data_enhanced(candidate): | |
| print(f"⚠️ تخطي {candidate['symbol']} - بيانات غير صالحة") | |
| continue | |
| print(f"🧠 تحليل متقدم لـ {candidate['symbol']}...") | |
| # استخدام التحليل المحسن ببيانات الحيتان | |
| llm_analysis_data = await enhanced_llm_analysis_with_whale_data(candidate) | |
| if not llm_analysis_data: | |
| print(f"⚠️ فشل التحليل المتقدم لـ {candidate['symbol']}") | |
| continue | |
| if llm_analysis_data.get('action') == "HOLD": | |
| print(f"⏸️ النموذج يوصي بالانتظار لـ {candidate['symbol']}") | |
| continue | |
| if llm_analysis_data.get('action') in ["BUY", "SELL"]: | |
| final_strategy = llm_analysis_data.get('strategy') | |
| candidate_strategy = candidate.get('target_strategy', 'GENERIC') | |
| if not final_strategy or final_strategy == 'unknown': | |
| final_strategy = candidate_strategy | |
| llm_analysis_data['strategy'] = final_strategy | |
| await r2_service_global.save_system_logs_async({ | |
| "new_opportunity_found": True, | |
| "symbol": candidate['symbol'], | |
| "action": llm_analysis_data.get('action'), | |
| "strategy": final_strategy, | |
| "with_whale_analysis": True, | |
| "combined_confidence": llm_analysis_data.get('combined_confidence', 0.5) | |
| }) | |
| print(f"🎯 فرصة تداول مثبتة: {candidate['symbol']} - {llm_analysis_data.get('action')} - {final_strategy}") | |
| print(f" 📊 الثقة المجمعة: {llm_analysis_data.get('combined_confidence', 0.5):.2f}") | |
| return { | |
| "symbol": candidate['symbol'], | |
| "decision": llm_analysis_data, | |
| "current_price": candidate['current_price'], | |
| "strategy": final_strategy | |
| } | |
| except Exception as error: | |
| print(f"❌ خطأ في التحليل المتقدم لـ {candidate.get('symbol', 'unknown')}: {error}") | |
| continue | |
| print("❌ لم يتم العثور على فرص تداول مناسبة") | |
| return None | |
| except Exception as error: | |
| print(f"❌ Error while scanning for opportunities: {error}") | |
| await r2_service_global.save_system_logs_async({ | |
| "opportunity_scan_error": True, | |
| "error": str(error) | |
| }) | |
| return None | |
| async def re_analyze_open_trade_async(trade_data): | |
| symbol = trade_data.get('symbol') | |
| try: | |
| async with state_manager.trade_analysis_lock: | |
| entry_time = datetime.fromisoformat(trade_data['entry_timestamp']) | |
| current_time = datetime.now() | |
| hold_minutes = (current_time - entry_time).total_seconds() / 60 | |
| original_strategy = trade_data.get('strategy') | |
| if not original_strategy or original_strategy == 'unknown': | |
| original_strategy = trade_data.get('decision_data', {}).get('strategy', 'GENERIC') | |
| try: | |
| market_context = await data_manager_global.get_market_context_async() | |
| except Exception: | |
| market_context = {'btc_sentiment': 'NEUTRAL'} | |
| symbol_with_reasons = [{'symbol': symbol, 'reasons': ['re-analysis']}] | |
| ohlcv_data_list = await data_manager_global.get_fast_pass_data_async(symbol_with_reasons) | |
| if not ohlcv_data_list: | |
| return None | |
| raw_data = ohlcv_data_list[0] | |
| try: | |
| updated_market_context = await data_manager_global.get_market_context_async() | |
| if updated_market_context: | |
| market_context = updated_market_context | |
| except Exception: | |
| pass | |
| feature_processor = FeatureProcessor(market_context, data_manager_global, learning_engine_global) | |
| processed_data = await feature_processor.process_and_score_symbol(raw_data) | |
| if not processed_data: | |
| return None | |
| await r2_service_global.save_candidates_data_async( | |
| candidates_data=None, | |
| reanalysis_data={ | |
| 'market_context': market_context, | |
| 'processed_data': processed_data | |
| } | |
| ) | |
| try: | |
| re_analysis_decision = await llm_service_global.re_analyze_trade_async(trade_data, processed_data) | |
| except Exception: | |
| re_analysis_decision = local_re_analyze_trade(trade_data, processed_data) | |
| final_decision = _apply_patience_logic(re_analysis_decision, hold_minutes, trade_data, processed_data) | |
| if not final_decision.get('strategy'): | |
| final_decision['strategy'] = original_strategy | |
| await r2_service_global.save_system_logs_async({ | |
| "trade_reanalyzed": True, | |
| "symbol": symbol, | |
| "action": final_decision.get('action'), | |
| "hold_minutes": hold_minutes, | |
| "strategy": final_decision.get('strategy') | |
| }) | |
| return { | |
| "symbol": symbol, | |
| "decision": final_decision, | |
| "current_price": processed_data.get('current_price'), | |
| "hold_minutes": hold_minutes | |
| } | |
| except Exception as error: | |
| print(f"❌ Error during trade re-analysis: {error}") | |
| await r2_service_global.save_system_logs_async({ | |
| "reanalysis_error": True, | |
| "symbol": symbol, | |
| "error": str(error) | |
| }) | |
| return None | |
| async def run_bot_cycle_async(): | |
| try: | |
| if not await state_manager.wait_for_initialization(): | |
| print("❌ الخدمات غير مهيأة بالكامل - تخطي الدورة") | |
| return | |
| print("🔄 بدء دورة التداول...") | |
| await r2_service_global.save_system_logs_async({"cycle_started": True}) | |
| if not r2_service_global.acquire_lock(): | |
| print("❌ فشل الحصول على القفل - تخطي الدورة") | |
| return | |
| open_trades = [] | |
| try: | |
| open_trades = await trade_manager_global.get_open_trades() | |
| print(f"📋 الصفقات المفتوحة: {len(open_trades)}") | |
| trades_fixed = 0 | |
| for trade in open_trades: | |
| if not trade.get('strategy') or trade['strategy'] == 'unknown': | |
| original_strategy = trade.get('decision_data', {}).get('strategy', 'GENERIC') | |
| trade['strategy'] = original_strategy | |
| trades_fixed += 1 | |
| if trades_fixed > 0: | |
| await r2_service_global.save_open_trades_async(open_trades) | |
| print(f"✅ تم إصلاح {trades_fixed} صفقة") | |
| should_look_for_new_trade = not open_trades | |
| print(f"🔍 البحث عن صفقات جديدة: {should_look_for_new_trade}") | |
| if open_trades: | |
| now = datetime.now() | |
| trades_to_reanalyze = [ | |
| trade for trade in open_trades | |
| if now >= datetime.fromisoformat(trade.get('expected_target_time', now.isoformat())) | |
| ] | |
| if trades_to_reanalyze: | |
| print(f"🔄 إعادة تحليل {len(trades_to_reanalyze)} صفقة") | |
| for trade in trades_to_reanalyze: | |
| result = await re_analyze_open_trade_async(trade) | |
| if result and result['decision'].get('action') == "CLOSE_TRADE": | |
| await trade_manager_global.close_trade(trade, result['current_price'], 'CLOSED_BY_REANALYSIS') | |
| should_look_for_new_trade = True | |
| elif result and result['decision'].get('action') == "UPDATE_TRADE": | |
| await trade_manager_global.update_trade(trade, result['decision']) | |
| if should_look_for_new_trade: | |
| portfolio_state = await r2_service_global.get_portfolio_state_async() | |
| current_capital = portfolio_state.get("current_capital_usd", 0) | |
| print(f"💰 رأس المال المتاح: ${current_capital:.2f}") | |
| if current_capital <= 0: | |
| if len(open_trades) == 0: | |
| initial_capital = portfolio_state.get("initial_capital_usd", 10.0) | |
| if initial_capital > 0: | |
| portfolio_state["current_capital_usd"] = initial_capital | |
| portfolio_state["invested_capital_usd"] = 0.0 | |
| await r2_service_global.save_portfolio_state_async(portfolio_state) | |
| current_capital = initial_capital | |
| print(f"🔄 إعادة تعيين رأس المال إلى ${initial_capital:.2f}") | |
| if current_capital > 1: | |
| print("🎯 البحث عن فرص تداول جديدة...") | |
| new_opportunity = await find_new_opportunities_async() | |
| if new_opportunity: | |
| if not new_opportunity['decision'].get('strategy'): | |
| new_opportunity['decision']['strategy'] = new_opportunity.get('strategy', 'GENERIC') | |
| print(f"✅ فتح صفقة جديدة: {new_opportunity['symbol']}") | |
| await trade_manager_global.open_trade( | |
| new_opportunity['symbol'], | |
| new_opportunity['decision'], | |
| new_opportunity['current_price'] | |
| ) | |
| else: | |
| print("❌ لم يتم العثور على فرص تداول مناسبة") | |
| else: | |
| print("❌ رأس المال غير كافي لفتح صفقات جديدة") | |
| finally: | |
| r2_service_global.release_lock() | |
| await r2_service_global.save_system_logs_async({ | |
| "cycle_completed": True, | |
| "open_trades": len(open_trades) | |
| }) | |
| print("✅ اكتملت دورة التداول") | |
| except Exception as error: | |
| print(f"❌ Unhandled error in main cycle: {error}") | |
| await r2_service_global.save_system_logs_async({ | |
| "cycle_error": True, | |
| "error": str(error) | |
| }) | |
| if r2_service_global.lock_acquired: | |
| r2_service_global.release_lock() | |
| async def lifespan(application: FastAPI): | |
| global r2_service_global, data_manager_global, llm_service_global, learning_engine_global, trade_manager_global, sentiment_analyzer_global, symbol_whale_monitor_global | |
| initialization_successful = False | |
| try: | |
| print("🚀 بدء تهيئة التطبيق...") | |
| r2_service_global = R2Service() | |
| state_manager.set_service_initialized('r2_service') | |
| print("✅ R2 Service initialized") | |
| contracts_database = await r2_service_global.load_contracts_db_async() | |
| print("✅ Contracts database loaded") | |
| from whale_news_data import EnhancedWhaleMonitor | |
| symbol_whale_monitor_global = EnhancedWhaleMonitor(contracts_database, r2_service_global) | |
| state_manager.set_service_initialized('symbol_whale_monitor') | |
| print("✅ Symbol Specific Whale Monitor initialized") | |
| data_manager_global = DataManager(contracts_database, symbol_whale_monitor_global) | |
| await data_manager_global.initialize() | |
| state_manager.set_service_initialized('data_manager') | |
| print("✅ Data Manager initialized") | |
| llm_service_global = LLMService() | |
| state_manager.set_service_initialized('llm_service') | |
| print("✅ LLM Service initialized") | |
| sentiment_analyzer_global = SentimentAnalyzer(data_manager_global) | |
| state_manager.set_service_initialized('sentiment_analyzer') | |
| print("✅ Sentiment Analyzer initialized") | |
| learning_engine_global = LearningEngine(r2_service_global, data_manager_global) | |
| await learning_engine_global.initialize_enhanced() | |
| await learning_engine_global.force_strategy_learning() | |
| state_manager.set_service_initialized('learning_engine') | |
| print("✅ Learning Engine initialized") | |
| trade_manager_global = TradeManager(r2_service_global, learning_engine_global, data_manager_global) | |
| state_manager.set_service_initialized('trade_manager') | |
| print("✅ Trade Manager initialized") | |
| asyncio.create_task(monitor_market_async()) | |
| asyncio.create_task(trade_manager_global.start_trade_monitoring()) | |
| await r2_service_global.save_system_logs_async({"application_started": True}) | |
| initialization_successful = True | |
| print("🎯 التطبيق جاهز للعمل") | |
| yield | |
| except Exception as error: | |
| print(f"❌ Application startup failed: {error}") | |
| if r2_service_global: | |
| await r2_service_global.save_system_logs_async({ | |
| "application_startup_failed": True, | |
| "error": str(error) | |
| }) | |
| raise | |
| finally: | |
| await cleanup_on_shutdown() | |
| application = FastAPI(lifespan=lifespan) | |
| async def run_cycle_api(): | |
| if not state_manager.initialization_complete: | |
| raise HTTPException(status_code=503, detail="الخدمات غير مهيأة بالكامل") | |
| asyncio.create_task(run_bot_cycle_async()) | |
| return {"message": "Bot cycle initiated"} | |
| async def health_check(): | |
| learning_metrics = {} | |
| if learning_engine_global and learning_engine_global.initialized: | |
| learning_metrics = await learning_engine_global.calculate_performance_metrics() | |
| api_stats = {} | |
| if data_manager_global: | |
| api_stats = data_manager_global.get_performance_stats() | |
| return { | |
| "status": "healthy" if state_manager.initialization_complete else "initializing", | |
| "initialization_complete": state_manager.initialization_complete, | |
| "services_initialized": state_manager.services_initialized, | |
| "timestamp": datetime.now().isoformat(), | |
| "services": { | |
| "r2_service": "initialized" if r2_service_global else "uninitialized", | |
| "llm_service": "initialized" if llm_service_global else "uninitialized", | |
| "data_manager": "initialized" if data_manager_global else "uninitialized", | |
| "learning_engine": "active" if learning_engine_global and learning_engine_global.initialized else "inactive", | |
| "trade_manager": "active" if trade_manager_global else "inactive", | |
| "symbol_whale_monitor": "active" if symbol_whale_monitor_global else "inactive" | |
| }, | |
| "market_state_ok": state.MARKET_STATE_OK, | |
| "learning_engine": learning_metrics | |
| } | |
| async def get_performance_stats(): | |
| try: | |
| if not state_manager.initialization_complete: | |
| raise HTTPException(status_code=503, detail="الخدمات غير مهيأة بالكامل") | |
| market_context = await data_manager_global.get_market_context_async() if data_manager_global else {} | |
| learning_stats = {} | |
| if learning_engine_global and learning_engine_global.initialized: | |
| learning_stats = await learning_engine_global.calculate_performance_metrics() | |
| api_stats = {} | |
| if data_manager_global: | |
| api_stats = data_manager_global.get_performance_stats() | |
| stats = { | |
| "timestamp": datetime.now().isoformat(), | |
| "data_manager": api_stats, | |
| "market_state": { | |
| "is_healthy": state.MARKET_STATE_OK, | |
| "context": market_context | |
| }, | |
| "trade_monitoring": { | |
| "active_trades": len(trade_manager_global.monitoring_tasks) if trade_manager_global else 0, | |
| "is_running": trade_manager_global.is_running if trade_manager_global else False | |
| }, | |
| "learning_engine": learning_stats, | |
| "whale_monitoring": { | |
| "symbol_specific_active": symbol_whale_monitor_global is not None, | |
| "monitoring_type": "TARGETED_NETWORK_ONLY" | |
| } | |
| } | |
| return stats | |
| except Exception as error: | |
| raise HTTPException(status_code=500, detail=f"Failed to retrieve stats: {str(error)}") | |
| async def get_logs_status(): | |
| try: | |
| open_trades = await r2_service_global.get_open_trades_async() | |
| portfolio_state = await r2_service_global.get_portfolio_state_async() | |
| return { | |
| "logging_system": "active", | |
| "open_trades_count": len(open_trades), | |
| "current_capital": portfolio_state.get("current_capital_usd", 0), | |
| "total_trades": portfolio_state.get("total_trades", 0), | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| except Exception as error: | |
| raise HTTPException(status_code=500, detail=f"Failed to get logs status: {str(error)}") | |
| async def cleanup_on_shutdown(): | |
| global r2_service_global, data_manager_global, trade_manager_global, learning_engine_global, symbol_whale_monitor_global | |
| print("🛑 Shutdown signal received. Cleaning up...") | |
| if trade_manager_global: | |
| trade_manager_global.stop_monitoring() | |
| print("✅ Trade monitoring stopped") | |
| if learning_engine_global and learning_engine_global.initialized: | |
| try: | |
| await learning_engine_global.save_weights_to_r2() | |
| await learning_engine_global.save_performance_history() | |
| print("✅ Learning engine data saved") | |
| except Exception as e: | |
| print(f"❌ Failed to save learning engine data: {e}") | |
| if data_manager_global: | |
| await data_manager_global.close() | |
| print("✅ Data manager closed") | |
| if symbol_whale_monitor_global: | |
| await symbol_whale_monitor_global.cleanup() | |
| print("✅ Symbol whale monitor cleaned up") | |
| if r2_service_global: | |
| try: | |
| await r2_service_global.save_system_logs_async({"application_shutdown": True}) | |
| print("✅ Shutdown log saved") | |
| except Exception as e: | |
| print(f"❌ Failed to save shutdown log: {e}") | |
| if r2_service_global.lock_acquired: | |
| r2_service_global.release_lock() | |
| print("✅ R2 lock released") | |
| def signal_handler(signum, frame): | |
| asyncio.create_task(cleanup_on_shutdown()) | |
| sys.exit(0) | |
| signal.signal(signal.SIGINT, signal_handler) | |
| signal.signal(signal.SIGTERM, signal_handler) | |
| if __name__ == "__main__": | |
| uvicorn.run(application, host="0.0.0.0", port=7860) |