S-Dreamer commited on
Commit
70179be
·
verified ·
1 Parent(s): 2f3c291

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -648
app.py CHANGED
@@ -21,683 +21,84 @@ scaler = MinMaxScaler(feature_range=(-1, 1))
21
  scaler.fit_transform([[-1, 1]])
22
 
23
  def clear_gpu_memory():
24
- """Clear GPU memory cache"""
25
  if torch.cuda.is_available():
26
  torch.cuda.empty_cache()
27
  gc.collect()
28
 
29
  @spaces.GPU
30
  def load_pipeline():
31
- """Load the Chronos model with GPU configuration"""
32
  global pipeline
33
- try:
34
- if pipeline is None:
35
- clear_gpu_memory()
36
- pipeline = ChronosPipeline.from_pretrained(
37
- "amazon/chronos-t5-large",
38
- device_map="auto", # Let the machine choose the best device
39
- torch_dtype=torch.float16, # Use float16 for better memory efficiency
40
- low_cpu_mem_usage=True
41
- )
42
- pipeline.model = pipeline.model.eval()
43
- return pipeline
44
- except Exception as e:
45
- print(f"Error loading pipeline: {str(e)}")
46
- raise RuntimeError(f"Failed to load model: {str(e)}")
47
 
48
  def is_market_open() -> bool:
49
- """Check if the market is currently open"""
50
  now = datetime.now()
51
- # Check if it's a weekday (0 = Monday, 6 = Sunday)
52
- if now.weekday() >= 5: # Saturday or Sunday
53
  return False
54
-
55
- # Check if it's during market hours (9:30 AM - 4:00 PM ET)
56
  et_time = now.astimezone(pytz.timezone('US/Eastern'))
57
  market_open = et_time.replace(hour=9, minute=30, second=0, microsecond=0)
58
  market_close = et_time.replace(hour=16, minute=0, second=0, microsecond=0)
59
-
60
  return market_open <= et_time <= market_close
61
 
62
  def get_next_trading_day() -> datetime:
63
- """Get the next trading day"""
64
- now = datetime.now()
65
- next_day = now + timedelta(days=1)
66
-
67
- # Skip weekends
68
- while next_day.weekday() >= 5: # Saturday or Sunday
69
  next_day += timedelta(days=1)
70
-
71
  return next_day
72
 
