eligapris commited on
Commit
09f44d7
·
verified ·
1 Parent(s): cc354ee

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +402 -147
main.py CHANGED
@@ -1,196 +1,451 @@
1
- from fastapi import FastAPI, HTTPException
2
  from pydantic import BaseModel
3
  import talib
4
  import numpy as np
5
- from typing import List, Optional
6
  import yfinance as yf
7
  from datetime import datetime, timedelta
 
 
8
 
9
- app = FastAPI(title="TA-Lib Technical Analysis API", version="1.0.0")
 
 
 
 
10
 
11
- # Pydantic models
12
- class PriceData(BaseModel):
13
- prices: List[float]
 
 
 
 
14
 
15
- class StockSymbol(BaseModel):
16
- symbol: str
17
- period: str = "1mo" # 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- class IndicatorResponse(BaseModel):
20
- indicator: str
21
- values: List[float]
22
- symbol: Optional[str] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  @app.get("/")
25
  async def root():
26
- return {"message": "TA-Lib FastAPI Technical Analysis Service", "version": "1.0.0"}
27
-
28
- @app.get("/indicators")
29
- async def list_indicators():
30
- """List available TA-Lib indicators"""
31
  return {
32
- "trend_indicators": ["SMA", "EMA", "MACD", "RSI"],
33
- "momentum_indicators": ["RSI", "STOCH", "WILLR"],
34
- "volume_indicators": ["AD", "ADOSC"],
35
- "volatility_indicators": ["BBANDS", "ATR"],
36
- "price_transform": ["AVGPRICE", "MEDPRICE", "TYPPRICE"]
 
 
 
 
 
37
  }
38
 
39
- @app.post("/sma", response_model=IndicatorResponse)
40
- async def simple_moving_average(data: PriceData, period: int = 20):
41
- """Calculate Simple Moving Average"""
42
- try:
43
- prices = np.array(data.prices)
44
- sma = talib.SMA(prices, timeperiod=period)
45
- # Remove NaN values
46
- sma_clean = sma[~np.isnan(sma)].tolist()
47
- return IndicatorResponse(indicator="SMA", values=sma_clean)
48
- except Exception as e:
49
- raise HTTPException(status_code=400, detail=str(e))
 
 
 
 
 
50
 
51
- @app.post("/ema", response_model=IndicatorResponse)
52
- async def exponential_moving_average(data: PriceData, period: int = 20):
53
- """Calculate Exponential Moving Average"""
54
- try:
55
- prices = np.array(data.prices)
56
- ema = talib.EMA(prices, timeperiod=period)
57
- ema_clean = ema[~np.isnan(ema)].tolist()
58
- return IndicatorResponse(indicator="EMA", values=ema_clean)
59
- except Exception as e:
60
- raise HTTPException(status_code=400, detail=str(e))
61
 
62
- @app.post("/rsi", response_model=IndicatorResponse)
63
- async def relative_strength_index(data: PriceData, period: int = 14):
64
- """Calculate Relative Strength Index"""
65
- try:
66
- prices = np.array(data.prices)
67
- rsi = talib.RSI(prices, timeperiod=period)
68
- rsi_clean = rsi[~np.isnan(rsi)].tolist()
69
- return IndicatorResponse(indicator="RSI", values=rsi_clean)
70
- except Exception as e:
71
- raise HTTPException(status_code=400, detail=str(e))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
- @app.post("/macd")
74
- async def macd_indicator(data: PriceData, fast_period: int = 12, slow_period: int = 26, signal_period: int = 9):
75
- """Calculate MACD (Moving Average Convergence Divergence)"""
 
 
 
76
  try:
77
- prices = np.array(data.prices)
78
- macd, macd_signal, macd_hist = talib.MACD(prices,
79
- fastperiod=fast_period,
80
- slowperiod=slow_period,
81
- signalperiod=signal_period)
82
 
