File size: 21,399 Bytes
e133d58
c6f2314
 
 
 
 
 
 
41a4fac
53cf6c0
35b000d
 
53cf6c0
49edbc8
53cf6c0
8785171
53cf6c0
35b000d
63c3c5c
53cf6c0
8785171
014b082
8785171
53cf6c0
 
 
 
63c3c5c
35b000d
b4b5d30
53cf6c0
6b28865
 
 
 
 
 
 
 
 
 
 
39b726a
b4b5d30
6b28865
 
 
41a4fac
6b28865
 
 
 
 
 
 
 
 
 
 
53cf6c0
8785171
35b000d
6b28865
 
 
63c3c5c
 
53cf6c0
 
6b28865
 
 
 
 
 
 
 
 
63c3c5c
6b28865
39b726a
 
6b28865
 
 
 
 
 
 
 
 
 
53cf6c0
 
6b28865
53cf6c0
 
 
8785171
 
 
 
 
 
 
53cf6c0
8785171
63c3c5c
8785171
 
 
53cf6c0
8785171
 
 
39b726a
8785171
 
39b726a
 
8785171
39b726a
8785171
 
 
 
 
 
 
39b726a
8785171
 
53cf6c0
41a4fac
8785171
 
63c3c5c
8785171
 
 
 
 
 
 
 
 
 
63c3c5c
8785171
 
 
 
 
 
 
 
63c3c5c
8785171
 
 
41a4fac
8785171
 
63c3c5c
8785171
 
 
41a4fac
8785171
 
 
 
 
63c3c5c
8785171
53cf6c0
8785171
39b726a
8785171
 
 
 
 
 
 
 
 
 
 
 
63c3c5c
8785171
 
 
63c3c5c
8785171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53cf6c0
8785171
 
 
53cf6c0
 
 
8785171
53cf6c0
 
6b28865
8785171
 
 
63c3c5c
8785171
6b28865
 
8785171
 
 
 
 
 
 
 
6b28865
63c3c5c
8785171
 
 
6b28865
 
 
8785171
 
6b28865
63c3c5c
6b28865
 
8785171
 
63c3c5c
8785171
53cf6c0
6b28865
63c3c5c
 
 
 
 
53cf6c0
 
 
8785171
53cf6c0
6b28865
 
 
 
41a4fac
49edbc8
41a4fac
63c3c5c
41a4fac
63c3c5c
 
53cf6c0
63c3c5c
41a4fac
 
8785171
41a4fac
8785171
53cf6c0
 
63c3c5c
 
 
 
8785171
53cf6c0
41a4fac
53cf6c0
 
 
63c3c5c
53cf6c0
63c3c5c
 
8785171
 
53cf6c0
 
df544c2
41a4fac
df544c2
41a4fac
8785171
 
 
 
63c3c5c
8785171
 
 
63c3c5c
41a4fac
 
 
 
8785171
53cf6c0
 
63c3c5c
 
8785171
63c3c5c
41a4fac
8785171
53cf6c0
6b28865
63c3c5c
 
 
 
 
 
53cf6c0
 
 
8785171
 
 
6b28865
 
53cf6c0
6b28865
 
8785171
53cf6c0
6b28865
 
53cf6c0
6b28865
39b726a
 
 
 
b4b5d30
53cf6c0
6b28865
 
 
 
 
35b000d
6b28865
 
53cf6c0
014b082
6b28865
 
63c3c5c
6b28865
 
8785171
53cf6c0
63c3c5c
6b28865
49edbc8
6b28865
8785171
6b28865
53cf6c0
6b28865
53cf6c0
6b28865
63c3c5c
 
 
 
 
53cf6c0
63c3c5c
 
53cf6c0
 
 
 
 
8785171
6b28865
 
53cf6c0
8785171
53cf6c0
 
 
8785171
 
6b28865
 
 
8785171
 
 
 
 
 
53cf6c0
8785171
 
53cf6c0
8785171
 
 
 
 
 
 
 
53cf6c0
8785171
 
 
 
 
53cf6c0
8785171
 
53cf6c0
 
8785171
 
 
6b28865
 
 
 
 
 
53cf6c0
 
 
 
6b28865
 
 
63c3c5c
 
 
6b28865
 
 
 
 
 
 
 
 
 
 
 
53cf6c0
 
8785171
53cf6c0
 
 
 
 
 