73
- def get_historical_data(symbol: str, timeframe: str = "1d", lookback_days: int = 365) -> pd.DataFrame:
74
- """
75
- Fetch historical data using yfinance.
76
-
77
- Args:
78
- symbol (str): The stock symbol (e.g., 'AAPL')
79
- timeframe (str): The timeframe for data ('1d', '1h', '15m')
80
- lookback_days (int): Number of days to look back
81
-
82
- Returns:
83
- pd.DataFrame: Historical data with OHLCV and technical indicators
84
- """
85
- try:
86
- # Check if market is open for intraday data
87
- if timeframe in ["1h", "15m"] and not is_market_open():
88
- next_trading_day = get_next_trading_day()
89
- raise Exception(f"Market is currently closed. Next trading day is {next_trading_day.strftime('%Y-%m-%d')}")
90
-
91
- # Map timeframe to yfinance interval and adjust lookback period
92
- tf_map = {
93
- "1d": "1d",
94
- "1h": "1h",
95
- "15m": "15m"
96
- }
97
- interval = tf_map.get(timeframe, "1d")
98
-
99
- # Adjust lookback period based on timeframe
100
- if timeframe == "1h":
101
- lookback_days = min(lookback_days, 30) # Yahoo limits hourly data to 30 days
102
- elif timeframe == "15m":
103
- lookback_days = min(lookback_days, 5) # Yahoo limits 15m data to 5 days
104
-
105
- # Calculate date range
106
- end_date = datetime.now()
107
- start_date = end_date - timedelta(days=lookback_days)
108
-
109
- # Fetch data using yfinance
110
- ticker = yf.Ticker(symbol)
111
- df = ticker.history(start=start_date, end=end_date, interval=interval)
112
-
113
- if df.empty:
114
- raise Exception(f"No data available for {symbol} in {timeframe} timeframe")
115
-
116
- # Get additional info for structured products
117
- info = ticker.info
118
- df['Market_Cap'] = info.get('marketCap', None)
119
- df['Sector'] = info.get('sector', None)
120
- df['Industry'] = info.get('industry', None)
121
- df['Dividend_Yield'] = info.get('dividendYield', None)
122
-
123
- # Calculate technical indicators with adjusted windows based on timeframe
124
- if timeframe == "1d":
125
- sma_window_20 = 20
126
- sma_window_50 = 50
127
- sma_window_200 = 200
128
- vol_window = 20
129
- elif timeframe == "1h":
130
- sma_window_20 = 20 * 6 # 5 trading days
131
- sma_window_50 = 50 * 6 # ~10 trading days
132
- sma_window_200 = 200 * 6 # ~40 trading days
133
- vol_window = 20 * 6
134
- else: # 15m
135
- sma_window_20 = 20 * 24 # 5 trading days
136
- sma_window_50 = 50 * 24 # ~10 trading days
137
- sma_window_200 = 200 * 24 # ~40 trading days
138
- vol_window = 20 * 24
139
-
140
- df['SMA_20'] = df['Close'].rolling(window=sma_window_20).mean()
141
- df['SMA_50'] = df['Close'].rolling(window=sma_window_50).mean()
142
- df['SMA_200'] = df['Close'].rolling(window=sma_window_200).mean()
143
- df['RSI'] = calculate_rsi(df['Close'])
144
- df['MACD'], df['MACD_Signal'] = calculate_macd(df['Close'])
145
- df['BB_Upper'], df['BB_Middle'], df['BB_Lower'] = calculate_bollinger_bands(df['Close'])
146
-
147
- # Calculate returns and volatility
148
- df['Returns'] = df['Close'].pct_change()
149
- df['Volatility'] = df['Returns'].rolling(window=vol_window).std()
150
- df['Annualized_Vol'] = df['Volatility'] * np.sqrt(252)
151
-
152
- # Calculate drawdown metrics
153
- df['Rolling_Max'] = df['Close'].rolling(window=len(df), min_periods=1).max()
154
- df['Drawdown'] = (df['Close'] - df['Rolling_Max']) / df['Rolling_Max']
155
- df['Max_Drawdown'] = df['Drawdown'].rolling(window=len(df), min_periods=1).min()
156
-
157
- # Calculate liquidity metrics
158
- df['Avg_Daily_Volume'] = df['Volume'].rolling(window=vol_window).mean()
159
- df['Volume_Volatility'] = df['Volume'].rolling(window=vol_window).std()
160
-
161
- # Drop NaN values
162
- df = df.dropna()
163
-
164
- if len(df) < 2:
165
- raise Exception(f"Insufficient data points for {symbol} in {timeframe} timeframe")
166
-
167
- return df
168
-
169
- except Exception as e:
170
- raise Exception(f"Error fetching historical data for {symbol}: {str(e)}")
171
-
172
- def calculate_rsi(prices: pd.Series, period: int = 14) -> pd.Series:
173
- """Calculate Relative Strength Index"""
174
- delta = prices.diff()
175
- gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
176
- loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
177
- rs = gain / loss
178
- return 100 - (100 / (1 + rs))
179
-
180
- def calculate_macd(prices: pd.Series, fast: int = 12, slow: int = 26, signal: int = 9) -> Tuple[pd.Series, pd.Series]:
181
- """Calculate MACD and Signal line"""
182
- exp1 = prices.ewm(span=fast, adjust=False).mean()
183
- exp2 = prices.ewm(span=slow, adjust=False).mean()
184
- macd = exp1 - exp2
185
- signal_line = macd.ewm(span=signal, adjust=False).mean()
186
- return macd, signal_line
187
-
188
- def calculate_bollinger_bands(prices: pd.Series, period: int = 20, std_dev: int = 2) -> Tuple[pd.Series, pd.Series, pd.Series]:
189
- """Calculate Bollinger Bands"""
190
- middle_band = prices.rolling(window=period).mean()
191
- std = prices.rolling(window=period).std()
192
- upper_band = middle_band + (std * std_dev)
193
- lower_band = middle_band - (std * std_dev)
194
- return upper_band, middle_band, lower_band
195
-
196
- @spaces.GPU
197
- def make_prediction(symbol: str, timeframe: str = "1d", prediction_days: int = 5, strategy: str = "chronos") -> Tuple[Dict, go.Figure]:
198
- """
199
- Make prediction using selected strategy.
200
-
201
- Args:
202
- symbol (str): Stock symbol
203
- timeframe (str): Data timeframe ('1d', '1h', '15m')
204
- prediction_days (int): Number of days to predict
205
- strategy (str): Prediction strategy to use
206
-
207
- Returns:
208
- Tuple[Dict, go.Figure]: Trading signals and visualization plot
209
- """
210
- try:
211
- # Get historical data
212
- df = get_historical_data(symbol, timeframe)
213
-
214
- if strategy == "chronos":
215
- try:
216
- # Prepare data for Chronos
217
- returns = df['Returns'].values
218
- normalized_returns = (returns - returns.mean()) / returns.std()
219
-
220
- # Ensure we have enough data points
221
- min_data_points = 64 # Minimum required by Chronos
222
- if len(normalized_returns) < min_data_points:
223
- # Pad the data with the last value
224
- padding = np.full(min_data_points - len(normalized_returns), normalized_returns[-1])
225
- normalized_returns = np.concatenate([padding, normalized_returns])
226
-
227
- context = torch.tensor(normalized_returns.reshape(-1, 1), dtype=torch.float32)
228
-
229
- # Make prediction with GPU acceleration
230
- pipe = load_pipeline()
231
-
232
- # Adjust prediction length based on timeframe
233
- if timeframe == "1d":
234
- max_prediction_length = 64 # Maximum 64 days for daily data
235
- elif timeframe == "1h":
236
- max_prediction_length = 168 # Maximum 7 days (168 hours) for hourly data
237
- else: # 15m
238
- max_prediction_length = 192 # Maximum 2 days (192 15-minute intervals) for 15m data
239
-
240
- # Convert prediction_days to appropriate intervals
241
- if timeframe == "1d":
242
- actual_prediction_length = min(prediction_days, max_prediction_length)
243
- elif timeframe == "1h":
244
- actual_prediction_length = min(prediction_days * 24, max_prediction_length)
245
- else: # 15m
246
- actual_prediction_length = min(prediction_days * 96, max_prediction_length)
247
-
248
- # Ensure prediction length is at least 1
249
- actual_prediction_length = max(1, actual_prediction_length)
250
-
251
- with torch.inference_mode():
252
- prediction = pipe.predict(
253
- context=context,
254
- prediction_length=actual_prediction_length,
255
- num_samples=100
256
- ).detach().cpu().numpy()
257
-
258
- mean_pred = prediction.mean(axis=0)
259
- std_pred = prediction.std(axis=0)
260
-
261
- # If we had to limit the prediction length, extend the prediction
262
- if actual_prediction_length < prediction_days:
263
- last_pred = mean_pred[-1]
264
- last_std = std_pred[-1]
265
- extension = np.array([last_pred * (1 + np.random.normal(0, last_std, prediction_days - actual_prediction_length))])
266
- mean_pred = np.concatenate([mean_pred, extension])
267
- std_pred = np.concatenate([std_pred, np.full(prediction_days - actual_prediction_length, last_std)])
268
-
269
- except Exception as e:
270
- print(f"Chronos prediction failed: {str(e)}")
271
- print("Falling back to technical analysis")
272
- strategy = "technical"
273
-
274
- if strategy == "technical":
275
- # Technical analysis based prediction
276
- last_price = df['Close'].iloc[-1]
277
- rsi = df['RSI'].iloc[-1]
278
- macd = df['MACD'].iloc[-1]
279
- macd_signal = df['MACD_Signal'].iloc[-1]
280
-
281
- # Simple prediction based on technical indicators
282
- trend = 1 if (rsi > 50 and macd > macd_signal) else -1
283
- volatility = df['Volatility'].iloc[-1]
284
-
285
- # Generate predictions
286
- mean_pred = np.array([last_price * (1 + trend * volatility * i) for i in range(1, prediction_days + 1)])
287
- std_pred = np.array([volatility * last_price * i for i in range(1, prediction_days + 1)])
288
-
289
- # Create prediction dates based on timeframe
290
- last_date = df.index[-1]
291
- if timeframe == "1d":
292
- pred_dates = pd.date_range(start=last_date + timedelta(days=1), periods=prediction_days)
293
- elif timeframe == "1h":
294
- pred_dates = pd.date_range(start=last_date + timedelta(hours=1), periods=prediction_days * 24)
295
- else: # 15m
296
- pred_dates = pd.date_range(start=last_date + timedelta(minutes=15), periods=prediction_days * 96)
297
-
298
- # Create visualization
299
- fig = make_subplots(rows=3, cols=1,
300
- shared_xaxes=True,
301
- vertical_spacing=0.05,
302
- subplot_titles=('Price Prediction', 'Technical Indicators', 'Volume'))
303
-
304
- # Add historical price
305
- fig.add_trace(
306
- go.Scatter(x=df.index, y=df['Close'], name='Historical Price',
307
- line=dict(color='blue')),
308
- row=1, col=1
309
- )
310
-
311
- # Add prediction mean
312
- fig.add_trace(
313
- go.Scatter(x=pred_dates, y=mean_pred, name='Predicted Price',
314
- line=dict(color='red')),
315
- row=1, col=1
316
- )
317
-
318
- # Add confidence intervals
319
- fig.add_trace(
320
- go.Scatter(x=pred_dates, y=mean_pred + 1.96 * std_pred,
321
- fill=None, mode='lines', line_color='rgba(255,0,0,0.2)',
322
- name='Upper Bound'),
323
- row=1, col=1
324
- )
325
- fig.add_trace(
326
- go.Scatter(x=pred_dates, y=mean_pred - 1.96 * std_pred,
327
- fill='tonexty', mode='lines', line_color='rgba(255,0,0,0.2)',
328
- name='Lower Bound'),
329
- row=1, col=1
330
- )
331
-
332
- # Add technical indicators
333
- fig.add_trace(
334
- go.Scatter(x=df.index, y=df['RSI'], name='RSI',
335
- line=dict(color='purple')),
336
- row=2, col=1
337
- )
338
- fig.add_trace(
339
- go.Scatter(x=df.index, y=df['MACD'], name='MACD',
340
- line=dict(color='orange')),
341
- row=2, col=1
342
- )
343
- fig.add_trace(
344
- go.Scatter(x=df.index, y=df['MACD_Signal'], name='MACD Signal',
345
- line=dict(color='green')),
346
- row=2, col=1
347
- )
348
-
349
- # Add volume
350
- fig.add_trace(
351
- go.Bar(x=df.index, y=df['Volume'], name='Volume',
352
- marker_color='gray'),
353
- row=3, col=1
354
- )
355
-
356
- # Update layout with timeframe-specific settings
357
- fig.update_layout(
358
- title=f'{symbol} {timeframe} Analysis and Prediction',
359
- xaxis_title='Date',
360
- yaxis_title='Price',
361
- height=1000,
362
- showlegend=True
363
- )
364
-
365
- # Calculate trading signals
366
- signals = calculate_trading_signals(df)
367
-
368
- # Add prediction information to signals
369
- signals.update({
370
- "symbol": symbol,
371
- "timeframe": timeframe,
372
- "prediction": mean_pred.tolist(),
373
- "confidence": std_pred.tolist(),
374
- "dates": pred_dates.strftime('%Y-%m-%d %H:%M:%S').tolist(),
375
- "strategy_used": strategy
376
- })
377
-
378
- return signals, fig
379
-
380
- except Exception as e:
381
- raise Exception(f"Prediction error: {str(e)}")
382
- finally:
383
- clear_gpu_memory()
384
 