83
- return {
84
- "indicator": "MACD",
85
- "macd": macd[~np.isnan(macd)].tolist(),
86
- "signal": macd_signal[~np.isnan(macd_signal)].tolist(),
87
- "histogram": macd_hist[~np.isnan(macd_hist)].tolist()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
- except Exception as e:
90
- raise HTTPException(status_code=400, detail=str(e))
91
-
92
- @app.post("/bollinger_bands")
93
- async def bollinger_bands(data: PriceData, period: int = 20, std_dev: int = 2):
94
- """Calculate Bollinger Bands"""
95
- try:
96
- prices = np.array(data.prices)
97
- upper, middle, lower = talib.BBANDS(prices,
98
- timeperiod=period,
99
- nbdevup=std_dev,
100
- nbdevdn=std_dev)
101
 
102
- return {
103
- "indicator": "BBANDS",
104
- "upper": upper[~np.isnan(upper)].tolist(),
105
- "middle": middle[~np.isnan(middle)].tolist(),
106
- "lower": lower[~np.isnan(lower)].tolist()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
- except Exception as e:
109
- raise HTTPException(status_code=400, detail=str(e))
110
-
111
- @app.post("/stock/{symbol}/sma")
112
- async def stock_sma(symbol: str, period: int = 20, timeframe: str = "1mo"):
113
- """Get SMA for a stock symbol using Yahoo Finance data"""
114
- try:
115
- # Fetch stock data
116
- stock = yf.Ticker(symbol.upper())
117
- hist = stock.history(period=timeframe)
118
 
119
- if hist.empty:
120
- raise HTTPException(status_code=404, detail=f"No data found for symbol {symbol}")
 
 
 
 
 
121
 
122
- prices = hist['Close'].values
123
- sma = talib.SMA(prices, timeperiod=period)
124
- sma_clean = sma[~np.isnan(sma)].tolist()
 
 
 
 
 
 
 
125
 
126
- return IndicatorResponse(indicator="SMA", values=sma_clean, symbol=symbol.upper())
127
  except Exception as e:
128
- raise HTTPException(status_code=400, detail=str(e))
129
 
130
- @app.post("/stock/{symbol}/rsi")
131
- async def stock_rsi(symbol: str, period: int = 14, timeframe: str = "1mo"):
132
- """Get RSI for a stock symbol using Yahoo Finance data"""
133
  try:
134
- stock = yf.Ticker(symbol.upper())
135
- hist = stock.history(period=timeframe)
136
 
137
- if hist.empty:
138
- raise HTTPException(status_code=404, detail=f"No data found for symbol {symbol}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
- prices = hist['Close'].values
141
- rsi = talib.RSI(prices, timeperiod=period)
142
- rsi_clean = rsi[~np.isnan(rsi)].tolist()
 
 
143
 
144
- return IndicatorResponse(indicator="RSI", values=rsi_clean, symbol=symbol.upper())
145
  except Exception as e:
146
- raise HTTPException(status_code=400, detail=str(e))
147
 
148
- @app.post("/stock/{symbol}/analysis")
149
- async def comprehensive_analysis(symbol: str, timeframe: str = "3mo"):
150
- """Get comprehensive technical analysis for a stock"""
151
  try:
152
- stock = yf.Ticker(symbol.upper())
153
- hist = stock.history(period=timeframe)
154
 
155
  if hist.empty:
156
- raise HTTPException(status_code=404, detail=f"No data found for symbol {symbol}")
157
 
158
- prices = hist['Close'].values
159
  highs = hist['High'].values
160
  lows = hist['Low'].values
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  volumes = hist['Volume'].values
 
 
162
 
163
- # Calculate multiple indicators
164
- sma_20 = talib.SMA(prices, timeperiod=20)
165
- ema_20 = talib.EMA(prices, timeperiod=20)
166
- rsi = talib.RSI(prices, timeperiod=14)
167
- macd, macd_signal, macd_hist = talib.MACD(prices)
168
- upper_bb, middle_bb, lower_bb = talib.BBANDS(prices)
169
- atr = talib.ATR(highs, lows, prices, timeperiod=14)
170
 
171
  return {
172
- "symbol": symbol.upper(),
173
- "timeframe": timeframe,
174
- "current_price": float(prices[-1]),
175
- "indicators": {
176
- "sma_20": float(sma_20[-1]) if not np.isnan(sma_20[-1]) else None,
177
- "ema_20": float(ema_20[-1]) if not np.isnan(ema_20[-1]) else None,
178
- "rsi": float(rsi[-1]) if not np.isnan(rsi[-1]) else None,
179
- "macd": float(macd[-1]) if not np.isnan(macd[-1]) else None,
180
- "macd_signal": float(macd_signal[-1]) if not np.isnan(macd_signal[-1]) else None,
181
- "bollinger_upper": float(upper_bb[-1]) if not np.isnan(upper_bb[-1]) else None,
182
- "bollinger_lower": float(lower_bb[-1]) if not np.isnan(lower_bb[-1]) else None,
183
- "atr": float(atr[-1]) if not np.isnan(atr[-1]) else None
184
- },
185
- "signals": {
186
- "rsi_overbought": float(rsi[-1]) > 70 if not np.isnan(rsi[-1]) else None,
187
- "rsi_oversold": float(rsi[-1]) < 30 if not np.isnan(rsi[-1]) else None,
188
- "price_above_sma": float(prices[-1]) > float(sma_20[-1]) if not np.isnan(sma_20[-1]) else None,
189
- "macd_bullish": float(macd[-1]) > float(macd_signal[-1]) if not np.isnan(macd[-1]) and not np.isnan(macd_signal[-1]) else None
190
- }
191
  }
 
192
  except Exception as e:
193
- raise HTTPException(status_code=400, detail=str(e))
194
 
195
  if __name__ == "__main__":
196
  import uvicorn
 
1
+ from fastapi import FastAPI, HTTPException, Query
2
  from pydantic import BaseModel
3
  import talib
4
  import numpy as np
5
+ from typing import List, Optional, Dict, Any
6
  import yfinance as yf
7
  from datetime import datetime, timedelta
8
+ from enum import Enum
9
+ import pandas as pd
10
 
11
+ app = FastAPI(
12
+ title="Elite US Stock Tracker API",
13
+ version="2.0.0",
14
+ description="Advanced technical analysis for top 5 US companies with actionable trading signals"
15
+ )
16
 
17
+ # Top 5 US Companies by Market Cap (2024)
18
+ class EliteStock(str, Enum):
19
+ APPLE = "AAPL"
20
+ MICROSOFT = "MSFT"
21
+ NVIDIA = "NVDA"
22
+ ALPHABET = "GOOGL"
23
+ AMAZON = "AMZN"
24
 
25
+ class TimeFrame(str, Enum):
26
+ ONE_WEEK = "7d"
27
+ ONE_MONTH = "1mo"
28
+ THREE_MONTHS = "3mo"
29
+ SIX_MONTHS = "6mo"
30
+ ONE_YEAR = "1y"
31
+
32
+ class TradingSignal(str, Enum):
33
+ STRONG_BUY = "STRONG_BUY"
34
+ BUY = "BUY"
35
+ HOLD = "HOLD"
36
+ SELL = "SELL"
37
+ STRONG_SELL = "STRONG_SELL"
38
+
39
+ class PositionRecommendation(BaseModel):
40
+ signal: TradingSignal
41
+ confidence: float # 0-100%
42
+ entry_price: Optional[float] = None
43
+ stop_loss: Optional[float] = None
44
+ take_profit: Optional[float] = None
45
+ position_size: str # Small, Medium, Large
46
+ reason: str
47
 
48
+ class TechnicalIndicators(BaseModel):
49
+ sma_20: float
50
+ sma_50: float
51
+ ema_12: float
52
+ ema_26: float
53
+ rsi: float
54
+ macd: float
55
+ macd_signal: float
56
+ macd_histogram: float
57
+ bollinger_upper: float
58
+ bollinger_middle: float
59
+ bollinger_lower: float
60
+ atr: float
61
+ stoch_k: float
62
+ stoch_d: float
63
+ williams_r: float
64
+ adx: float
65
+
66
+ class MarketMetrics(BaseModel):
67
+ current_price: float
68
+ price_change_24h: float
69
+ price_change_pct_24h: float
70
+ volume: int
71
+ avg_volume_20d: float
72
+ market_cap: Optional[float] = None
73
+ pe_ratio: Optional[float] = None
74
+ support_level: float
75
+ resistance_level: float
76
+
77
+ class ComprehensiveAnalysis(BaseModel):
78
+ symbol: str
79
+ company_name: str
80
+ last_updated: datetime
81
+ market_metrics: MarketMetrics
82
+ technical_indicators: TechnicalIndicators
83
+ position_recommendation: PositionRecommendation
84
+ key_levels: Dict[str, float]
85
+ trend_analysis: Dict[str, Any]
86
 
87
  @app.get("/")
88
  async def root():
 
 
 
 
 
89
  return {
90
+ "message": "Elite US Stock Tracker API - Top 5 Companies",
91
+ "version": "2.0.0",
92
+ "supported_stocks": [stock.value for stock in EliteStock],
93
+ "features": [
94
+ "Advanced technical analysis",
95
+ "Position recommendations",
96
+ "Support/Resistance levels",
97
+ "Multi-timeframe analysis",
98
+ "Risk management signals"
99
+ ]
100
  }
101
 
102
+ @app.get("/stocks")
103
+ async def list_elite_stocks():
104
+ """Get information about all supported elite stocks"""
105
+ stock_info = {
106
+ "AAPL": {"name": "Apple Inc.", "sector": "Technology"},
107
+ "MSFT": {"name": "Microsoft Corporation", "sector": "Technology"},
108
+ "NVDA": {"name": "NVIDIA Corporation", "sector": "Technology"},
109
+ "GOOGL": {"name": "Alphabet Inc.", "sector": "Technology"},
110
+ "AMZN": {"name": "Amazon.com Inc.", "sector": "Consumer Discretionary"}
111
+ }
112
+
113
+ return {
114
+ "elite_stocks": stock_info,
115
+ "total_count": len(stock_info),
116
+ "last_updated": datetime.now()
117
+ }
118
 
119
+ def calculate_support_resistance(prices: np.ndarray, window: int = 20) -> tuple:
120
+ """Calculate dynamic support and resistance levels"""
121
+ recent_prices = prices[-window:]
122
+ support = np.min(recent_prices)
123
+ resistance = np.max(recent_prices)
124
+ return support, resistance
 
 
 
 
125
 
126
+ def generate_trading_signal(indicators: dict, market_data: dict) -> PositionRecommendation:
127
+ """Generate intelligent trading signals based on multiple indicators"""
128
+
129
+ score = 0
130
+ reasons = []
131
+
132
+ # RSI Analysis
133
+ rsi = indicators['rsi']
134
+ if rsi < 30:
135
+ score += 2
136
+ reasons.append("RSI oversold (bullish)")
137
+ elif rsi > 70:
138
+ score -= 2
139
+ reasons.append("RSI overbought (bearish)")
140
+ elif 40 <= rsi <= 60:
141
+ score += 1
142
+ reasons.append("RSI neutral zone")
143
+
144
+ # MACD Analysis
145
+ if indicators['macd'] > indicators['macd_signal']:
146
+ score += 1
147
+ reasons.append("MACD bullish crossover")
148
+ else:
149
+ score -= 1
150
+ reasons.append("MACD bearish signal")
151
+
152
+ # Moving Average Analysis
153
+ current_price = market_data['current_price']
154
+ if current_price > indicators['sma_50']:
155
+ score += 1
156
+ reasons.append("Price above 50-day SMA")
157
+ else:
158
+ score -= 1
159
+ reasons.append("Price below 50-day SMA")
160
+
161
+ # Bollinger Bands Analysis
162
+ bb_position = (current_price - indicators['bollinger_lower']) / (indicators['bollinger_upper'] - indicators['bollinger_lower'])
163
+ if bb_position < 0.2:
164
+ score += 1
165
+ reasons.append("Near lower Bollinger Band (potential bounce)")
166
+ elif bb_position > 0.8:
167
+ score -= 1
168
+ reasons.append("Near upper Bollinger Band (potential reversal)")
169
+
170
+ # ADX Trend Strength
171
+ if indicators['adx'] > 25:
172
+ if score > 0:
173
+ score += 1
174
+ reasons.append("Strong trend confirms bullish bias")
175
+ else:
176
+ score -= 1
177
+ reasons.append("Strong trend confirms bearish bias")
178
+
179
+ # Determine signal and confidence
180
+ if score >= 4:
181
+ signal = TradingSignal.STRONG_BUY
182
+ confidence = min(95, 70 + score * 5)
183
+ position_size = "Large"
184
+ elif score >= 2:
185
+ signal = TradingSignal.BUY
186
+ confidence = min(85, 60 + score * 5)
187
+ position_size = "Medium"
188
+ elif score <= -4:
189
+ signal = TradingSignal.STRONG_SELL
190
+ confidence = min(95, 70 + abs(score) * 5)
191
+ position_size = "Large"
192
+ elif score <= -2:
193
+ signal = TradingSignal.SELL
194
+ confidence = min(85, 60 + abs(score) * 5)
195
+ position_size = "Medium"
196
+ else:
197
+ signal = TradingSignal.HOLD
198
+ confidence = 50 + abs(score) * 10
199
+ position_size = "Small"
200
+
201
+ # Calculate risk management levels
202
+ atr = indicators['atr']
203
+ if signal in [TradingSignal.STRONG_BUY, TradingSignal.BUY]:
204
+ entry_price = current_price
205
+ stop_loss = current_price - (2 * atr)
206
+ take_profit = current_price + (3 * atr)
207
+ elif signal in [TradingSignal.STRONG_SELL, TradingSignal.SELL]:
208
+ entry_price = current_price
209
+ stop_loss = current_price + (2 * atr)
210
+ take_profit = current_price - (3 * atr)
211
+ else:
212
+ entry_price = None
213
+ stop_loss = None
214
+ take_profit = None
215
+
216
+ return PositionRecommendation(
217
+ signal=signal,
218
+ confidence=confidence,
219
+ entry_price=entry_price,
220
+ stop_loss=stop_loss,
221
+ take_profit=take_profit,
222
+ position_size=position_size,
223
+ reason="; ".join(reasons)
224
+ )
225
 
226
+ @app.get("/analysis/{symbol}", response_model=ComprehensiveAnalysis)
227
+ async def get_comprehensive_analysis(
228
+ symbol: EliteStock,
229
+ timeframe: TimeFrame = TimeFrame.THREE_MONTHS
230
+ ):
231
+ """Get comprehensive technical analysis for an elite stock"""
232
  try:
233
+ # Fetch stock data
234
+ ticker = yf.Ticker(symbol.value)
235
+ hist = ticker.history(period=timeframe.value)
236
+ info = ticker.info
 
237
 
238
+ if hist.empty:
239
+ raise HTTPException(status_code=404, detail=f"No data found for {symbol.value}")
240
+
241
+ # Extract price data
242
+ closes = hist['Close'].values
243
+ highs = hist['High'].values
244
+ lows = hist['Low'].values
245
+ volumes = hist['Volume'].values
246
+
247
+ # Calculate technical indicators
248
+ sma_20 = talib.SMA(closes, timeperiod=20)
249
+ sma_50 = talib.SMA(closes, timeperiod=50)
250
+ ema_12 = talib.EMA(closes, timeperiod=12)
251
+ ema_26 = talib.EMA(closes, timeperiod=26)
252
+ rsi = talib.RSI(closes, timeperiod=14)
253
+ macd, macd_signal, macd_hist = talib.MACD(closes)
254
+ bb_upper, bb_middle, bb_lower = talib.BBANDS(closes)
255
+ atr = talib.ATR(highs, lows, closes, timeperiod=14)
256
+ stoch_k, stoch_d = talib.STOCH(highs, lows, closes)
257
+ williams_r = talib.WILLR(highs, lows, closes)
258
+ adx = talib.ADX(highs, lows, closes)
259
+
260
+ # Get latest values
261
+ current_price = float(closes[-1])
262
+ latest_indicators = {
263
+ 'sma_20': float(sma_20[-1]) if not np.isnan(sma_20[-1]) else current_price,
264
+ 'sma_50': float(sma_50[-1]) if not np.isnan(sma_50[-1]) else current_price,
265
+ 'ema_12': float(ema_12[-1]) if not np.isnan(ema_12[-1]) else current_price,
266
+ 'ema_26': float(ema_26[-1]) if not np.isnan(ema_26[-1]) else current_price,
267
+ 'rsi': float(rsi[-1]) if not np.isnan(rsi[-1]) else 50.0,
268
+ 'macd': float(macd[-1]) if not np.isnan(macd[-1]) else 0.0,
269
+ 'macd_signal': float(macd_signal[-1]) if not np.isnan(macd_signal[-1]) else 0.0,
270
+ 'macd_histogram': float(macd_hist[-1]) if not np.isnan(macd_hist[-1]) else 0.0,
271
+ 'bollinger_upper': float(bb_upper[-1]) if not np.isnan(bb_upper[-1]) else current_price * 1.02,
272
+ 'bollinger_middle': float(bb_middle[-1]) if not np.isnan(bb_middle[-1]) else current_price,
273
+ 'bollinger_lower': float(bb_lower[-1]) if not np.isnan(bb_lower[-1]) else current_price * 0.98,
274
+ 'atr': float(atr[-1]) if not np.isnan(atr[-1]) else current_price * 0.02,
275
+ 'stoch_k': float(stoch_k[-1]) if not np.isnan(stoch_k[-1]) else 50.0,
276
+ 'stoch_d': float(stoch_d[-1]) if not np.isnan(stoch_d[-1]) else 50.0,
277
+ 'williams_r': float(williams_r[-1]) if not np.isnan(williams_r[-1]) else -50.0,
278
+ 'adx': float(adx[-1]) if not np.isnan(adx[-1]) else 25.0
279
  }
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
+ # Calculate support and resistance
282
+ support, resistance = calculate_support_resistance(closes)
283
+
284
+ # Market metrics
285
+ price_change_24h = float(closes[-1] - closes[-2]) if len(closes) > 1 else 0.0
286
+ price_change_pct_24h = (price_change_24h / closes[-2] * 100) if len(closes) > 1 else 0.0
287
+ avg_volume_20d = float(np.mean(volumes[-20:])) if len(volumes) >= 20 else float(volumes[-1])
288
+
289
+ market_metrics = MarketMetrics(
290
+ current_price=current_price,
291
+ price_change_24h=price_change_24h,
292
+ price_change_pct_24h=price_change_pct_24h,
293
+ volume=int(volumes[-1]),
294
+ avg_volume_20d=avg_volume_20d,
295
+ market_cap=info.get('marketCap'),
296
+ pe_ratio=info.get('trailingPE'),
297
+ support_level=float(support),
298
+ resistance_level=float(resistance)
299
+ )
300
+
301
+ # Generate trading recommendation
302
+ position_rec = generate_trading_signal(latest_indicators, {'current_price': current_price})
303
+
304
+ # Key levels analysis
305
+ key_levels = {
306
+ "pivot_point": float((highs[-1] + lows[-1] + closes[-1]) / 3),
307
+ "fibonacci_618": float(support + (resistance - support) * 0.618),
308
+ "fibonacci_382": float(support + (resistance - support) * 0.382),
309
+ "vwap": float(np.average(closes[-20:], weights=volumes[-20:])) if len(closes) >= 20 else current_price
310
  }
 
 
 
 
 
 
 
 
 
 
311
 
312
+ # Trend analysis
313
+ trend_analysis = {
314
+ "short_term_trend": "bullish" if latest_indicators['ema_12'] > latest_indicators['ema_26'] else "bearish",
315
+ "medium_term_trend": "bullish" if current_price > latest_indicators['sma_50'] else "bearish",
316
+ "trend_strength": "strong" if latest_indicators['adx'] > 25 else "weak",
317
+ "volatility": "high" if latest_indicators['atr'] / current_price > 0.03 else "normal"
318
+ }
319
 
320
+ return ComprehensiveAnalysis(
321
+ symbol=symbol.value,
322
+ company_name=info.get('longName', symbol.value),
323
+ last_updated=datetime.now(),
324
+ market_metrics=market_metrics,
325
+ technical_indicators=TechnicalIndicators(**latest_indicators),
326
+ position_recommendation=position_rec,
327
+ key_levels=key_levels,
328
+ trend_analysis=trend_analysis
329
+ )
330
 
 
331
  except Exception as e:
332
+ raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
333
 
334
+ @app.get("/portfolio/overview")
335
+ async def portfolio_overview():
336
+ """Get overview of all elite stocks with quick signals"""
337
  try:
338
+ results = {}
 
339
 
340
+ for stock in EliteStock:
341
+ ticker = yf.Ticker(stock.value)
342
+ hist = ticker.history(period="1mo")
343
+
344
+ if not hist.empty:
345
+ closes = hist['Close'].values
346
+ current_price = float(closes[-1])
347
+ rsi = talib.RSI(closes, timeperiod=14)
348
+ macd, macd_signal, _ = talib.MACD(closes)
349
+
350
+ # Quick signal
351
+ latest_rsi = float(rsi[-1]) if not np.isnan(rsi[-1]) else 50.0
352
+ latest_macd = float(macd[-1]) if not np.isnan(macd[-1]) else 0.0
353
+ latest_macd_signal = float(macd_signal[-1]) if not np.isnan(macd_signal[-1]) else 0.0
354
+
355
+ if latest_rsi < 30 and latest_macd > latest_macd_signal:
356
+ quick_signal = "BUY"
357
+ elif latest_rsi > 70 and latest_macd < latest_macd_signal:
358
+ quick_signal = "SELL"
359
+ else:
360
+ quick_signal = "HOLD"
361
+
362
+ results[stock.value] = {
363
+ "current_price": current_price,
364
+ "rsi": latest_rsi,
365
+ "quick_signal": quick_signal,
366
+ "price_change_24h": float(closes[-1] - closes[-2]) if len(closes) > 1 else 0.0
367
+ }
368
 
369
+ return {
370
+ "portfolio_overview": results,
371
+ "market_sentiment": "mixed", # Could be enhanced with market-wide analysis
372
+ "last_updated": datetime.now()
373
+ }
374
 
 
375
  except Exception as e:
376
+ raise HTTPException(status_code=500, detail=f"Portfolio overview failed: {str(e)}")
377
 
378
+ @app.get("/alerts/{symbol}")
379
+ async def get_trading_alerts(symbol: EliteStock):
380
+ """Get real-time trading alerts for a specific stock"""
381
  try:
382
+ ticker = yf.Ticker(symbol.value)
383
+ hist = ticker.history(period="5d") # Last 5 days for recent alerts
384
 
385
  if hist.empty:
386
+ raise HTTPException(status_code=404, detail=f"No data found for {symbol.value}")
387
 
388
+ closes = hist['Close'].values
389
  highs = hist['High'].values
390
  lows = hist['Low'].values
391
+
392
+ # Calculate indicators for alerts
393
+ rsi = talib.RSI(closes, timeperiod=14)
394
+ bb_upper, bb_middle, bb_lower = talib.BBANDS(closes)
395
+
396
+ alerts = []
397
+ current_price = float(closes[-1])
398
+ latest_rsi = float(rsi[-1]) if not np.isnan(rsi[-1]) else 50.0
399
+
400
+ # RSI alerts
401
+ if latest_rsi <= 30:
402
+ alerts.append({
403
+ "type": "RSI_OVERSOLD",
404
+ "message": f"RSI at {latest_rsi:.1f} - Potential buying opportunity",
405
+ "urgency": "HIGH"
406
+ })
407
+ elif latest_rsi >= 70:
408
+ alerts.append({
409
+ "type": "RSI_OVERBOUGHT",
410
+ "message": f"RSI at {latest_rsi:.1f} - Consider taking profits",
411
+ "urgency": "HIGH"
412
+ })
413
+
414
+ # Bollinger Band alerts
415
+ if current_price <= bb_lower[-1]:
416
+ alerts.append({
417
+ "type": "BOLLINGER_LOWER",
418
+ "message": f"Price touching lower Bollinger Band - Potential reversal",
419
+ "urgency": "MEDIUM"
420
+ })
421
+ elif current_price >= bb_upper[-1]:
422
+ alerts.append({
423
+ "type": "BOLLINGER_UPPER",
424
+ "message": f"Price touching upper Bollinger Band - Overbought condition",
425
+ "urgency": "MEDIUM"
426
+ })
427
+
428
+ # Volume alerts
429
  volumes = hist['Volume'].values
430
+ avg_volume = np.mean(volumes[:-1]) # Average excluding today
431
+ volume_ratio = volumes[-1] / avg_volume
432
 
433
+ if volume_ratio > 2:
434
+ alerts.append({
435
+ "type": "HIGH_VOLUME",
436
+ "message": f"Volume spike: {volume_ratio:.1f}x average - Significant interest",
437
+ "urgency": "HIGH"
438
+ })
 
439
 
440
  return {
441
+ "symbol": symbol.value,
442
+ "alerts": alerts,
443
+ "alert_count": len(alerts),
444
+ "last_updated": datetime.now()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
  }
446
+
447
  except Exception as e:
448
+ raise HTTPException(status_code=500, detail=f"Alerts failed: {str(e)}")
449
 
450
  if __name__ == "__main__":
451
  import uvicorn