63c3c5c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# 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
from learning_engine import LearningEngine
from sentiment_news import SentimentAnalyzer
from trade_manager import TradeManager
import state
from helpers import safe_float_conversion, 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 run_3_layer_analysis():
    """
    تشغيل النظام الطبقي المكون من 3 طبقات:
    الطبقة 1: data_manager - الفحص السريع
    الطبقة 2: MLProcessor - التحليل المتقدم  
    الطبقة 3: LLMService - النموذج الضخم
    """
    try:
        print("🎯 بدء النظام الطبقي المكون من 3 طبقات...")
        
        if not await state_manager.wait_for_initialization():
            print("❌ الخدمات غير مهيأة بالكامل")
            return None

        # الطبقة 1: الفحص السريع لجميع العملات
        print("\n🔍 الطبقة 1: الفحص السريع (data_manager)...")
        layer1_candidates = await data_manager_global.layer1_rapid_screening()
        
        if not layer1_candidates:
            print("❌ لم يتم العثور على مرشحين في الطبقة 1")
            return None
        
        print(f"✅ تم اختيار {len(layer1_candidates)} عملة للطبقة 2")

        # جلب بيانات OHLCV كاملة للمرشحين
        layer1_symbols = [candidate['symbol'] for candidate in layer1_candidates]
        ohlcv_data_list = await data_manager_global.get_ohlcv_data_for_symbols(layer1_symbols)
        
        if not ohlcv_data_list:
            print("❌ فشل جلب بيانات OHLCV للمرشحين")
            return None

        # الطبقة 2: التحليل المتقدم
        print("\n📈 الطبقة 2: التحليل المتقدم (MLProcessor)...")
        market_context = await data_manager_global.get_market_context_async()
        
        # إنشاء معالج ML
        ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
        
        # معالجة كل مرشح باستخدام ML
        layer2_candidates = []
        for ohlcv_data in ohlcv_data_list:
            try:
                # إضافة أسباب الترشيح من الطبقة 1
                symbol = ohlcv_data['symbol']
                layer1_candidate = next((c for c in layer1_candidates if c['symbol'] == symbol), None)
                if layer1_candidate:
                    ohlcv_data['reasons_for_candidacy'] = layer1_candidate.get('reasons', [])
                    ohlcv_data['layer1_score'] = layer1_candidate.get('layer1_score', 0)
                
                # التحليل المتقدم باستخدام ML
                analyzed_data = await ml_processor.process_and_score_symbol_enhanced(ohlcv_data)
                if analyzed_data and analyzed_data.get('enhanced_final_score', 0) > 0.4:
                    layer2_candidates.append(analyzed_data)
                    
            except Exception as e:
                print(f"❌ خطأ في تحليل {ohlcv_data.get('symbol')}: {e}")
                continue
        
        if not layer2_candidates:
            print("❌ لم يتم العثور على مرشحين في الطبقة 2")
            return None
        
        # ترتيب المرشحين حسب الدرجة المحسنة
        layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
        
        # أخذ أفضل 9-20 مرشح للطبقة 3
        target_count = min(max(9, len(layer2_candidates) // 2), 20)
        final_layer2_candidates = layer2_candidates[:target_count]
        
        print(f"✅ تم اختيار {len(final_layer2_candidates)} عملة للطبقة 3")

        # الطبقة 3: التحليل بالنموذج الضخم
        print("\n🧠 الطبقة 3: التحليل بالنموذج الضخم (LLMService)...")
        final_opportunities = []
        
        for candidate in final_layer2_candidates:
            try:
                print(f"   🤔 تحليل {candidate['symbol']} بالنموذج الضخم...")
                
                # إرسال كل عملة للنموذج الضخم على حدة
                llm_analysis = await llm_service_global.get_trading_decision(candidate)
                
                if llm_analysis and llm_analysis.get('action') in ['BUY', 'SELL']:
                    opportunity = {
                        'symbol': candidate['symbol'],
                        'current_price': candidate.get('current_price', 0),
                        'decision': llm_analysis,
                        'enhanced_score': candidate.get('enhanced_final_score', 0),
                        'llm_confidence': llm_analysis.get('confidence_level', 0),
                        'strategy': llm_analysis.get('strategy', 'GENERIC'),
                        'analysis_timestamp': datetime.now().isoformat()
                    }
                    final_opportunities.append(opportunity)
                    
                    print(f"   ✅ {candidate['symbol']}: {llm_analysis.get('action')} - ثقة: {llm_analysis.get('confidence_level', 0):.2f}")
                
            except Exception as e:
                print(f"❌ خطأ في تحليل النموذج الضخم لـ {candidate.get('symbol')}: {e}")
                continue
        
        if not final_opportunities:
            print("❌ لم يتم العثور على فرص تداول مناسبة")
            return None
        
        # ترتيب الفرص النهائية حسب الثقة والدرجة
        final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
        
        print(f"\n🏆 النظام الطبقي اكتمل: {len(final_opportunities)} فرصة تداول")
        for i, opportunity in enumerate(final_opportunities[:5]):
            print(f"   {i+1}. {opportunity['symbol']}: {opportunity['decision'].get('action')} - ثقة: {opportunity['llm_confidence']:.2f}")
        
        return final_opportunities[0] if final_opportunities else None
        
    except Exception as error:
        print(f"❌ خطأ في النظام الطبقي: {error}")
        import traceback
        traceback.print_exc()
        return None

async def re_analyze_open_trade_async(trade_data):
    """إعادة تحليل الصفقة المفتوحة"""
    symbol = trade_data.get('symbol')
    try:
        async with state_manager.trade_analysis_lock:
            # جلب البيانات الحالية
            market_context = await data_manager_global.get_market_context_async()
            ohlcv_data_list = await data_manager_global.get_ohlcv_data_for_symbols([symbol])
            
            if not ohlcv_data_list:
                return None
                
            ohlcv_data = ohlcv_data_list[0]
            ohlcv_data['reasons_for_candidacy'] = ['re-analysis']
            
            # استخدام ML للتحليل
            ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
            processed_data = await ml_processor.process_and_score_symbol_enhanced(ohlcv_data)
            
            if not processed_data:
                return None
            
            # استخدام LLM لإعادة التحليل
            re_analysis_decision = await llm_service_global.re_analyze_trade_async(trade_data, processed_data)
            
            await r2_service_global.save_system_logs_async({
                "trade_reanalyzed": True, 
                "symbol": symbol, 
                "action": re_analysis_decision.get('action'),
                "strategy": re_analysis_decision.get('strategy', 'GENERIC')
            })
            
            return {
                "symbol": symbol, 
                "decision": re_analysis_decision,
                "current_price": processed_data.get('current_price')
            }
            
    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
            
        try:
            open_trades = await trade_manager_global.get_open_trades()
            print(f"📋 الصفقات المفتوحة: {len(open_trades)}")
            
            should_look_for_new_trade = len(open_trades) == 0
            
            # إعادة تحليل الصفقات المفتوحة
            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)
                
                if current_capital > 1:
                    print("🎯 البحث عن فرص تداول جديدة...")
                    best_opportunity = await run_3_layer_analysis()
                    
                    if best_opportunity:
                        print(f"✅ فتح صفقة جديدة: {best_opportunity['symbol']}")
                        await trade_manager_global.open_trade(
                            best_opportunity['symbol'], 
                            best_opportunity['decision'], 
                            best_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) if 'open_trades' in locals() else 0
            })
            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()

