Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -32,6 +32,86 @@ def get_current_time_in_timezone(timezone: str) -> str:
|
|
32 |
return f"The current local time in {timezone} is: {local_time}"
|
33 |
except Exception as e:
|
34 |
return f"Error fetching time for timezone '{timezone}': {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
|
37 |
final_answer = FinalAnswerTool()
|
|
|
32 |
return f"The current local time in {timezone} is: {local_time}"
|
33 |
except Exception as e:
|
34 |
return f"Error fetching time for timezone '{timezone}': {str(e)}"
|
35 |
+
@tool
|
36 |
+
def analyze_stock(ticker: str) -> dict: # type: ignore[type-arg]
|
37 |
+
"""
|
38 |
+
A tool that analyze stock data.
|
39 |
+
Args:
|
40 |
+
ticker: A string representing ticker
|
41 |
+
"""
|
42 |
+
import os
|
43 |
+
from datetime import datetime, timedelta
|
44 |
+
|
45 |
+
import matplotlib.pyplot as plt
|
46 |
+
import numpy as np
|
47 |
+
import pandas as pd
|
48 |
+
import yfinance as yf
|
49 |
+
from pytz import timezone # type: ignore
|
50 |
+
|
51 |
+
stock = yf.Ticker(ticker)
|
52 |
+
|
53 |
+
# Get historical data (1 year of data to ensure we have enough for 200-day MA)
|
54 |
+
end_date = datetime.now(timezone("UTC"))
|
55 |
+
start_date = end_date - timedelta(days=365)
|
56 |
+
hist = stock.history(start=start_date, end=end_date)
|
57 |
+
|
58 |
+
# Ensure we have data
|
59 |
+
if hist.empty:
|
60 |
+
return {"error": "No historical data available for the specified ticker."}
|
61 |
+
|
62 |
+
# Compute basic statistics and additional metrics
|
63 |
+
current_price = stock.info.get("currentPrice", hist["Close"].iloc[-1])
|
64 |
+
year_high = stock.info.get("fiftyTwoWeekHigh", hist["High"].max())
|
65 |
+
year_low = stock.info.get("fiftyTwoWeekLow", hist["Low"].min())
|
66 |
+
|
67 |
+
# Calculate 50-day and 200-day moving averages
|
68 |
+
ma_50 = hist["Close"].rolling(window=50).mean().iloc[-1]
|
69 |
+
ma_200 = hist["Close"].rolling(window=200).mean().iloc[-1]
|
70 |
+
|
71 |
+
# Calculate YTD price change and percent change
|
72 |
+
ytd_start = datetime(end_date.year, 1, 1, tzinfo=timezone("UTC"))
|
73 |
+
ytd_data = hist.loc[ytd_start:] # type: ignore[misc]
|
74 |
+
if not ytd_data.empty:
|
75 |
+
price_change = ytd_data["Close"].iloc[-1] - ytd_data["Close"].iloc[0]
|
76 |
+
percent_change = (price_change / ytd_data["Close"].iloc[0]) * 100
|
77 |
+
else:
|
78 |
+
price_change = percent_change = np.nan
|
79 |
+
|
80 |
+
# Determine trend
|
81 |
+
if pd.notna(ma_50) and pd.notna(ma_200):
|
82 |
+
if ma_50 > ma_200:
|
83 |
+
trend = "Upward"
|
84 |
+
elif ma_50 < ma_200:
|
85 |
+
trend = "Downward"
|
86 |
+
else:
|
87 |
+
trend = "Neutral"
|
88 |
+
else:
|
89 |
+
trend = "Insufficient data for trend analysis"
|
90 |
+
|
91 |
+
# Calculate volatility (standard deviation of daily returns)
|
92 |
+
daily_returns = hist["Close"].pct_change().dropna()
|
93 |
+
volatility = daily_returns.std() * np.sqrt(252) # Annualized volatility
|
94 |
+
|
95 |
+
# Create result dictionary
|
96 |
+
result = {
|
97 |
+
"ticker": ticker,
|
98 |
+
"current_price": current_price,
|
99 |
+
"52_week_high": year_high,
|
100 |
+
"52_week_low": year_low,
|
101 |
+
"50_day_ma": ma_50,
|
102 |
+
"200_day_ma": ma_200,
|
103 |
+
"ytd_price_change": price_change,
|
104 |
+
"ytd_percent_change": percent_change,
|
105 |
+
"trend": trend,
|
106 |
+
"volatility": volatility,
|
107 |
+
}
|
108 |
+
|
109 |
+
# Convert numpy types to Python native types for better JSON serialization
|
110 |
+
for key, value in result.items():
|
111 |
+
if isinstance(value, np.generic):
|
112 |
+
result[key] = value.item()
|
113 |
+
|
114 |
+
return result
|
115 |
|
116 |
|
117 |
final_answer = FinalAnswerTool()
|