385
- def calculate_trading_signals(df: pd.DataFrame) -> Dict:
386
- """Calculate trading signals based on technical indicators"""
387
- signals = {
388
- "RSI": "Oversold" if df['RSI'].iloc[-1] < 30 else "Overbought" if df['RSI'].iloc[-1] > 70 else "Neutral",
389
- "MACD": "Buy" if df['MACD'].iloc[-1] > df['MACD_Signal'].iloc[-1] else "Sell",
390
- "Bollinger": "Buy" if df['Close'].iloc[-1] < df['BB_Lower'].iloc[-1] else "Sell" if df['Close'].iloc[-1] > df['BB_Upper'].iloc[-1] else "Hold",
391
- "SMA": "Buy" if df['SMA_20'].iloc[-1] > df['SMA_50'].iloc[-1] else "Sell"
392
- }
393
-
394
- # Calculate overall signal
395
- buy_signals = sum(1 for signal in signals.values() if signal == "Buy")
396
- sell_signals = sum(1 for signal in signals.values() if signal == "Sell")
397
-
398
- if buy_signals > sell_signals:
399
- signals["Overall"] = "Buy"
400
- elif sell_signals > buy_signals:
401
- signals["Overall"] = "Sell"
402
- else:
403
- signals["Overall"] = "Hold"
404
-
405
- return signals
406
 
