ckharche commited on
Commit
0342bed
·
verified ·
1 Parent(s): 7706725

Update trade_analysis/enhanced_api.py

Browse files
Files changed (1) hide show
  1. trade_analysis/enhanced_api.py +593 -598
trade_analysis/enhanced_api.py CHANGED
@@ -1,599 +1,594 @@
1
- # trade_analysis/enhanced_api.py
2
-
3
- import os
4
- from fastapi import FastAPI, Query, HTTPException
5
- from pydantic import BaseModel
6
- import httpx
7
- from typing import Dict, Any, List
8
- import pandas as pd
9
- import numpy as np
10
- import asyncio
11
- from datetime import datetime
12
- from pathlib import Path
13
-
14
- # Import only modules that still exist
15
- from .data import UnifiedDataProvider
16
- from .indicators import enrich_with_indicators, identify_current_setup
17
- from .enhanced_sentiment import EnhancedFinancialSentimentAnalyzer, analyze_momentum_sentiment
18
- from .momentum_trading_engine import IntegratedMomentumEngine
19
- from .enhanced_llm import EnhancedLLMEngine, generate_enhanced_llm_signal
20
- from .tft_model import GapPredictionTFT
21
- from .agent import TradingAgent, analyze_agent_performance
22
-
23
- # Global dictionary to store TFT models
24
- api_tft_models = {}
25
- trading_agent = None
26
-
27
- def sanitize_for_json(data: any) -> any:
28
- """Recursively converts numpy and pandas types to JSON-serializable types."""
29
- if isinstance(data, dict):
30
- return {key: sanitize_for_json(value) for key, value in data.items()}
31
- elif isinstance(data, list):
32
- return [sanitize_for_json(item) for item in data]
33
- elif isinstance(data, np.bool_):
34
- return bool(data)
35
- elif isinstance(data, (np.integer, np.int64)):
36
- return int(data)
37
- elif isinstance(data, np.floating):
38
- return float(data)
39
- elif isinstance(data, pd.Timestamp):
40
- return data.isoformat()
41
- elif isinstance(data, (pd.Series, pd.Index, np.ndarray)):
42
- return data.tolist()
43
- return data
44
-
45
- class EnhancedSignalResponse(BaseModel):
46
- """Enhanced response model with momentum and LLM analysis"""
47
- symbol: str
48
- signal: str
49
- confidence: float
50
- reasoning: str
51
- position_size: float
52
- status: str
53
- details: Dict[str, Any]
54
-
55
- # Enhanced fields
56
- momentum_analysis: Dict[str, Any] = {}
57
- llm_ensemble: Dict[str, Any] = {}
58
- options_strategy: Dict[str, Any] = {}
59
- timeframe_recommendation: str = "15m"
60
- expected_hold_time: str = "Unknown"
61
-
62
- # Enhanced FastAPI App
63
- app = FastAPI(
64
- title="Enhanced Intraday Momentum Engine",
65
- version="2.0.0",
66
- description="SOTA Financial AI with multi-LLM ensemble and momentum analysis"
67
- )
68
-
69
- # Initialize enhanced components
70
- data_provider = UnifiedDataProvider()
71
- sentiment_analyzer = EnhancedFinancialSentimentAnalyzer()
72
- momentum_engine = IntegratedMomentumEngine()
73
- llm_engine = EnhancedLLMEngine()
74
- tft_predictor = GapPredictionTFT(context_length=96, prediction_length=1)
75
-
76
- @app.on_event("startup")
77
- async def startup_event():
78
- """Initialize all AI models on startup"""
79
- print("🚀 Starting Enhanced Trading Engine...")
80
-
81
- try:
82
- # Initialize sentiment models
83
- print("📊 Loading sentiment models...")
84
- sentiment_analyzer.initialize_models()
85
-
86
- # Initialize LLM models
87
- print("🧠 Loading LLM ensemble...")
88
- llm_engine.initialize_llm_models()
89
-
90
- # Load all TFT models conditionally
91
- print("🤖 Loading TFT models...")
92
- symbols = ['QQQ', 'SPY', 'MSFT', 'TSLA', 'NVDA', 'META']
93
-
94
- # Initialize trading agent
95
- global trading_agent
96
- trading_agent = TradingAgent(api_url="http://localhost:8000")
97
- print("🤖 Trading Agent initialized")
98
-
99
- for symbol in symbols:
100
- model_path = f"trained_models/tft_{symbol}_validated.pth"
101
- tft_instance = GapPredictionTFT()
102
-
103
- if os.path.exists(model_path):
104
- try:
105
- tft_instance.load_pretrained(symbol=symbol, path=model_path)
106
- print(f"✅ Loaded pretrained TFT model for {symbol}")
107
- except Exception as e:
108
- print(f"⚠️ Failed to load TFT model for {symbol}: {e}")
109
- else:
110
- print(f"⚠️ No pretrained TFT model found for {symbol}, will train on-demand")
111
-
112
- api_tft_models[symbol] = tft_instance
113
-
114
- print("✅ Enhanced Trading Engine startup complete!")
115
-
116
- except Exception as e:
117
- print(f"❌ Startup error: {e}")
118
-
119
- @app.get("/")
120
- def read_root():
121
- """Enhanced root endpoint with system info"""
122
- import torch
123
-
124
- gpu_info = "CPU only"
125
- if torch.cuda.is_available():
126
- gpu_name = torch.cuda.get_device_name(0)
127
- gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1e9
128
- gpu_info = f"{gpu_name} ({gpu_memory:.1f} GB)"
129
-
130
- return {
131
- "status": "operational",
132
- "engine": "Enhanced Intraday Momentum Engine v2.0.0",
133
- "gpu_info": gpu_info,
134
- "features": [
135
- "Multi-LLM Ensemble Analysis",
136
- "Advanced Sentiment Analysis (10+ models)",
137
- "High-Frequency Momentum Engine",
138
- "Options Strategy Generation",
139
- "TFT Gap Prediction",
140
- "Autonomous Trading Agent"
141
- ],
142
- "timestamp": datetime.now().isoformat()
143
- }
144
-
145
- @app.post("/predict/enhanced/", response_model=EnhancedSignalResponse)
146
- async def predict_enhanced_signal(
147
- symbol: str = Query(..., description="Stock symbol (e.g., QQQ, SPY)"),
148
- timeframe: str = Query("5m", description="Trading timeframe: 1m, 5m, 15m, 1h"),
149
- strategy_mode: str = Query("momentum", description="Strategy: momentum, scalp, gap, swing")
150
- ):
151
- """
152
- Enhanced prediction endpoint with full AI stack
153
- """
154
- try:
155
- start_time = datetime.now()
156
-
157
- # Fetch market data
158
- async with httpx.AsyncClient() as client:
159
- print(f"📈 Fetching data for {symbol}...")
160
-
161
- # Multi-timeframe OHLCV data
162
- ohlcv_data = await data_provider.fetch_multi_timeframe_stock_data(symbol)
163
-
164
- # News and social data - FIXED SYNTAX
165
- news_data, _ = await data_provider.fetch_news(symbol, client)
166
- reddit_data, _ = await data_provider.fetch_reddit_data(symbol)
167
-
168
- # Alternative data
169
- alt_data = data_provider.get_alternative_data(symbol)
170
-
171
- # Process dataframes
172
- news_df = pd.DataFrame(news_data) if news_data else pd.DataFrame()
173
- reddit_df = pd.DataFrame(reddit_data) if reddit_data else pd.DataFrame()
174
-
175
- # Technical analysis for each timeframe
176
- tech_setups = {}
177
- for tf, df in ohlcv_data.items():
178
- if not df.empty:
179
- enriched_df = enrich_with_indicators(df.copy(), tf)
180
- tech_setups[tf] = identify_current_setup(enriched_df, tf)
181
-
182
- print("🔄 Running AI analysis...")
183
-
184
- # 1. Enhanced Sentiment Analysis
185
- sentiment_analysis = await asyncio.get_event_loop().run_in_executor(
186
- None,
187
- analyze_momentum_sentiment,
188
- news_df, reddit_df, symbol, timeframe
189
- )
190
-
191
- # 2. Momentum Analysis
192
- momentum_analysis = momentum_engine.generate_enhanced_signal(
193
- ohlcv_data, sentiment_analysis, alt_data
194
- )
195
-
196
- # 3. TFT Prediction
197
- daily_df = ohlcv_data.get("daily")
198
- tft_prediction = None
199
- tft_model = api_tft_models.get(symbol.upper())
200
-
201
- if daily_df is not None and len(daily_df) >= 96 and tft_model:
202
- if tft_model.is_trained:
203
- tft_prediction = tft_model.predict_gap_probability(daily_df)
204
- print(f"🚀 Using pretrained TFT model for {symbol}")
205
- else:
206
- print(f"🤖 Training TFT model for {symbol}...")
207
- tft_model.train(daily_df, epochs=20)
208
- tft_prediction = tft_model.predict_gap_probability(daily_df)
209
- else:
210
- if tft_model:
211
- tft_prediction = tft_model._default_prediction()
212
- else:
213
- temp_tft = GapPredictionTFT()
214
- tft_prediction = temp_tft._default_prediction()
215
-
216
- # 4. LLM Ensemble Analysis
217
- llm_analysis = {}
218
- try:
219
- llm_analysis = llm_engine.generate_enhanced_trading_signal(
220
- ohlcv_data, sentiment_analysis, momentum_analysis, alt_data
221
- )
222
- except Exception as e:
223
- print(f"LLM analysis failed: {e}")
224
- conditions = {
225
- "is_vix_high": alt_data.get('vix_level', 0) > 25,
226
- "is_15m_rsi_bullish": tech_setups.get("15m", {}).get('rsi', 50) > 65,
227
- "is_15m_rsi_bearish": tech_setups.get("15m", {}).get('rsi', 50) < 35,
228
- "is_15m_volume_spike": tech_setups.get("15m", {}).get('volume_spike', False),
229
- "is_hourly_trend_bullish": tech_setups.get("hourly", {}).get('direction') == 'up',
230
- "is_hourly_trend_bearish": tech_setups.get("hourly", {}).get('direction') == 'down'
231
- }
232
- llm_analysis = generate_enhanced_llm_signal(conditions)
233
-
234
- # 5. Master Signal Generation - FIXED FUNCTION NAME
235
- master_signal = _generate_master_signal(
236
- momentum_analysis, llm_analysis, sentiment_analysis, tft_prediction,
237
- timeframe, strategy_mode
238
- )
239
-
240
- # 6. Options Strategy - FIXED FUNCTION NAME
241
- options_strategy = _generate_options_strategy(
242
- master_signal, momentum_analysis, alt_data, timeframe, strategy_mode
243
- )
244
-
245
- # Calculate processing time
246
- processing_time = (datetime.now() - start_time).total_seconds()
247
-
248
- # Prepare response
249
- sanitized_details = sanitize_for_json({
250
- "tech_setups": tech_setups,
251
- "sentiment": sentiment_analysis,
252
- "alternative_data": alt_data,
253
- "tft_prediction": tft_prediction,
254
- "processing_time_seconds": processing_time,
255
- "data_sources": {
256
- "news_articles": len(news_df),
257
- "social_posts": len(reddit_df),
258
- "timeframes_analyzed": list(ohlcv_data.keys())
259
- }
260
- })
261
-
262
- return EnhancedSignalResponse(
263
- symbol=symbol,
264
- signal=master_signal["signal"],
265
- confidence=master_signal["confidence"],
266
- reasoning=master_signal["reasoning"],
267
- position_size=master_signal["position_size"],
268
- status="Success",
269
- details=sanitized_details,
270
- momentum_analysis=sanitize_for_json(momentum_analysis),
271
- llm_ensemble=sanitize_for_json(llm_analysis),
272
- options_strategy=sanitize_for_json(options_strategy),
273
- timeframe_recommendation=master_signal.get("timeframe", timeframe),
274
- expected_hold_time=master_signal.get("hold_time", "Unknown")
275
- )
276
-
277
- except Exception as e:
278
- import traceback
279
- traceback.print_exc()
280
- raise HTTPException(status_code=500, detail=f"Enhanced analysis failed: {e}")
281
-
282
- @app.get("/agent/start")
283
- async def start_agent():
284
- """Start the autonomous agent"""
285
- if trading_agent:
286
- asyncio.create_task(trading_agent.run())
287
- return {"status": "Agent started"}
288
- return {"status": "Agent not initialized"}
289
-
290
- @app.get("/agent/stats")
291
- async def get_agent_stats():
292
- """Get agent's performance stats"""
293
- if trading_agent:
294
- return trading_agent.get_stats()
295
- return {"error": "Agent not initialized"}
296
-
297
- @app.get("/agent/positions")
298
- async def get_agent_positions():
299
- """Get current positions"""
300
- if trading_agent:
301
- return {"positions": trading_agent.positions}
302
- return {"positions": {}}
303
-
304
- @app.get("/agent/analyze")
305
- async def analyze_agent():
306
- """Analyze agent's performance"""
307
- try:
308
- analyze_agent_performance()
309
- return {"status": "Analysis complete - check console output"}
310
- except Exception as e:
311
- return {"error": str(e)}
312
-
313
- def _generate_master_signal(momentum_analysis: Dict, llm_analysis: Dict,
314
- sentiment_analysis: Dict, tft_prediction: Dict,
315
- timeframe: str = "15m", strategy_mode: str = "momentum") -> Dict:
316
- """Generate master trading signal from all analyses - FIXED VERSION"""
317
-
318
- # Extract signals
319
- momentum_signal = momentum_analysis.get("signal", "HOLD")
320
- momentum_confidence = momentum_analysis.get("confidence", 50)
321
-
322
- # Use the actual momentum analysis results
323
- momentum_master = momentum_analysis.get("momentum_analysis", {}).get("master_signal", {})
324
- momentum_strategy = momentum_master.get("strategy", "WAIT")
325
-
326
- llm_signal = llm_analysis.get("signal", "HOLD")
327
- sentiment_composite = sentiment_analysis.get("composite_score", 0)
328
- tft_direction = tft_prediction.get("expected_direction", "FLAT") if tft_prediction else "FLAT"
329
-
330
- # TIMEFRAME-SPECIFIC THRESHOLDS
331
- timeframe_configs = {
332
- "1m": {
333
- "threshold": 0.2,
334
- "min_confidence": 70,
335
- "hold_time": "1-2 minutes",
336
- "position_multiplier": 0.5
337
- },
338
- "5m": {
339
- "threshold": 0.25,
340
- "min_confidence": 65,
341
- "hold_time": "2-5 minutes",
342
- "position_multiplier": 0.7
343
- },
344
- "15m": {
345
- "threshold": 0.3,
346
- "min_confidence": 60,
347
- "hold_time": "10-30 minutes",
348
- "position_multiplier": 1.0
349
- },
350
- "1h": {
351
- "threshold": 0.35,
352
- "min_confidence": 55,
353
- "hold_time": "30-60 minutes",
354
- "position_multiplier": 1.2
355
- }
356
- }
357
-
358
- config = timeframe_configs.get(timeframe, timeframe_configs["15m"])
359
-
360
- # STRATEGY MODE ADJUSTMENTS
361
- if strategy_mode == "scalp":
362
- config["threshold"] *= 0.8
363
- config["hold_time"] = "1-3 minutes"
364
- elif strategy_mode == "gap" and tft_prediction:
365
- if tft_direction != "FLAT" and tft_prediction.get("gap_probability", 50) > 70:
366
- config["min_confidence"] -= 10
367
-
368
- # Calculate weighted score
369
- if momentum_strategy in ["AGGRESSIVE_SCALP", "STANDARD_MOMENTUM"]:
370
- weighted_score = momentum_master.get("conviction", 0)
371
- weighted_confidence = momentum_confidence
372
- else:
373
- weights = {
374
- "momentum": 0.4,
375
- "llm": 0.25,
376
- "sentiment": 0.2,
377
- "tft": 0.15
378
- }
379
-
380
- signal_scores = {}
381
- signal_scores["momentum"] = 1.0 if momentum_signal == "CALLS" else -1.0 if momentum_signal == "PUTS" else 0.0
382
- signal_scores["llm"] = 1.0 if llm_signal == "CALLS" else -1.0 if llm_signal == "PUTS" else 0.0
383
- signal_scores["sentiment"] = np.clip(sentiment_composite, -1, 1)
384
- signal_scores["tft"] = 0.7 if tft_direction == "UP" else -0.7 if tft_direction == "DOWN" else 0.0
385
-
386
- weighted_score = sum(signal_scores[k] * weights[k] for k in weights)
387
- weighted_confidence = (momentum_confidence * 0.4 +
388
- llm_analysis.get("conviction", 50) * 0.3 +
389
- (sentiment_analysis.get("confidence", "LOW") == "HIGH") * 80 * 0.3)
390
-
391
- # Generate final signal
392
- if weighted_score > config["threshold"] and weighted_confidence > config["min_confidence"]:
393
- final_signal = "CALLS"
394
- position_size = min(0.5, (weighted_confidence / 100) * config["position_multiplier"])
395
- elif weighted_score < -config["threshold"] and weighted_confidence > config["min_confidence"]:
396
- final_signal = "PUTS"
397
- position_size = min(0.5, (weighted_confidence / 100) * config["position_multiplier"])
398
- else:
399
- final_signal = "HOLD"
400
- position_size = 0.0
401
- config["hold_time"] = "Wait for better setup"
402
-
403
- # Build reasoning
404
- reasoning = []
405
- reasoning.append(f"{strategy_mode.upper()} {timeframe}: {final_signal}")
406
- reasoning.append(f"Confidence: {weighted_confidence:.0f}%")
407
-
408
- if momentum_strategy != "WAIT":
409
- reasoning.append(f"Momentum: {momentum_strategy}")
410
- if abs(sentiment_composite) > 0.3:
411
- reasoning.append(f"Sentiment: {'Bullish' if sentiment_composite > 0 else 'Bearish'}")
412
- if tft_prediction and tft_prediction.get("gap_probability", 50) > 70:
413
- reasoning.append(f"Gap probability: {tft_prediction['gap_probability']:.0f}%")
414
-
415
- return {
416
- "signal": final_signal,
417
- "confidence": int(weighted_confidence),
418
- "reasoning": ". ".join(reasoning),
419
- "position_size": position_size,
420
- "timeframe": timeframe,
421
- "hold_time": config["hold_time"],
422
- "weighted_score": weighted_score,
423
- "strategy_mode": strategy_mode,
424
- "momentum_strategy": momentum_strategy
425
- }
426
-
427
- def _generate_options_strategy(master_signal: Dict, momentum_analysis: Dict,
428
- alt_data: Dict, timeframe: str = "15m",
429
- strategy_mode: str = "momentum") -> Dict:
430
- """Generate options strategy with timeframe awareness"""
431
-
432
- signal = master_signal["signal"]
433
- confidence = master_signal["confidence"]
434
- vix_level = alt_data.get("vix_level", 20)
435
-
436
- if signal == "HOLD":
437
- return {
438
- "strategy": "WAIT",
439
- "reasoning": "No clear directional bias",
440
- "contracts": [],
441
- "risk_management": "Wait for better setup"
442
- }
443
-
444
- # TIMEFRAME-SPECIFIC STRATEGIES
445
- if timeframe in ["1m", "5m"] and strategy_mode == "scalp":
446
- strategy = {
447
- "strategy": "0DTE_SCALP",
448
- "reasoning": f"{timeframe} scalp: {signal} with {confidence}% confidence",
449
- "contracts": [
450
- {
451
- "type": "CALL" if signal == "CALLS" else "PUT",
452
- "strike": "ATM",
453
- "quantity": min(int(confidence / 8), 15),
454
- "dte": 0,
455
- "target_profit": 20,
456
- "stop_loss": 10
457
- }
458
- ],
459
- "max_hold_time": f"{timeframe} bars (max 5 minutes)",
460
- "risk_management": "Ultra-tight stops, quick exits"
461
- }
462
-
463
- elif timeframe == "15m" and confidence > 70:
464
- strategy = {
465
- "strategy": "MOMENTUM_15M",
466
- "reasoning": f"15-minute momentum {signal} play, {confidence}% confidence",
467
- "contracts": [
468
- {
469
- "type": "CALL" if signal == "CALLS" else "PUT",
470
- "strike": "1% ITM",
471
- "quantity": min(int(confidence / 12), 8),
472
- "dte": 1,
473
- "target_profit": 40,
474
- "stop_loss": 20
475
- }
476
- ],
477
- "max_hold_time": "30 minutes",
478
- "risk_management": "Standard momentum stops"
479
- }
480
-
481
- elif timeframe == "1h":
482
- strategy = {
483
- "strategy": "HOURLY_SWING",
484
- "reasoning": f"Hourly swing {signal}, {confidence}% confidence",
485
- "contracts": [
486
- {
487
- "type": "CALL_SPREAD" if signal == "CALLS" else "PUT_SPREAD",
488
- "long_strike": "ATM",
489
- "short_strike": "3% OTM",
490
- "quantity": min(int(confidence / 15), 5),
491
- "dte": 3,
492
- "target_profit": 35,
493
- "stop_loss": 25
494
- }
495
- ],
496
- "max_hold_time": "2-4 hours",
497
- "risk_management": "Defined risk spreads"
498
- }
499
-
500
- else:
501
- strategy = {
502
- "strategy": "CONSERVATIVE",
503
- "reasoning": f"Lower conviction {signal}, using conservative approach",
504
- "contracts": [
505
- {
506
- "type": "CALL_SPREAD" if signal == "CALLS" else "PUT_SPREAD",
507
- "long_strike": "ATM",
508
- "short_strike": "5% OTM",
509
- "quantity": 3,
510
- "dte": 7,
511
- "target_profit": 25,
512
- "stop_loss": 20
513
- }
514
- ],
515
- "max_hold_time": "End of day",
516
- "risk_management": "Limited risk, defined reward"
517
- }
518
-
519
- # VIX adjustments
520
- if vix_level > 30:
521
- strategy["reasoning"] += f". High VIX ({vix_level}) - reduced size"
522
- for contract in strategy["contracts"]:
523
- contract["quantity"] = max(1, contract["quantity"] // 2)
524
-
525
- return strategy
526
-
527
- @app.post("/backtest/enhanced/")
528
- async def enhanced_backtest(
529
- symbol: str = Query(..., description="Stock symbol"),
530
- start_date: str = Query(..., description="Start date (YYYY-MM-DD)"),
531
- end_date: str = Query(..., description="End date (YYYY-MM-DD)"),
532
- strategy_mode: str = Query("momentum", description="Strategy mode"),
533
- initial_capital: float = Query(100000, description="Initial capital")
534
- ):
535
- """Enhanced backtesting with momentum strategies"""
536
- try:
537
- return {
538
- "status": "success",
539
- "message": "Enhanced backtesting ready",
540
- "features": [
541
- "Multi-timeframe momentum analysis",
542
- "LLM ensemble signal validation",
543
- "Options strategy backtesting",
544
- "Risk-adjusted performance metrics",
545
- "Slippage and commission modeling"
546
- ]
547
- }
548
- except Exception as e:
549
- return {"status": "error", "message": str(e)}
550
-
551
- @app.get("/health/detailed")
552
- async def detailed_health_check():
553
- """Detailed system health check"""
554
- import torch
555
-
556
- health_status = {
557
- "timestamp": datetime.now().isoformat(),
558
- "overall_status": "healthy",
559
- "components": {}
560
- }
561
-
562
- # Check GPU
563
- if torch.cuda.is_available():
564
- gpu_memory_used = torch.cuda.memory_allocated(0) / 1e9
565
- gpu_memory_total = torch.cuda.get_device_properties(0).total_memory / 1e9
566
- health_status["components"]["gpu"] = {
567
- "status": "available",
568
- "device": torch.cuda.get_device_name(0),
569
- "memory_used_gb": gpu_memory_used,
570
- "memory_total_gb": gpu_memory_total,
571
- "utilization": f"{gpu_memory_used/gpu_memory_total*100:.1f}%"
572
- }
573
- else:
574
- health_status["components"]["gpu"] = {"status": "not_available"}
575
-
576
- # Check model status
577
- health_status["components"]["sentiment_models"] = {
578
- "loaded": len(sentiment_analyzer.models),
579
- "status": "ready" if sentiment_analyzer.models else "not_loaded"
580
- }
581
-
582
- health_status["components"]["llm_models"] = {
583
- "loaded": len(llm_engine.models),
584
- "status": "ready" if llm_engine.models else "not_loaded"
585
- }
586
-
587
- health_status["components"]["tft_model"] = {
588
- "status": "trained" if tft_predictor.is_trained else "not_trained"
589
- }
590
-
591
- health_status["components"]["agent"] = {
592
- "status": "initialized" if trading_agent else "not_initialized"
593
- }
594
-
595
- return health_status
596
-
597
- if __name__ == "__main__":
598
- import uvicorn
599
  uvicorn.run(app, host="0.0.0.0", port=8000)
 
1
+ # trade_analysis/enhanced_api.py
2
+
3
+ import os
4
+ from fastapi import FastAPI, Query, HTTPException
5
+ from pydantic import BaseModel
6
+ import httpx
7
+ from typing import Dict, Any, List
8
+ import pandas as pd
9
+ import numpy as np
10
+ import asyncio
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+
14
+ # Import only modules that still exist
15
+ from .data import UnifiedDataProvider
16
+ from .indicators import enrich_with_indicators, identify_current_setup
17
+ from .enhanced_sentiment import EnhancedFinancialSentimentAnalyzer, analyze_momentum_sentiment
18
+ from .momentum_trading_engine import IntegratedMomentumEngine
19
+ from .enhanced_llm import EnhancedLLMEngine, generate_enhanced_llm_signal
20
+ from .tft_model import GapPredictionTFT
21
+ from .agent import TradingAgent, analyze_agent_performance
22
+
23
+ # Global dictionary to store TFT models
24
+ api_tft_models = {}
25
+ trading_agent = None
26
+
27
+ def sanitize_for_json(data: any) -> any:
28
+ """Recursively converts numpy and pandas types to JSON-serializable types."""
29
+ if isinstance(data, dict):
30
+ return {key: sanitize_for_json(value) for key, value in data.items()}
31
+ elif isinstance(data, list):
32
+ return [sanitize_for_json(item) for item in data]
33
+ elif isinstance(data, np.bool_):
34
+ return bool(data)
35
+ elif isinstance(data, (np.integer, np.int64)):
36
+ return int(data)
37
+ elif isinstance(data, np.floating):
38
+ return float(data)
39
+ elif isinstance(data, pd.Timestamp):
40
+ return data.isoformat()
41
+ elif isinstance(data, (pd.Series, pd.Index, np.ndarray)):
42
+ return data.tolist()
43
+ return data
44
+
45
+ class EnhancedSignalResponse(BaseModel):
46
+ """Enhanced response model with momentum and LLM analysis"""
47
+ symbol: str
48
+ signal: str
49
+ confidence: float
50
+ reasoning: str
51
+ position_size: float
52
+ status: str
53
+ details: Dict[str, Any]
54
+
55
+ # Enhanced fields
56
+ momentum_analysis: Dict[str, Any] = {}
57
+ llm_ensemble: Dict[str, Any] = {}
58
+ options_strategy: Dict[str, Any] = {}
59
+ timeframe_recommendation: str = "15m"
60
+ expected_hold_time: str = "Unknown"
61
+
62
+ # Enhanced FastAPI App
63
+ app = FastAPI(
64
+ title="Enhanced Intraday Momentum Engine",
65
+ version="2.0.0",
66
+ description="SOTA Financial AI with multi-LLM ensemble and momentum analysis"
67
+ )
68
+
69
+ # Initialize enhanced components
70
+ data_provider = UnifiedDataProvider()
71
+ sentiment_analyzer = EnhancedFinancialSentimentAnalyzer()
72
+ momentum_engine = IntegratedMomentumEngine()
73
+ llm_engine = EnhancedLLMEngine()
74
+ tft_predictor = GapPredictionTFT(context_length=96, prediction_length=1)
75
+
76
+ @app.on_event("startup")
77
+ async def startup_event():
78
+ """Initialize all AI models on startup and launch the agent."""
79
+ print("🚀 Starting Enhanced Trading Engine...")
80
+
81
+ # --- This new logic checks the environment before loading models ---
82
+ from .deploy import DeploymentConfig
83
+ config = DeploymentConfig.auto_detect()
84
+
85
+ # Load sentiment models regardless of environment
86
+ print("📊 Loading sentiment models...")
87
+ sentiment_analyzer.initialize_models()
88
+
89
+ # Only load LLMs if we are NOT on a CPU
90
+ if config.device != "cpu":
91
+ print("🧠 Loading LLM ensemble...")
92
+ llm_engine.initialize_llm_models()
93
+ else:
94
+ print("🚫 CPU environment detected. Skipping LLM loading.")
95
+
96
+ # Load TFT models
97
+ print("🤖 Loading TFT models...")
98
+ # (Your existing TFT model loading logic here, ensure it writes to /tmp if needed)
99
+ symbols = ['QQQ', 'SPY', 'MSFT', 'TSLA', 'NVDA', 'META']
100
+ for symbol in symbols:
101
+ model_path = f"/tmp/tft_{symbol}_validated.pth" # Use /tmp for models
102
+ tft_instance = GapPredictionTFT()
103
+ # (The rest of your TFT loading logic...)
104
+ api_tft_models[symbol] = tft_instance
105
+
106
+ # Initialize and run the agent as a background task
107
+ global trading_agent
108
+ trading_agent = TradingAgent(api_url="http://localhost:7860")
109
+ print("🤖 Launching Trading Agent as a background task...")
110
+ asyncio.create_task(trading_agent.run())
111
+
112
+ print("✅ Enhanced Trading Engine startup complete!")
113
+
114
+ @app.get("/")
115
+ def read_root():
116
+ """Enhanced root endpoint with system info"""
117
+ import torch
118
+
119
+ gpu_info = "CPU only"
120
+ if torch.cuda.is_available():
121
+ gpu_name = torch.cuda.get_device_name(0)
122
+ gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1e9
123
+ gpu_info = f"{gpu_name} ({gpu_memory:.1f} GB)"
124
+
125
+ return {
126
+ "status": "operational",
127
+ "engine": "Enhanced Intraday Momentum Engine v2.0.0",
128
+ "gpu_info": gpu_info,
129
+ "features": [
130
+ "Multi-LLM Ensemble Analysis",
131
+ "Advanced Sentiment Analysis (10+ models)",
132
+ "High-Frequency Momentum Engine",
133
+ "Options Strategy Generation",
134
+ "TFT Gap Prediction",
135
+ "Autonomous Trading Agent"
136
+ ],
137
+ "timestamp": datetime.now().isoformat()
138
+ }
139
+
140
+ @app.post("/predict/enhanced/", response_model=EnhancedSignalResponse)
141
+ async def predict_enhanced_signal(
142
+ symbol: str = Query(..., description="Stock symbol (e.g., QQQ, SPY)"),
143
+ timeframe: str = Query("5m", description="Trading timeframe: 1m, 5m, 15m, 1h"),
144
+ strategy_mode: str = Query("momentum", description="Strategy: momentum, scalp, gap, swing")
145
+ ):
146
+ """
147
+ Enhanced prediction endpoint with full AI stack
148
+ """
149
+ try:
150
+ start_time = datetime.now()
151
+
152
+ # Fetch market data
153
+ async with httpx.AsyncClient() as client:
154
+ print(f"📈 Fetching data for {symbol}...")
155
+
156
+ # Multi-timeframe OHLCV data
157
+ ohlcv_data = await data_provider.fetch_multi_timeframe_stock_data(symbol)
158
+
159
+ # News and social data - FIXED SYNTAX
160
+ news_data, _ = await data_provider.fetch_news(symbol, client)
161
+ reddit_data, _ = await data_provider.fetch_reddit_data(symbol)
162
+
163
+ # Alternative data
164
+ alt_data = data_provider.get_alternative_data(symbol)
165
+
166
+ # Process dataframes
167
+ news_df = pd.DataFrame(news_data) if news_data else pd.DataFrame()
168
+ reddit_df = pd.DataFrame(reddit_data) if reddit_data else pd.DataFrame()
169
+
170
+ # Technical analysis for each timeframe
171
+ tech_setups = {}
172
+ for tf, df in ohlcv_data.items():
173
+ if not df.empty:
174
+ enriched_df = enrich_with_indicators(df.copy(), tf)
175
+ tech_setups[tf] = identify_current_setup(enriched_df, tf)
176
+
177
+ print("🔄 Running AI analysis...")
178
+
179
+ # 1. Enhanced Sentiment Analysis
180
+ sentiment_analysis = await asyncio.get_event_loop().run_in_executor(
181
+ None,
182
+ analyze_momentum_sentiment,
183
+ news_df, reddit_df, symbol, timeframe
184
+ )
185
+
186
+ # 2. Momentum Analysis
187
+ momentum_analysis = momentum_engine.generate_enhanced_signal(
188
+ ohlcv_data, sentiment_analysis, alt_data
189
+ )
190
+
191
+ # 3. TFT Prediction
192
+ daily_df = ohlcv_data.get("daily")
193
+ tft_prediction = None
194
+ tft_model = api_tft_models.get(symbol.upper())
195
+
196
+ if daily_df is not None and len(daily_df) >= 96 and tft_model:
197
+ if tft_model.is_trained:
198
+ tft_prediction = tft_model.predict_gap_probability(daily_df)
199
+ print(f"🚀 Using pretrained TFT model for {symbol}")
200
+ else:
201
+ print(f"🤖 Training TFT model for {symbol}...")
202
+ tft_model.train(daily_df, epochs=20)
203
+ tft_prediction = tft_model.predict_gap_probability(daily_df)
204
+ else:
205
+ if tft_model:
206
+ tft_prediction = tft_model._default_prediction()
207
+ else:
208
+ temp_tft = GapPredictionTFT()
209
+ tft_prediction = temp_tft._default_prediction()
210
+
211
+ # 4. LLM Ensemble Analysis
212
+ llm_analysis = {}
213
+ try:
214
+ llm_analysis = llm_engine.generate_enhanced_trading_signal(
215
+ ohlcv_data, sentiment_analysis, momentum_analysis, alt_data
216
+ )
217
+ except Exception as e:
218
+ print(f"LLM analysis failed: {e}")
219
+ conditions = {
220
+ "is_vix_high": alt_data.get('vix_level', 0) > 25,
221
+ "is_15m_rsi_bullish": tech_setups.get("15m", {}).get('rsi', 50) > 65,
222
+ "is_15m_rsi_bearish": tech_setups.get("15m", {}).get('rsi', 50) < 35,
223
+ "is_15m_volume_spike": tech_setups.get("15m", {}).get('volume_spike', False),
224
+ "is_hourly_trend_bullish": tech_setups.get("hourly", {}).get('direction') == 'up',
225
+ "is_hourly_trend_bearish": tech_setups.get("hourly", {}).get('direction') == 'down'
226
+ }
227
+ llm_analysis = generate_enhanced_llm_signal(conditions)
228
+
229
+ # 5. Master Signal Generation - FIXED FUNCTION NAME
230
+ master_signal = _generate_master_signal(
231
+ momentum_analysis, llm_analysis, sentiment_analysis, tft_prediction,
232
+ timeframe, strategy_mode
233
+ )
234
+
235
+ # 6. Options Strategy - FIXED FUNCTION NAME
236
+ options_strategy = _generate_options_strategy(
237
+ master_signal, momentum_analysis, alt_data, timeframe, strategy_mode
238
+ )
239
+
240
+ # Calculate processing time
241
+ processing_time = (datetime.now() - start_time).total_seconds()
242
+
243
+ # Prepare response
244
+ sanitized_details = sanitize_for_json({
245
+ "tech_setups": tech_setups,
246
+ "sentiment": sentiment_analysis,
247
+ "alternative_data": alt_data,
248
+ "tft_prediction": tft_prediction,
249
+ "processing_time_seconds": processing_time,
250
+ "data_sources": {
251
+ "news_articles": len(news_df),
252
+ "social_posts": len(reddit_df),
253
+ "timeframes_analyzed": list(ohlcv_data.keys())
254
+ }
255
+ })
256
+
257
+ return EnhancedSignalResponse(
258
+ symbol=symbol,
259
+ signal=master_signal["signal"],
260
+ confidence=master_signal["confidence"],
261
+ reasoning=master_signal["reasoning"],
262
+ position_size=master_signal["position_size"],
263
+ status="Success",
264
+ details=sanitized_details,
265
+ momentum_analysis=sanitize_for_json(momentum_analysis),
266
+ llm_ensemble=sanitize_for_json(llm_analysis),
267
+ options_strategy=sanitize_for_json(options_strategy),
268
+ timeframe_recommendation=master_signal.get("timeframe", timeframe),
269
+ expected_hold_time=master_signal.get("hold_time", "Unknown")
270
+ )
271
+
272
+ except Exception as e:
273
+ import traceback
274
+ traceback.print_exc()
275
+ raise HTTPException(status_code=500, detail=f"Enhanced analysis failed: {e}")
276
+
277
+ @app.get("/agent/start")
278
+ async def start_agent():
279
+ """Start the autonomous agent"""
280
+ if trading_agent:
281
+ asyncio.create_task(trading_agent.run())
282
+ return {"status": "Agent started"}
283
+ return {"status": "Agent not initialized"}
284
+
285
+ @app.get("/agent/stats")
286
+ async def get_agent_stats():
287
+ """Get agent's performance stats"""
288
+ if trading_agent:
289
+ return trading_agent.get_stats()
290
+ return {"error": "Agent not initialized"}
291
+
292
+ @app.get("/agent/positions")
293
+ async def get_agent_positions():
294
+ """Get current positions"""
295
+ if trading_agent:
296
+ return {"positions": trading_agent.positions}
297
+ return {"positions": {}}
298
+
299
+ @app.get("/agent/analyze")
300
+ async def analyze_agent():
301
+ """Analyze agent's performance"""
302
+ try:
303
+ analyze_agent_performance()
304
+ return {"status": "Analysis complete - check console output"}
305
+ except Exception as e:
306
+ return {"error": str(e)}
307
+
308
+ def _generate_master_signal(momentum_analysis: Dict, llm_analysis: Dict,
309
+ sentiment_analysis: Dict, tft_prediction: Dict,
310
+ timeframe: str = "15m", strategy_mode: str = "momentum") -> Dict:
311
+ """Generate master trading signal from all analyses - FIXED VERSION"""
312
+
313
+ # Extract signals
314
+ momentum_signal = momentum_analysis.get("signal", "HOLD")
315
+ momentum_confidence = momentum_analysis.get("confidence", 50)
316
+
317
+ # Use the actual momentum analysis results
318
+ momentum_master = momentum_analysis.get("momentum_analysis", {}).get("master_signal", {})
319
+ momentum_strategy = momentum_master.get("strategy", "WAIT")
320
+
321
+ llm_signal = llm_analysis.get("signal", "HOLD")
322
+ sentiment_composite = sentiment_analysis.get("composite_score", 0)
323
+ tft_direction = tft_prediction.get("expected_direction", "FLAT") if tft_prediction else "FLAT"
324
+
325
+ # TIMEFRAME-SPECIFIC THRESHOLDS
326
+ timeframe_configs = {
327
+ "1m": {
328
+ "threshold": 0.2,
329
+ "min_confidence": 70,
330
+ "hold_time": "1-2 minutes",
331
+ "position_multiplier": 0.5
332
+ },
333
+ "5m": {
334
+ "threshold": 0.25,
335
+ "min_confidence": 65,
336
+ "hold_time": "2-5 minutes",
337
+ "position_multiplier": 0.7
338
+ },
339
+ "15m": {
340
+ "threshold": 0.3,
341
+ "min_confidence": 60,
342
+ "hold_time": "10-30 minutes",
343
+ "position_multiplier": 1.0
344
+ },
345
+ "1h": {
346
+ "threshold": 0.35,
347
+ "min_confidence": 55,
348
+ "hold_time": "30-60 minutes",
349
+ "position_multiplier": 1.2
350
+ }
351
+ }
352
+
353
+ config = timeframe_configs.get(timeframe, timeframe_configs["15m"])
354
+
355
+ # STRATEGY MODE ADJUSTMENTS
356
+ if strategy_mode == "scalp":
357
+ config["threshold"] *= 0.8
358
+ config["hold_time"] = "1-3 minutes"
359
+ elif strategy_mode == "gap" and tft_prediction:
360
+ if tft_direction != "FLAT" and tft_prediction.get("gap_probability", 50) > 70:
361
+ config["min_confidence"] -= 10
362
+
363
+ # Calculate weighted score
364
+ if momentum_strategy in ["AGGRESSIVE_SCALP", "STANDARD_MOMENTUM"]:
365
+ weighted_score = momentum_master.get("conviction", 0)
366
+ weighted_confidence = momentum_confidence
367
+ else:
368
+ weights = {
369
+ "momentum": 0.4,
370
+ "llm": 0.25,
371
+ "sentiment": 0.2,
372
+ "tft": 0.15
373
+ }
374
+
375
+ signal_scores = {}
376
+ signal_scores["momentum"] = 1.0 if momentum_signal == "CALLS" else -1.0 if momentum_signal == "PUTS" else 0.0
377
+ signal_scores["llm"] = 1.0 if llm_signal == "CALLS" else -1.0 if llm_signal == "PUTS" else 0.0
378
+ signal_scores["sentiment"] = np.clip(sentiment_composite, -1, 1)
379
+ signal_scores["tft"] = 0.7 if tft_direction == "UP" else -0.7 if tft_direction == "DOWN" else 0.0
380
+
381
+ weighted_score = sum(signal_scores[k] * weights[k] for k in weights)
382
+ weighted_confidence = (momentum_confidence * 0.4 +
383
+ llm_analysis.get("conviction", 50) * 0.3 +
384
+ (sentiment_analysis.get("confidence", "LOW") == "HIGH") * 80 * 0.3)
385
+
386
+ # Generate final signal
387
+ if weighted_score > config["threshold"] and weighted_confidence > config["min_confidence"]:
388
+ final_signal = "CALLS"
389
+ position_size = min(0.5, (weighted_confidence / 100) * config["position_multiplier"])
390
+ elif weighted_score < -config["threshold"] and weighted_confidence > config["min_confidence"]:
391
+ final_signal = "PUTS"
392
+ position_size = min(0.5, (weighted_confidence / 100) * config["position_multiplier"])
393
+ else:
394
+ final_signal = "HOLD"
395
+ position_size = 0.0
396
+ config["hold_time"] = "Wait for better setup"
397
+
398
+ # Build reasoning
399
+ reasoning = []
400
+ reasoning.append(f"{strategy_mode.upper()} {timeframe}: {final_signal}")
401
+ reasoning.append(f"Confidence: {weighted_confidence:.0f}%")
402
+
403
+ if momentum_strategy != "WAIT":
404
+ reasoning.append(f"Momentum: {momentum_strategy}")
405
+ if abs(sentiment_composite) > 0.3:
406
+ reasoning.append(f"Sentiment: {'Bullish' if sentiment_composite > 0 else 'Bearish'}")
407
+ if tft_prediction and tft_prediction.get("gap_probability", 50) > 70:
408
+ reasoning.append(f"Gap probability: {tft_prediction['gap_probability']:.0f}%")
409
+
410
+ return {
411
+ "signal": final_signal,
412
+ "confidence": int(weighted_confidence),
413
+ "reasoning": ". ".join(reasoning),
414
+ "position_size": position_size,
415
+ "timeframe": timeframe,
416
+ "hold_time": config["hold_time"],
417
+ "weighted_score": weighted_score,
418
+ "strategy_mode": strategy_mode,
419
+ "momentum_strategy": momentum_strategy
420
+ }
421
+
422
+ def _generate_options_strategy(master_signal: Dict, momentum_analysis: Dict,
423
+ alt_data: Dict, timeframe: str = "15m",
424
+ strategy_mode: str = "momentum") -> Dict:
425
+ """Generate options strategy with timeframe awareness"""
426
+
427
+ signal = master_signal["signal"]
428
+ confidence = master_signal["confidence"]
429
+ vix_level = alt_data.get("vix_level", 20)
430
+
431
+ if signal == "HOLD":
432
+ return {
433
+ "strategy": "WAIT",
434
+ "reasoning": "No clear directional bias",
435
+ "contracts": [],
436
+ "risk_management": "Wait for better setup"
437
+ }
438
+
439
+ # TIMEFRAME-SPECIFIC STRATEGIES
440
+ if timeframe in ["1m", "5m"] and strategy_mode == "scalp":
441
+ strategy = {
442
+ "strategy": "0DTE_SCALP",
443
+ "reasoning": f"{timeframe} scalp: {signal} with {confidence}% confidence",
444
+ "contracts": [
445
+ {
446
+ "type": "CALL" if signal == "CALLS" else "PUT",
447
+ "strike": "ATM",
448
+ "quantity": min(int(confidence / 8), 15),
449
+ "dte": 0,
450
+ "target_profit": 20,
451
+ "stop_loss": 10
452
+ }
453
+ ],
454
+ "max_hold_time": f"{timeframe} bars (max 5 minutes)",
455
+ "risk_management": "Ultra-tight stops, quick exits"
456
+ }
457
+
458
+ elif timeframe == "15m" and confidence > 70:
459
+ strategy = {
460
+ "strategy": "MOMENTUM_15M",
461
+ "reasoning": f"15-minute momentum {signal} play, {confidence}% confidence",
462
+ "contracts": [
463
+ {
464
+ "type": "CALL" if signal == "CALLS" else "PUT",
465
+ "strike": "1% ITM",
466
+ "quantity": min(int(confidence / 12), 8),
467
+ "dte": 1,
468
+ "target_profit": 40,
469
+ "stop_loss": 20
470
+ }
471
+ ],
472
+ "max_hold_time": "30 minutes",
473
+ "risk_management": "Standard momentum stops"
474
+ }
475
+
476
+ elif timeframe == "1h":
477
+ strategy = {
478
+ "strategy": "HOURLY_SWING",
479
+ "reasoning": f"Hourly swing {signal}, {confidence}% confidence",
480
+ "contracts": [
481
+ {
482
+ "type": "CALL_SPREAD" if signal == "CALLS" else "PUT_SPREAD",
483
+ "long_strike": "ATM",
484
+ "short_strike": "3% OTM",
485
+ "quantity": min(int(confidence / 15), 5),
486
+ "dte": 3,
487
+ "target_profit": 35,
488
+ "stop_loss": 25
489
+ }
490
+ ],
491
+ "max_hold_time": "2-4 hours",
492
+ "risk_management": "Defined risk spreads"
493
+ }
494
+
495
+ else:
496
+ strategy = {
497
+ "strategy": "CONSERVATIVE",
498
+ "reasoning": f"Lower conviction {signal}, using conservative approach",
499
+ "contracts": [
500
+ {
501
+ "type": "CALL_SPREAD" if signal == "CALLS" else "PUT_SPREAD",
502
+ "long_strike": "ATM",
503
+ "short_strike": "5% OTM",
504
+ "quantity": 3,
505
+ "dte": 7,
506
+ "target_profit": 25,
507
+ "stop_loss": 20
508
+ }
509
+ ],
510
+ "max_hold_time": "End of day",
511
+ "risk_management": "Limited risk, defined reward"
512
+ }
513
+
514
+ # VIX adjustments
515
+ if vix_level > 30:
516
+ strategy["reasoning"] += f". High VIX ({vix_level}) - reduced size"
517
+ for contract in strategy["contracts"]:
518
+ contract["quantity"] = max(1, contract["quantity"] // 2)
519
+
520
+ return strategy
521
+
522
+ @app.post("/backtest/enhanced/")
523
+ async def enhanced_backtest(
524
+ symbol: str = Query(..., description="Stock symbol"),
525
+ start_date: str = Query(..., description="Start date (YYYY-MM-DD)"),
526
+ end_date: str = Query(..., description="End date (YYYY-MM-DD)"),
527
+ strategy_mode: str = Query("momentum", description="Strategy mode"),
528
+ initial_capital: float = Query(100000, description="Initial capital")
529
+ ):
530
+ """Enhanced backtesting with momentum strategies"""
531
+ try:
532
+ return {
533
+ "status": "success",
534
+ "message": "Enhanced backtesting ready",
535
+ "features": [
536
+ "Multi-timeframe momentum analysis",
537
+ "LLM ensemble signal validation",
538
+ "Options strategy backtesting",
539
+ "Risk-adjusted performance metrics",
540
+ "Slippage and commission modeling"
541
+ ]
542
+ }
543
+ except Exception as e:
544
+ return {"status": "error", "message": str(e)}
545
+
546
+ @app.get("/health/detailed")
547
+ async def detailed_health_check():
548
+ """Detailed system health check"""
549
+ import torch
550
+
551
+ health_status = {
552
+ "timestamp": datetime.now().isoformat(),
553
+ "overall_status": "healthy",
554
+ "components": {}
555
+ }
556
+
557
+ # Check GPU
558
+ if torch.cuda.is_available():
559
+ gpu_memory_used = torch.cuda.memory_allocated(0) / 1e9
560
+ gpu_memory_total = torch.cuda.get_device_properties(0).total_memory / 1e9
561
+ health_status["components"]["gpu"] = {
562
+ "status": "available",
563
+ "device": torch.cuda.get_device_name(0),
564
+ "memory_used_gb": gpu_memory_used,
565
+ "memory_total_gb": gpu_memory_total,
566
+ "utilization": f"{gpu_memory_used/gpu_memory_total*100:.1f}%"
567
+ }
568
+ else:
569
+ health_status["components"]["gpu"] = {"status": "not_available"}
570
+
571
+ # Check model status
572
+ health_status["components"]["sentiment_models"] = {
573
+ "loaded": len(sentiment_analyzer.models),
574
+ "status": "ready" if sentiment_analyzer.models else "not_loaded"
575
+ }
576
+
577
+ health_status["components"]["llm_models"] = {
578
+ "loaded": len(llm_engine.models),
579
+ "status": "ready" if llm_engine.models else "not_loaded"
580
+ }
581
+
582
+ health_status["components"]["tft_model"] = {
583
+ "status": "trained" if tft_predictor.is_trained else "not_trained"
584
+ }
585
+
586
+ health_status["components"]["agent"] = {
587
+ "status": "initialized" if trading_agent else "not_initialized"
588
+ }
589
+
590
+ return health_status
591
+
592
+ if __name__ == "__main__":
593
+ import uvicorn
 
 
 
 
 
594
  uvicorn.run(app, host="0.0.0.0", port=8000)