@asynccontextmanager
async def lifespan(application: FastAPI):
    """إدارة دورة حياة التطبيق"""
    global r2_service_global, data_manager_global, llm_service_global, learning_engine_global
    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')

        contracts_database = await r2_service_global.load_contracts_db_async()

        from whale_news_data import EnhancedWhaleMonitor
        symbol_whale_monitor_global = EnhancedWhaleMonitor(contracts_database, r2_service_global)
        state_manager.set_service_initialized('symbol_whale_monitor')

        data_manager_global = DataManager(contracts_database, symbol_whale_monitor_global)
        await data_manager_global.initialize()
        state_manager.set_service_initialized('data_manager')

        llm_service_global = LLMService()
        state_manager.set_service_initialized('llm_service')

        sentiment_analyzer_global = SentimentAnalyzer(data_manager_global)
        state_manager.set_service_initialized('sentiment_analyzer')

        learning_engine_global = LearningEngine(r2_service_global, data_manager_global)
        await learning_engine_global.initialize_enhanced()
        state_manager.set_service_initialized('learning_engine')

        trade_manager_global = TradeManager(r2_service_global, learning_engine_global, data_manager_global)
        state_manager.set_service_initialized('trade_manager')

        # بدء المهام الخلفية
        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("🎯 التطبيق جاهز للعمل - نظام الطبقات 3 فعال")
        
        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)

@application.get("/run-cycle")
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", "system": "3-Layer Analysis"}

@application.get("/health")
async def health_check():
    """فحص صحة النظام"""
    services_status = {
        "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(),
        "system_architecture": "3-Layer Analysis System",
        "layers": {
            "layer1": "Data Manager - Rapid Screening",
            "layer2": "ML Processor - Advanced Analysis", 
            "layer3": "LLM Service - Deep Analysis"
        }
    }
    return services_status

@application.get("/analyze-market")
async def analyze_market_api():
    """تشغيل التحليل الطبقي فقط"""
    if not state_manager.initialization_complete:
        raise HTTPException(status_code=503, detail="الخدمات غير مهيأة بالكامل")
    
    result = await run_3_layer_analysis()
    if result:
        return {
            "opportunity_found": True,
            "symbol": result['symbol'],
            "action": result['decision'].get('action'),
            "confidence": result['llm_confidence'],
            "strategy": result['strategy']
        }
    else:
        return {"opportunity_found": False, "message": "No suitable opportunities found"}

async def cleanup_on_shutdown():
    """تنظيف الموارد عند الإغلاق"""
    global r2_service_global, data_manager_global, trade_manager_global, learning_engine_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 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)