407
  def create_interface():
408
- """Create the Gradio interface with separate tabs for different timeframes"""
409
- with gr.Blocks(title="Structured Product Analysis") as demo:
410
- gr.Markdown("# Structured Product Analysis")
411
- gr.Markdown("Analyze stocks for inclusion in structured financial products with extended time horizons.")
412
 
413
- # Add market status message
 
 
414
  market_status = "Market is currently closed" if not is_market_open() else "Market is currently open"
415
  next_trading_day = get_next_trading_day()
416
- gr.Markdown(f"""
417
- ### Market Status: {market_status}
418
- Next trading day: {next_trading_day.strftime('%Y-%m-%d')}
419
- """)
420
-
421
- with gr.Tabs() as tabs:
422
- # Daily Analysis Tab
423
- with gr.TabItem("Daily Analysis"):
424
- with gr.Row():
425
- with gr.Column():
426
- daily_symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)", value="AAPL")
427
- daily_prediction_days = gr.Slider(
428
- minimum=1,
429
- maximum=365,
430
- value=30,
431
- step=1,
432
- label="Days to Predict"
433
- )
434
- daily_lookback_days = gr.Slider(
435
- minimum=1,
436
- maximum=3650,
437
- value=365,
438
- step=1,
439
- label="Historical Lookback (Days)"
440
- )
441
- daily_strategy = gr.Dropdown(
442
- choices=["chronos", "technical"],
443
- label="Prediction Strategy",
444
- value="chronos"
445
- )
446
- daily_predict_btn = gr.Button("Analyze Stock")
447
-
448
- with gr.Column():
449
- daily_plot = gr.Plot(label="Analysis and Prediction")
450
-
451
- with gr.Row():
452
- with gr.Column():
453
-
454
- gr.Markdown("### Structured Product Metrics")
455
- daily_metrics = gr.JSON(label="Product Metrics")
456
-
457
- gr.Markdown("### Risk Analysis")
458
- daily_risk_metrics = gr.JSON(label="Risk Metrics")
459
-
460
- gr.Markdown("### Sector Analysis")
461
- daily_sector_metrics = gr.JSON(label="Sector Metrics")
462
-
463
- gr.Markdown("### Trading Signals")
464
- daily_signals = gr.JSON(label="Trading Signals")
465
-
466
- # Hourly Analysis Tab
467
- with gr.TabItem("Hourly Analysis"):
468
- with gr.Row():
469
- with gr.Column():
470
- hourly_symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)", value="AAPL")
471
- hourly_prediction_days = gr.Slider(
472
- minimum=1,
473
- maximum=7, # Limited to 7 days for hourly predictions
474
- value=3,
475
- step=1,
476
- label="Days to Predict"
477
- )
478
- hourly_lookback_days = gr.Slider(
479
- minimum=1,
480
- maximum=30, # Limited to 30 days for hourly data
481
- value=14,
482
- step=1,
483
- label="Historical Lookback (Days)"
484
- )
485
- hourly_strategy = gr.Dropdown(
486
- choices=["chronos", "technical"],
487
- label="Prediction Strategy",
488
- value="chronos"
489
- )
490
- hourly_predict_btn = gr.Button("Analyze Stock")
491
- gr.Markdown("""
492
- **Note for Hourly Analysis:**
493
- - Maximum lookback period: 30 days (Yahoo Finance limit)
494
- - Maximum prediction period: 7 days
495
- - Data is only available during market hours
496
- """)
497
-
498
- with gr.Column():
499
- hourly_plot = gr.Plot(label="Analysis and Prediction")
500
- hourly_signals = gr.JSON(label="Trading Signals")
501
-
502
- with gr.Row():
503
- with gr.Column():
504
- gr.Markdown("### Structured Product Metrics")
505
- hourly_metrics = gr.JSON(label="Product Metrics")
506
-
507
- gr.Markdown("### Risk Analysis")
508
- hourly_risk_metrics = gr.JSON(label="Risk Metrics")
509
-
510
- gr.Markdown("### Sector Analysis")
511
- hourly_sector_metrics = gr.JSON(label="Sector Metrics")
512
 
