Spaces:
Running
Running
Commit
·
0255349
1
Parent(s):
76e906f
o2
Browse files
app.py
CHANGED
@@ -95,6 +95,12 @@ def get_stock_prices(ticker: str, period: str = "3mo") -> Union[Dict, str]:
|
|
95 |
"""Fetches historical stock price data and technical indicators for a given ticker."""
|
96 |
try:
|
97 |
start, end = period_to_start_end(period)
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
data = yf.download(
|
99 |
ticker,
|
100 |
start=start,
|
@@ -102,6 +108,14 @@ def get_stock_prices(ticker: str, period: str = "3mo") -> Union[Dict, str]:
|
|
102 |
interval='1d'
|
103 |
)
|
104 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
if data.empty:
|
106 |
return {"error": f"No stock data found for {ticker}"}
|
107 |
|
@@ -122,24 +136,24 @@ def get_stock_prices(ticker: str, period: str = "3mo") -> Union[Dict, str]:
|
|
122 |
# RSI
|
123 |
rsi_series = RSIIndicator(df['Close'], window=14).rsi().iloc[-n:]
|
124 |
indicators["RSI"] = {
|
125 |
-
str(date.date()):
|
126 |
}
|
127 |
|
128 |
# Stochastic
|
129 |
sto_series = StochasticOscillator(df['High'], df['Low'], df['Close'], window=14).stoch().iloc[-n:]
|
130 |
indicators["Stochastic_Oscillator"] = {
|
131 |
-
str(date.date()):
|
132 |
}
|
133 |
|
134 |
# MACD
|
135 |
macd = MACD(df['Close'])
|
136 |
macd_series = macd.macd().iloc[-n:]
|
137 |
indicators["MACD"] = {
|
138 |
-
str(date.date()):
|
139 |
}
|
140 |
macd_signal_series = macd.macd_signal().iloc[-n:]
|
141 |
indicators["MACD_Signal"] = {
|
142 |
-
str(date.date()):
|
143 |
}
|
144 |
|
145 |
# VWAP
|
@@ -150,7 +164,7 @@ def get_stock_prices(ticker: str, period: str = "3mo") -> Union[Dict, str]:
|
|
150 |
volume=df['Volume']
|
151 |
).iloc[-n:]
|
152 |
indicators["vwap"] = {
|
153 |
-
str(date.date()):
|
154 |
}
|
155 |
|
156 |
return {
|
@@ -158,14 +172,18 @@ def get_stock_prices(ticker: str, period: str = "3mo") -> Union[Dict, str]:
|
|
158 |
"indicators": indicators
|
159 |
}
|
160 |
except Exception as e:
|
|
|
161 |
return f"Error fetching price data: {str(e)}"
|
162 |
|
163 |
def get_financial_news(ticker: str) -> Union[Dict, str]:
|
164 |
"""Fetches the latest financial news related to a given ticker."""
|
165 |
try:
|
|
|
166 |
stock = yf.Ticker(ticker)
|
167 |
news = stock.news # 從 Yahoo Finance 獲取新聞
|
|
|
168 |
if not news:
|
|
|
169 |
return {"news": "No recent news found."}
|
170 |
|
171 |
# 只取最新5則新聞
|
@@ -177,15 +195,22 @@ def get_financial_news(ticker: str) -> Union[Dict, str]:
|
|
177 |
"link": item.get('link'),
|
178 |
"published_date": item.get('providerPublishTime')
|
179 |
})
|
|
|
|
|
180 |
return {"news": latest_news}
|
181 |
except Exception as e:
|
|
|
182 |
return f"Error fetching news: {str(e)}"
|
183 |
|
184 |
def get_financial_metrics(ticker: str) -> Union[Dict, str]:
|
185 |
"""Fetches key financial ratios for a given ticker."""
|
186 |
try:
|
|
|
187 |
stock = yf.Ticker(ticker)
|
188 |
info = stock.info
|
|
|
|
|
|
|
189 |
return {
|
190 |
'pe_ratio': info.get('forwardPE'),
|
191 |
'price_to_book': info.get('priceToBook'),
|
@@ -193,6 +218,7 @@ def get_financial_metrics(ticker: str) -> Union[Dict, str]:
|
|
193 |
'profit_margins': info.get('profitMargins')
|
194 |
}
|
195 |
except Exception as e:
|
|
|
196 |
return f"Error fetching ratios: {str(e)}"
|
197 |
|
198 |
def analyze_stock(api_key: str, ticker: str, period: str) -> str:
|
@@ -232,10 +258,13 @@ def analyze_stock(api_key: str, ticker: str, period: str) -> str:
|
|
232 |
"""
|
233 |
|
234 |
# 呼叫 LLM 生成最終分析報告
|
|
|
235 |
response = llm.invoke(analysis_prompt)
|
|
|
236 |
return response.content
|
237 |
|
238 |
except Exception as e:
|
|
|
239 |
return f"分析過程中發生錯誤: {str(e)}\n{traceback.format_exc()}"
|
240 |
|
241 |
# --- Gradio 介面 ---
|
|
|
95 |
"""Fetches historical stock price data and technical indicators for a given ticker."""
|
96 |
try:
|
97 |
start, end = period_to_start_end(period)
|
98 |
+
|
99 |
+
# --- 除錯訊息開始 ---
|
100 |
+
print(f"[get_stock_prices] Downloading data for ticker={ticker}, period={period}")
|
101 |
+
print(f"[get_stock_prices] Start={start}, End={end}")
|
102 |
+
# --- 除錯訊息結束 ---
|
103 |
+
|
104 |
data = yf.download(
|
105 |
ticker,
|
106 |
start=start,
|
|
|
108 |
interval='1d'
|
109 |
)
|
110 |
|
111 |
+
# --- 除錯訊息:看資料長度與前幾筆 ---
|
112 |
+
print(f"[get_stock_prices] Fetched data shape={data.shape}")
|
113 |
+
if not data.empty:
|
114 |
+
print(f"[get_stock_prices] Head of data:\n{data.head()}")
|
115 |
+
else:
|
116 |
+
print("[get_stock_prices] No data returned from yfinance.")
|
117 |
+
# ---
|
118 |
+
|
119 |
if data.empty:
|
120 |
return {"error": f"No stock data found for {ticker}"}
|
121 |
|
|
|
136 |
# RSI
|
137 |
rsi_series = RSIIndicator(df['Close'], window=14).rsi().iloc[-n:]
|
138 |
indicators["RSI"] = {
|
139 |
+
str(date.date()): float(value) for date, value in rsi_series.dropna().items()
|
140 |
}
|
141 |
|
142 |
# Stochastic
|
143 |
sto_series = StochasticOscillator(df['High'], df['Low'], df['Close'], window=14).stoch().iloc[-n:]
|
144 |
indicators["Stochastic_Oscillator"] = {
|
145 |
+
str(date.date()): float(value) for date, value in sto_series.dropna().items()
|
146 |
}
|
147 |
|
148 |
# MACD
|
149 |
macd = MACD(df['Close'])
|
150 |
macd_series = macd.macd().iloc[-n:]
|
151 |
indicators["MACD"] = {
|
152 |
+
str(date.date()): float(value) for date, value in macd_series.items()
|
153 |
}
|
154 |
macd_signal_series = macd.macd_signal().iloc[-n:]
|
155 |
indicators["MACD_Signal"] = {
|
156 |
+
str(date.date()): float(value) for date, value in macd_signal_series.items()
|
157 |
}
|
158 |
|
159 |
# VWAP
|
|
|
164 |
volume=df['Volume']
|
165 |
).iloc[-n:]
|
166 |
indicators["vwap"] = {
|
167 |
+
str(date.date()): float(value) for date, value in vwap_series.items()
|
168 |
}
|
169 |
|
170 |
return {
|
|
|
172 |
"indicators": indicators
|
173 |
}
|
174 |
except Exception as e:
|
175 |
+
print(f"[get_stock_prices] Exception: {str(e)}")
|
176 |
return f"Error fetching price data: {str(e)}"
|
177 |
|
178 |
def get_financial_news(ticker: str) -> Union[Dict, str]:
|
179 |
"""Fetches the latest financial news related to a given ticker."""
|
180 |
try:
|
181 |
+
print(f"[get_financial_news] Fetching news for ticker={ticker}")
|
182 |
stock = yf.Ticker(ticker)
|
183 |
news = stock.news # 從 Yahoo Finance 獲取新聞
|
184 |
+
|
185 |
if not news:
|
186 |
+
print("[get_financial_news] No news data returned from yfinance.")
|
187 |
return {"news": "No recent news found."}
|
188 |
|
189 |
# 只取最新5則新聞
|
|
|
195 |
"link": item.get('link'),
|
196 |
"published_date": item.get('providerPublishTime')
|
197 |
})
|
198 |
+
|
199 |
+
print(f"[get_financial_news] Found {len(latest_news)} news items.")
|
200 |
return {"news": latest_news}
|
201 |
except Exception as e:
|
202 |
+
print(f"[get_financial_news] Exception: {str(e)}")
|
203 |
return f"Error fetching news: {str(e)}"
|
204 |
|
205 |
def get_financial_metrics(ticker: str) -> Union[Dict, str]:
|
206 |
"""Fetches key financial ratios for a given ticker."""
|
207 |
try:
|
208 |
+
print(f"[get_financial_metrics] Fetching financial metrics for ticker={ticker}")
|
209 |
stock = yf.Ticker(ticker)
|
210 |
info = stock.info
|
211 |
+
# --- 除錯訊息:打印完整 info 來檢查看看 ---
|
212 |
+
print(f"[get_financial_metrics] Info returned:\n{json.dumps(info, indent=2)}")
|
213 |
+
|
214 |
return {
|
215 |
'pe_ratio': info.get('forwardPE'),
|
216 |
'price_to_book': info.get('priceToBook'),
|
|
|
218 |
'profit_margins': info.get('profitMargins')
|
219 |
}
|
220 |
except Exception as e:
|
221 |
+
print(f"[get_financial_metrics] Exception: {str(e)}")
|
222 |
return f"Error fetching ratios: {str(e)}"
|
223 |
|
224 |
def analyze_stock(api_key: str, ticker: str, period: str) -> str:
|
|
|
258 |
"""
|
259 |
|
260 |
# 呼叫 LLM 生成最終分析報告
|
261 |
+
print("[analyze_stock] Sending prompt to LLM...")
|
262 |
response = llm.invoke(analysis_prompt)
|
263 |
+
|
264 |
return response.content
|
265 |
|
266 |
except Exception as e:
|
267 |
+
print(f"[analyze_stock] Exception: {str(e)}")
|
268 |
return f"分析過程中發生錯誤: {str(e)}\n{traceback.format_exc()}"
|
269 |
|
270 |
# --- Gradio 介面 ---
|