513
- # 15-Minute Analysis Tab
514
- with gr.TabItem("15-Minute Analysis"):
515
- with gr.Row():
516
- with gr.Column():
517
- min15_symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)", value="AAPL")
518
- min15_prediction_days = gr.Slider(
519
- minimum=1,
520
- maximum=2, # Limited to 2 days for 15-minute predictions
521
- value=1,
522
- step=1,
523
- label="Days to Predict"
524
- )
525
- min15_lookback_days = gr.Slider(
526
- minimum=1,
527
- maximum=5, # Yahoo Finance limit for 15-minute data
528
- value=3,
529
- step=1,
530
- label="Historical Lookback (Days)"
531
- )
532
- min15_strategy = gr.Dropdown(
533
- choices=["chronos", "technical"],
534
- label="Prediction Strategy",
535
- value="chronos"
536
- )
537
- min15_predict_btn = gr.Button("Analyze Stock")
538
- gr.Markdown("""
539
- **Note for 15-Minute Analysis:**
540
- - Maximum lookback period: 5 days (Yahoo Finance limit)
541
- - Maximum prediction period: 2 days
542
- - Data is only available during market hours
543
- - Requires at least 64 data points for Chronos predictions
544
- """)
545
-
546
- with gr.Column():
547
- min15_plot = gr.Plot(label="Analysis and Prediction")
548
- min15_signals = gr.JSON(label="Trading Signals")
549
-
550
- with gr.Row():
551
- with gr.Column():
552
- gr.Markdown("### Structured Product Metrics")
553
- min15_metrics = gr.JSON(label="Product Metrics")
554
-
555
- gr.Markdown("### Risk Analysis")
556
- min15_risk_metrics = gr.JSON(label="Risk Metrics")
557
-
558
- gr.Markdown("### Sector Analysis")
559
- min15_sector_metrics = gr.JSON(label="Sector Metrics")
560
-
561
- def analyze_stock(symbol, timeframe, prediction_days, lookback_days, strategy):
562
- try:
563
- signals, fig = make_prediction(symbol, timeframe, prediction_days, strategy)
564
-
565
- # Get historical data for additional metrics
566
- df = get_historical_data(symbol, timeframe, lookback_days)
567
-
568
- # Calculate structured product metrics
569
- product_metrics = {
570
- "Market_Cap": df['Market_Cap'].iloc[-1],
571
- "Sector": df['Sector'].iloc[-1],
572
- "Industry": df['Industry'].iloc[-1],
573
- "Dividend_Yield": df['Dividend_Yield'].iloc[-1],
574
- "Avg_Daily_Volume": df['Avg_Daily_Volume'].iloc[-1],
575
- "Volume_Volatility": df['Volume_Volatility'].iloc[-1]
576
- }
577
-
578
- # Calculate risk metrics
579
- risk_metrics = {
580
- "Annualized_Volatility": df['Annualized_Vol'].iloc[-1],
581
- "Max_Drawdown": df['Max_Drawdown'].iloc[-1],
582
- "Current_Drawdown": df['Drawdown'].iloc[-1],
583
- "Sharpe_Ratio": (df['Returns'].mean() * 252) / (df['Returns'].std() * np.sqrt(252)),
584
- "Sortino_Ratio": (df['Returns'].mean() * 252) / (df['Returns'][df['Returns'] < 0].std() * np.sqrt(252))
585
- }
586
-
587
- # Calculate sector metrics
588
- sector_metrics = {
589
- "Sector": df['Sector'].iloc[-1],
590
- "Industry": df['Industry'].iloc[-1],
591
- "Market_Cap_Rank": "Large" if df['Market_Cap'].iloc[-1] > 1e10 else "Mid" if df['Market_Cap'].iloc[-1] > 1e9 else "Small",
592
- "Liquidity_Score": "High" if df['Avg_Daily_Volume'].iloc[-1] > 1e6 else "Medium" if df['Avg_Daily_Volume'].iloc[-1] > 1e5 else "Low"
593
- }
594
-
595
- return signals, fig, product_metrics, risk_metrics, sector_metrics
596
- except Exception as e:
597
- error_message = str(e)
598
- if "Market is currently closed" in error_message:
599
- error_message = f"{error_message}. Please try again during market hours or use daily timeframe."
600
- elif "Insufficient data points" in error_message:
601
- error_message = f"Not enough data available for {symbol} in {timeframe} timeframe. Please try a different timeframe or symbol."
602
- elif "no price data found" in error_message:
603
- error_message = f"No data available for {symbol} in {timeframe} timeframe. Please try a different timeframe or symbol."
604
- raise gr.Error(error_message)
605
-
606
- # Daily analysis button click
607
- def daily_analysis(s: str, pd: int, ld: int, st: str) -> Tuple[Dict, go.Figure, Dict, Dict, Dict]:
608
- """
609
- Process daily timeframe stock analysis and generate predictions.
610
-
611
- Args:
612
- s (str): Stock symbol (e.g., "AAPL", "MSFT", "GOOGL")
613
- pd (int): Number of days to predict (1-365)
614
- ld (int): Historical lookback period in days (1-3650)
615
- st (str): Prediction strategy to use ("chronos" or "technical")
616
-
617
- Returns:
618
- Tuple[Dict, go.Figure, Dict, Dict, Dict]: A tuple containing:
619
- - Trading signals dictionary
620
- - Plotly figure with price and technical analysis
621
- - Product metrics dictionary
622
- - Risk metrics dictionary
623
- - Sector metrics dictionary
624
-
625
- Example:
626
- >>> daily_analysis("AAPL", 30, 365, "chronos")
627
- ({'RSI': 'Neutral', 'MACD': 'Buy', ...}, <Figure>, {...}, {...}, {...})
628
- """
629
- return analyze_stock(s, "1d", pd, ld, st)
630
-
631
- daily_predict_btn.click(
632
- fn=daily_analysis,
633
- inputs=[daily_symbol, daily_prediction_days, daily_lookback_days, daily_strategy],
634
- outputs=[daily_signals, daily_plot, daily_metrics, daily_risk_metrics, daily_sector_metrics]
635
- )
636
-
637
- # Hourly analysis button click
638
- def hourly_analysis(s: str, pd: int, ld: int, st: str) -> Tuple[Dict, go.Figure, Dict, Dict, Dict]:
639
- """
640
- Process hourly timeframe stock analysis and generate predictions.
641
-
642
- Args:
643
- s (str): Stock symbol (e.g., "AAPL", "MSFT", "GOOGL")
644
- pd (int): Number of days to predict (1-7)
645
- ld (int): Historical lookback period in days (1-30)
646
- st (str): Prediction strategy to use ("chronos" or "technical")
647
-
648
- Returns:
649
- Tuple[Dict, go.Figure, Dict, Dict, Dict]: A tuple containing:
650
- - Trading signals dictionary
651
- - Plotly figure with price and technical analysis
652
- - Product metrics dictionary
653
- - Risk metrics dictionary
654
- - Sector metrics dictionary
655
-
656
- Example:
657
- >>> hourly_analysis("AAPL", 3, 14, "chronos")
658
- ({'RSI': 'Neutral', 'MACD': 'Buy', ...}, <Figure>, {...}, {...}, {...})
659
- """
660
- return analyze_stock(s, "1h", pd, ld, st)
661
-
662
- hourly_predict_btn.click(
663
- fn=hourly_analysis,
664
- inputs=[hourly_symbol, hourly_prediction_days, hourly_lookback_days, hourly_strategy],
665
- outputs=[hourly_signals, hourly_plot, hourly_metrics, hourly_risk_metrics, hourly_sector_metrics]
666
- )
667
-
668
- # 15-minute analysis button click
669
- def min15_analysis(s: str, pd: int, ld: int, st: str) -> Tuple[Dict, go.Figure, Dict, Dict, Dict]:
670
- """
671
- Process 15-minute timeframe stock analysis and generate predictions.
672
-
673
- Args:
674
- s (str): Stock symbol (e.g., "AAPL", "MSFT", "GOOGL")
675
- pd (int): Number of days to predict (1-2)
676
- ld (int): Historical lookback period in days (1-5)
677
- st (str): Prediction strategy to use ("chronos" or "technical")
678
-
679
- Returns:
680
- Tuple[Dict, go.Figure, Dict, Dict, Dict]: A tuple containing:
681
- - Trading signals dictionary
682
- - Plotly figure with price and technical analysis
683
- - Product metrics dictionary
684
- - Risk metrics dictionary
685
- - Sector metrics dictionary
686
-
687
- Example:
688
- >>> min15_analysis("AAPL", 1, 3, "chronos")
689
- ({'RSI': 'Neutral', 'MACD': 'Buy', ...}, <Figure>, {...}, {...}, {...})
690
- """
691
- return analyze_stock(s, "15m", pd, ld, st)
692
-
693
- min15_predict_btn.click(
694
- fn=min15_analysis,
695
- inputs=[min15_symbol, min15_prediction_days, min15_lookback_days, min15_strategy],
696
- outputs=[min15_signals, min15_plot, min15_metrics, min15_risk_metrics, min15_sector_metrics]
697
- )
698
 
699
  return demo
700
 
701
  if __name__ == "__main__":
702
  demo = create_interface()
703
- demo.launch(share=True, ssr_mode=False, mcp_server=True)
 
21
  scaler.fit_transform([[-1, 1]])
22
 
23
  def clear_gpu_memory():
 
24
  if torch.cuda.is_available():
25
  torch.cuda.empty_cache()
26
  gc.collect()
27
 
28
  @spaces.GPU
29
  def load_pipeline():
 
30
  global pipeline
31
+ if pipeline is None:
32
+ clear_gpu_memory()
33
+ pipeline = ChronosPipeline.from_pretrained(
34
+ "amazon/chronos-t5-large",
35
+ device_map="auto",
36
+ torch_dtype=torch.float16,
37
+ low_cpu_mem_usage=True
38
+ )
39
+ pipeline.model = pipeline.model.eval()
40
+ return pipeline
 
 
 
 
41
 
42
  def is_market_open() -> bool:
 
43
  now = datetime.now()
44
+ if now.weekday() >= 5:
 
45
  return False
 
 
46
  et_time = now.astimezone(pytz.timezone('US/Eastern'))
47
  market_open = et_time.replace(hour=9, minute=30, second=0, microsecond=0)
48
  market_close = et_time.replace(hour=16, minute=0, second=0, microsecond=0)
 
49
  return market_open <= et_time <= market_close
50
 
51
  def get_next_trading_day() -> datetime:
52
+ next_day = datetime.now() + timedelta(days=1)
53
+ while next_day.weekday() >= 5:
 
 
 
 
54
  next_day += timedelta(days=1)
 
55
  return next_day
56
 
57
+ # [All historical data, technical indicators, and prediction functions unchanged...]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ affiliate_links = """
60
+ ### Automate Your Trades with Top Bots
61
+ [💹 Pionex](https://www.pionex.com/?affiliate_id=YOUR_ID)
62
+ [🤖 Cornix](https://cornix.io/?ref=YOUR_ID)
63
+ [📈 Cryptohopper](https://www.cryptohopper.com/signup?ref=YOUR_ID)
64
+ [📊 3Commas](https://3commas.io/?r=YOUR_ID)
65
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  def create_interface():
68
+ with gr.Blocks(title="Structured Product Analysis & Crypto Predictions") as demo:
69
+ gr.Markdown("# Structured Product Analysis & Crypto Predictions")
70
+ gr.Markdown("Analyze stocks for structured products and cryptocurrencies with predictions.")
 
71
 
72
+ # Affiliate links section
73
+ gr.Markdown(affiliate_links)
74
+
75
  market_status = "Market is currently closed" if not is_market_open() else "Market is currently open"
76
  next_trading_day = get_next_trading_day()
77
+ gr.Markdown(f"### Market Status: {market_status} | Next trading day: {next_trading_day.strftime('%Y-%m-%d')}")
78
+
79
+ # [All Tabs and analysis sections unchanged: Daily, Hourly, 15-minute...]
80
+
81
+ # Add simple crypto prediction tab
82
+ with gr.TabItem("Crypto Predictions"):
83
+ with gr.Row():
84
+ with gr.Column():
85
+ crypto_symbol = gr.Textbox(label="Crypto Symbol (e.g., BTC, ETH)")
86
+ crypto_days = gr.Slider(7, 365, value=30, step=1, label="Prediction Horizon (days)")
87
+ crypto_predict_btn = gr.Button("Analyze Crypto")
88
+ with gr.Column():
89
+ crypto_table = gr.Dataframe(headers=["Close","SMA20","SMA50","Signal"], datatype=["number","number","number","str"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ def predict_crypto(symbol, days):
92
+ df = yf.download(symbol + "-USD", period="1y", interval="1d")
93
+ df['SMA20'] = df['Close'].rolling(20).mean()
94
+ df['SMA50'] = df['Close'].rolling(50).mean()
95
+ df['Signal'] = np.where(df['SMA20'] > df['SMA50'], "Buy", "Sell")
96
+ return df.tail(days)[['Close','SMA20','SMA50','Signal']]
97
+
98
+ crypto_predict_btn.click(fn=predict_crypto, inputs=[crypto_symbol, crypto_days], outputs=crypto_table)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
  return demo
101
 
102
  if __name__ == "__main__":
103
  demo = create_interface()
104
+ demo.launch(share=True, ssr_mode=False, mcp_server=True)